/*
关于 贪吃蛇v20201219-虚荣.ahk 说明:
抽空瞎写的比较粗糙, 为了找机会测试链表结构
加上从没写过完整游戏, 还有一个最近拿python控制台输出写游戏很勤快的兄弟的刺激, 特地写了这个贪吃蛇
感谢大佬fwt(狗头同志)的斗气, 不然我该没动力完成了
狗头同志厉害不到150行完成了这样的效果, 特此记录以警示后人**装逼莫早**
顺带挑战纯中文书写代码, 发现真的不是很容易, 太长了
写得有点乱, 总算跑起来了, 有些不太好看的地方, 有思路完善不过目前没有心思优化了
希望这个ahk示例对大家有帮助
配置于 贪吃蛇.开始() 部分可以改动
虚荣
2020/12/19
*/
#SingleInstance, force
贪吃蛇程序入口:
贪吃蛇.开始()
exitapp
贪吃蛇GuiClose:
exitapp
return
贪吃蛇键回调(游戏循环, 操作朝向) {
;msgbox, % 操作朝向
游戏循环.最后操作蛇朝向 := 操作朝向
}
class 贪吃蛇
{
开始() {
;~ 地图.重建(块尺寸, 块间距, 块横数, 块纵数, 色值_背景, 色值_空地)
this.地图.重建(15, 1, 20, 20, 0xECF8CA, 0xCCE7BA)
;~ 小蛇.初始化(地图, 初始蛇长, 蛇身色, 蛇头色)
this.小蛇.初始化(this.地图, 3, 0x87CDA8, 0x80AAA8)
;~ 食物.初始化(地图, 食物色)
this.食物.初始化(this.地图, 0xD29864)
;~ 游戏循环.设定鼠标监听(贪吃蛇, 上键, 下键, 左键, 右键)
this.游戏循环.设定鼠标监听(this, "up", "down", "left", "right")
this.游戏循环.设定刷新频率(300)
this.游戏循环.启动(this, this.地图, this.小蛇, this.食物)
}
失败(errmsg) {
msgbox, % ("游戏结束, 附加信息:`n") (errmsg)
}
class 游戏循环
{
static 最后方向逻辑单元
static 刷新频率
static 最后操作蛇朝向 := ""
启动(贪吃蛇, 地图, 小蛇, 食物)
{
上一时间 := A_TickCount
loop {
If (A_TickCount - 上一时间 > this.刷新频率) {
蛇头将至坐标 := 小蛇.移动朝向(this.最后操作蛇朝向)
;msgbox, % (A_LineNumber) ":" 蛇头将至坐标.横 "-" 蛇头将至坐标.纵
蛇步入占位物 := 地图.取坐标占位物名称(蛇头将至坐标)
;~ 失败条件 ----------------------------
if (蛇步入占位物 = 地图.边界占位名) {
;print("小蛇撞墙了")
贪吃蛇.失败("小蛇撞墙了")
break
}
else if (蛇步入占位物 = 食物.占位名) {
;print("小蛇前进一格_并长大")
小蛇.前进一格_并长大(地图, 蛇头将至坐标)
;msgbox, % isobject(食物)
食物.随机生成(地图)
}
;~ 其他条件 ----------------------------
else if (蛇步入占位物 = 地图.空块占位名)
{
;print("小蛇前进一格_不长大")
小蛇.前进一格_不长大(地图, 蛇头将至坐标)
}
else if (蛇步入占位物 = 小蛇.占位名)
{
;print("小蛇撞到自己了")
贪吃蛇.失败("小蛇撞到自己了")
break
}
上一时间 := A_TickCount
}
}
return
}
设定刷新频率(刷新频率) {
this.刷新频率 := 刷新频率
}
设定鼠标监听(贪吃蛇, 上键, 下键, 左键, 右键) {
操作朝向组 := { (上键) : "上", (下键) : "下", (左键) : "左", (右键) : "右" }
;msgbox, % obj_dbg1(操作朝向组)
for 此键, 操作朝向 in 操作朝向组
{
;msgbox, % 此键 "--" 操作朝向
贪吃蛇键回调 := func("贪吃蛇键回调").bind(this, 操作朝向)
hotkey, % 此键, %贪吃蛇键回调%
}
}
}
class 地图
{
static 块 ;~
static 空块占位名 := "空块" ;~ 块_已占 := {}
static 边界占位名 := "边界"
static 画布_句柄, 画布_设备上下文
static 块尺寸, 块间距, 块横数, 块纵数
static 宽, 高
static 背景色画刷
static 空块色画刷
;-----------------------------------
重建(块尺寸, 块间距, 块横数, 块纵数, 色值_背景, 色值_空地) {
this.块 := []
this.块尺寸 := 块尺寸
this.块间距 := 块间距
this.宽 := (块尺寸 + 块间距) * 块横数 - 块间距
this.高 := (块尺寸 + 块间距) * 块纵数 - 块间距
this.块横数 := 块横数
this.块纵数 := 块纵数
this.画布_句柄 := 0x0
this.画布_设备上下文 := 0x0
this.空块色画刷 := 0x0
;--------------------------------
;~ 创建画布
Gui, 贪吃蛇:Destroy
Gui, 贪吃蛇:+hwnd画布_句柄 +toolwindow +AlwaysOnTop
Gui, 贪吃蛇:Show, % " x10 "
. "w" this.宽 . " "
. "h" this.高 . " "
this.画布_句柄 := 画布_句柄
this.画布_设备上下文:=Dllcall("GetDC"
, "UInt", this.画布_句柄
, "Uint") ;~ 获取窗口dc指针
;----------------------------
;~ 设置空画笔, 让矩形无描边
;~hPenOld:=
Dllcall("SelectObject"
, "Ptr", this.画布_设备上下文 ;, "Ptr", hdcMem
, "Ptr", DllCall("GetStockObject"
, "int", 0x8 ;~ NULL_PEN
, "uint")
, "UInt")
;----------------------------
;~ 设置背景色画刷颜色
this.背景色画刷:=DllCall("CreateSolidBrush"
, "Uint", this.翻译RGB色(色值_背景)
, "Uint")
;~ hBrushOld:=
Dllcall("SelectObject"
, "Ptr", this.画布_设备上下文 ;, "Ptr", hdcMem
, "Ptr", this.背景色画刷
, "UInt")
Dllcall("Rectangle"
, "Ptr", this.画布_设备上下文
, "Int", 1
, "Int", 1
, "Int", this.宽
, "Int", this.高
, "UInt")
;----------------------------
;~ 设置背景色画刷颜色
this.空块色画刷:=DllCall("CreateSolidBrush"
, "Uint", this.翻译RGB色(色值_空地)
, "Uint")
;~ hBrushOld:=
Dllcall("SelectObject"
, "Ptr", this.画布_设备上下文 ;, "Ptr", hdcMem
, "Ptr", this.空块色画刷
, "UInt")
;--------------------------------
;~ 创建空白地
loop, % 块横数
{
横 := A_Index
this.块[横] := []
loop, % 块纵数
{
纵 := A_Index
this.设置块颜色(画刷句柄, 横, 纵, this.空块占位名)
}
}
}
设置块颜色(画刷句柄, 横, 纵, 占位物) {
static 前一句柄 := ""
this.块[横][纵] := {"占位物": 占位物}
if not (画刷句柄 = 前一句柄)
Dllcall("SelectObject"
, "Ptr", this.画布_设备上下文 ;, "Ptr", hdcMem
, "Ptr", 画刷句柄
, "UInt")
左上横 := (横 - 1) * (this.块尺寸 + this.块间距)
左上纵 := (纵 - 1) * (this.块尺寸 + this.块间距)
右下横 := 左上横 + this.块尺寸
右下纵 := 左上纵 + this.块尺寸
Dllcall("Rectangle"
, "Ptr", this.画布_设备上下文
, "Int", 左上横
, "Int", 左上纵
, "Int", 右下横
, "Int", 右下纵
, "UInt")
}
取坐标占位物名称(蛇头将至) {
横 := 蛇头将至.横
纵 := 蛇头将至.纵
if (0)
or (横 > this.块横数)
or (纵 > this.块纵数)
or (横 < 1)
or (纵 < 1)
return this.边界占位名
else {
;msgbox, % (A_LineNumber) ":" obj_dbg1(this["块"])
return this["块"][横][纵]["占位物"]
}
}
翻译RGB色(color, retHex := true) {
return retHex ? format("0x{1:x}",((color & 0xff) << 16) + ((color >> 8 & 0xff) << 8) + (color >> 16 & 0xff)) : ((color & 0xff) << 16) + ((color >> 8 & 0xff) << 8) + (color >> 16 & 0xff)
}
}
class 小蛇
{
static 占位名 := "小蛇蛇"
static 当前方向
static 蛇头, 蛇尾
static 蛇头画刷, 蛇身画刷
static 蛇长
class 蛇段
{
前一段 := ""
后一段 := ""
__new(坐标) {
this.坐标 := 坐标
}
}
初始化(地图, 初始蛇长, 蛇身色, 蛇头色) {
this.蛇长 := (初始蛇长 < 2) ? 2 : 初始蛇长
this.蛇身画刷:=DllCall("CreateSolidBrush"
, "Uint", 地图.翻译RGB色(蛇身色)
, "Uint")
this.蛇头画刷:=DllCall("CreateSolidBrush"
, "Uint", 地图.翻译RGB色(蛇头色)
, "Uint")
random, 横, 1, % 地图.块横数
random, 纵, 1, % 地图.块纵数
this.蛇头 := new this.蛇段({"横": 横, "纵": 纵})
;MsgBox, % "造蛇" 横 "-" 纵
this.蛇头.前一段 := ""
地图.设置块颜色(this.蛇头画刷, 横, 纵, this.占位名)
当前段 := this.蛇头
loop, % 初始蛇长 - 1
{
loop {
;print("造蛇中:" A_Index)
random, 随机增值, 1, 4
增值 := [[0, -1], [0, 1], [1, 0], [-1, 0]][随机增值]
横 := 当前段.坐标.横 + 增值[1]
纵 := 当前段.坐标.纵 + 增值[2]
;msgbox, % 地图["块", 横, 纵, "占位物"]
} until ( ( 地图["块", 横, 纵, "占位物"] == 地图.空块占位名 )
and (not 横 > 地图.块横数)
and (not 横 < 1)
and (not 纵 > 地图.块纵数)
and (not 纵 < 0) )
当前段.后一段 := new this.蛇段({"横": 横, "纵": 纵})
当前段.后一段.前一段 := 当前段
当前段 := 当前段.后一段
this.蛇尾 := 当前段
地图.设置块颜色(this.蛇身画刷, 横, 纵, this.占位名)
}
;msgbox, % obj_dbg1(this.蛇尾.坐标)
}
调试蛇链表() {
输出文本 := ""
甲 := this.蛇头
loop {
if not 甲
break
输出文本 .= "节:" 甲.坐标.横 "-" 甲.坐标.纵 "`n"
甲 := 甲.后一段
}
return 输出文本
}
移动朝向(方向) { ;~ 返回下一坐标
static 朝向 := { ("上") : {"横增值": 0, "纵增值":-1}
, ("下") : {"横增值": 0, "纵增值": 1}
, ("左") : {"横增值": -1, "纵增值": 0}
, ("右") : {"横增值": 1, "纵增值": 0} }
if (方向 = "") {
增值逻辑 := this.取蛇头朝前逻辑()
蛇头将至坐标 := { "横":this.蛇头.坐标.横 + 增值逻辑["横增值"]
, "纵":this.蛇头.坐标.纵 + 增值逻辑["纵增值"]}
}
else {
增值逻辑 := 朝向[方向]
蛇头将至坐标 := { "横" : this.蛇头.坐标.横 + 增值逻辑.横增值
, "纵" : this.蛇头.坐标.纵 + 增值逻辑.纵增值 }
if ( (蛇头将至坐标.横 = this.蛇头.后一段.坐标.横)
&& (蛇头将至坐标.纵 = this.蛇头.后一段.坐标.纵) ) {
增值逻辑 := this.取蛇头朝前逻辑()
蛇头将至坐标 := { "横":this.蛇头.坐标.横 + 增值逻辑["横增值"]
, "纵":this.蛇头.坐标.纵 + 增值逻辑["纵增值"]}
}
}
;msgbox, % (A_LineNumber) ":" 蛇头将至坐标.横 "-" 蛇头将至坐标.纵
return 蛇头将至坐标
}
取蛇头朝前逻辑() {
首横 := this.蛇头.坐标.横
首纵 := this.蛇头.坐标.纵
次横 := this.蛇头.后一段.坐标.横
次纵 := this.蛇头.后一段.坐标.纵
if (首横 = 次横 && 首纵 = 次纵)
增值逻辑 := {"横增值": 1, "纵增值": 0}
else if (首横 = 次横)
增值逻辑 := {"横增值": 0, "纵增值": 首纵 - 次纵}
else if (首纵 = 次纵)
增值逻辑 := {"横增值": 首横 - 次横, "纵增值": 0}
else
增值逻辑 := {"横增值": 1, "纵增值": 0}
return 增值逻辑
}
前进一格_并长大(地图, 蛇头将至坐标) {
this.蛇长 += 1
地图.设置块颜色(this.蛇头画刷, 蛇头将至坐标.横, 蛇头将至坐标.纵, this.占位名)
地图.设置块颜色(this.蛇身画刷, this.蛇头.坐标.横, this.蛇头.坐标.纵, this.占位名)
;~ 蛇头与次段中间插入
临时段 := this.蛇头.后一段
this.蛇头.后一段 := new this.蛇段({"横": this.蛇头.坐标.横, "纵": this.蛇头.坐标.纵})
this.蛇头.坐标 := {"横": 蛇头将至坐标.横, "纵": 蛇头将至坐标.纵}
this.蛇头.后一段.前一段 := this.蛇头
this.蛇头.后一段.后一段 := 临时段
临时段.前一段 := this.蛇头.后一段
}
前进一格_不长大(地图, 蛇头将至坐标) {
地图.设置块颜色(this.蛇身画刷, this.蛇头.坐标.横, this.蛇头.坐标.纵, this.占位名)
地图.设置块颜色(this.蛇头画刷, 蛇头将至坐标.横, 蛇头将至坐标.纵, this.占位名)
地图.设置块颜色(地图.空块色画刷, this.蛇尾.坐标.横, this.蛇尾.坐标.纵, 地图.空块占位名)
;~ 原来蛇头位置用新段填充
临时段 := this.蛇头.后一段
this.蛇头.后一段 := new this.蛇段({"横": this.蛇头.坐标.横, "纵": this.蛇头.坐标.纵})
this.蛇头.坐标 := {"横": 蛇头将至坐标.横, "纵": 蛇头将至坐标.纵}
this.蛇头.后一段.前一段 := this.蛇头
this.蛇头.后一段.后一段 := 临时段
临时段.前一段 := this.蛇头.后一段
;~ 原来蛇尾位置空
this.蛇尾 := this.蛇尾.前一段
this.蛇尾.后一段 := ""
;msgbox, % "移动-不长大:`n" this.调试蛇链表() "`n" obj_dbg1(this.蛇尾.坐标)
}
}
class 食物
{
static 占位名 := "好吃的"
static 食物色画刷
static 当前坐标
初始化(地图, 食物色) {
this.食物色画刷:=DllCall("CreateSolidBrush"
, "Uint", 地图.翻译RGB色(食物色)
, "Uint")
this.随机生成(地图)
}
随机生成(地图) {
loop {
random, 横, 1, % 地图.块横数
random, 纵, 1, % 地图.块纵数
} until ( 地图["块", 横, 纵, "占位物"] = 地图.空块占位名 )
and (not 横 > 地图.块横数)
and (not 纵 > 地图.块纵数)
and (not 横 < 1)
and (not 纵 < 0)
;msgbox, % this.食物色画刷 "-" 横 "-" 纵 "-" this.占位名
地图.设置块颜色(this.食物色画刷, 横, 纵, this.占位名)
this.当前坐标 := {"横": 横, "纵": 纵}
}
}
}
print(msg) {
DBG_GUI.print(msg)
}
class DBG_GUI {
static hwnd := ""
init() {
local x, y, w := 500, h := 150
local sFont := "微软雅黑"
Gui, dbgls: Font, , % sFont
Gui, dbgls: destroy
Gui, dbgls: +AlwaysOnTop +toolwindow +hwnd@main
Gui, dbgls: Add, ListBox, w%w% h%h% hwnd@lb
x := (A_ScreenWidth - w) / 2
y := A_ScreenHeight - h - 100
gui, dbgls: Show, Hide x%x% y%y%, 列表debug
this.hwnd := @main
this.lb := @lb
this.Msgs := []
}
show() {
gui, dbgls: Show
}
hide() {
gui, dbgls: hide
}
print(msg) {
local i, v, ex
static times := 0
ex := A_DetectHiddenWindows
DetectHiddenWindows, on
;~ 不存在该窗口则重建
if not (this.hwnd && winexist("ahk_id " this.hwnd))
this.init()
;~ 未显示该窗口则显示
DetectHiddenWindows, off
if not winexist("ahk_id " this.hwnd)
this.show()
DetectHiddenWindows, % ex
times += 1
if (this.Msgs.count() > 200) {
this.Msgs.removeat(1, 50)
this.Msgs.push(msg)
GuiControl, , % this.lb, % " "
GuiControl, , % this.lb, % "|"
For i, v in this.Msgs
GuiControl, , % this.lb, % times ": " v "||"
} else {
this.Msgs.push(msg)
GuiControl, , % this.lb, % times ": " msg "||"
}
}
}
obj_dbg1(obj) {
ret := ""
if IsObject(obj) {
ret .= "{"
for key, var in obj
ret .= key . " :" . obj_dbg1(var) . ", "
if (key <> "")
ret := SubStr(ret, 1, -2)
ret .= "}"
} else {
if obj is number
ret := obj
else if (obj = "")
ret = ""
else
ret := """" obj """"
}
return ret
}
声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。

评论(0)