最近有点游戏荒,不知道玩啥,于是重拾儿时的快乐,下载了植物大战僵尸!
游戏还是当年的游戏,但我已经不是当年那个我了。
我变秃了,也变强了!唉,捋着额头上稀疏的秀发,空叹年华似水流...
现在再玩这个游戏的时候,我的眼界和格局都不是当年年幼的我能够比拟的了。以前玩的时候只顾着打僵尸,而现在的我想的是,怎么收购这家游戏公司?
不好意思吹过头了!现在玩的时候,想的是怎么让游戏过程更丝滑,身为程序员,我现在可以借助一点小小的帮助。
比如在种向日葵的时候,发现种起来非常地不丝滑:

种一朵向日葵,需要把鼠标移动到卡片槽,点一下,再移回草地上,点击种植。不仅速度慢,还容易点歪。在编程的 IDE 里面用惯了快捷键的我,已经快不会用鼠标了。
那么,有没有什么选中向日葵卡片的快捷键呢?很可惜植物大战僵尸里没有提供这样的设置。
遇到困难,我们应该------知难而退!不对,是迎难而上!
既然游戏里没有提供,那我们就自己给它提供一个。于是我去 GitHub 上逛了一圈,找到了 AutoHotkey 这个好东西。
自定义选中向日葵的快捷键
AutoHotkey,直译为 "自动快捷键",顾名思义,它有两个基本功能,一是用来写自动化脚本,二就是用来自定义快捷键。
AutoHotkey Github 地址:github.com/AutoHotkey/...
首先在它的 releases 里下载最新的安装包,我下的是 AutoHotkey_2.0.19_setup.exe
安装好之后,文件夹的内容长这样:

其中,WindowSpy.ahk 是 AutoHotkey 这个软件自带的一个脚本,双击运行:

这个脚本有一个作用:查看鼠标当前所在的位置坐标。在 Mouse Position 这一栏,Screen 的值会随着鼠标的移动而变化。比如,将鼠标移动到卡片槽里的向日葵的位置,可以看到这里的坐标显示 208, 110,这个坐标我们待会自己写脚本时需要用到。
接下来我们就开始写自己的脚本,新建一个文件,名字就叫 HelloWorld.ahk,顺便提一下,.ahk 后缀是 AutoHotkey 脚本的专用后缀。在脚本中写入以下内容:
ahk
#Requires AutoHotkey v2.0+
#SingleInstance Force
1:: {
; 保存当前鼠标位置,记录为 StartX 和 StartY
MouseGetPos(&StartX, &StartY)
; 移动到目标位置并点击,最后一个参数表示移动速度,0 表示瞬间移动
MouseMove(208, 110, 0)
Click()
; 停留 100ms 确保点击被处理,尝试了下如果不停留一会,点击有时会失效
Sleep(100)
; 移动回原始位置
MouseMove(StartX, StartY, 0)
}
简单解释一下:
#Requires AutoHotkey v2.0+指定脚本需要 AutoHotkey v2.0 或更高版本才能运行,我下载的是 AutoHotkey_2.0.19,可以看出已经是 v2.0 以上了。#SingleInstance Force表示当尝试启动脚本的另一个实例时,强制关闭旧实例并启动新实例。在写脚本的过程中,我们需要频繁地修改和重新运行脚本,所以这个设置非常有用。如果不写这一行的话,运行另一个实例时会有这个弹窗提示:

1::{}表示定义快捷键为1,当点击1的时候执行{}中的内容。一些常见的键:^表示 Ctrl,+表示 Shift,!表示 Alt,#表示 Windows 键,可以自由组合,比如^+1表示Ctrl + Shift + 1。- 这个脚本的作用是,点击快捷键 1,将鼠标从当前位置快速移动到指定位置,执行一次点击,然后再移动回来。
双击这个脚本运行,看一下效果:

可以看到,只要点击键盘上的 1,就一键完成了选中向日葵并回到草坪上的操作,只需要种植就可以了。还可以轻松拓展,比如回到草坪上之后,直接再自动点击一下完成种植也是可以的。
啊,我的土豆雷居然被僵尸吃掉了!!!
自动收集阳光
长久以来,植物大战僵尸这款游戏都有一个痛点,那就是收集阳光实在是太累了。有没有什么办法自动帮忙收集阳光呢?
有的有的,兄弟们有的。
写一个这样的脚本就可以了:
ahk
#Requires AutoHotkey v2.0+
#SingleInstance Force
; 设置悬停提示文本
A_TrayMenu.Tip := "植物大战僵尸 - 阳光自动收集器"
; 配置坐标
firstCell := [500, 360] ; 第一行第一列
lastCell := [1500, 1000] ; 第六行第九列
; 生成6行9列的坐标网格
SunGrid := GenerateSunGrid(firstCell, lastCell, 6, 9)
; 热键:Q键开始收集阳光
Q:: {
CollectAllSunshine(SunGrid)
}
; 生成坐标网格的函数
GenerateSunGrid(startPos, endPos, rows, cols) {
grid := []
; 计算每个格子的步长
xStep := (endPos[1] - startPos[1]) / (cols - 1)
yStep := (endPos[2] - startPos[2]) / (rows - 1)
Loop rows {
rowIndex := A_Index
currentRow := [] ; 创建新的一行
Loop cols {
colIndex := A_Index
; 计算当前格子的坐标
x := startPos[1] + (colIndex - 1) * xStep
y := startPos[2] + (rowIndex - 1) * yStep
; 将坐标添加到当前行
currentRow.Push([Round(x), Round(y)])
}
; 将当前行添加到网格
grid.Push(currentRow)
}
return grid
}
; 收集所有阳光的函数
CollectAllSunshine(grid) {
ToolTip("开始收集阳光...", 500, 10)
rows := grid.Length
cols := grid[1].Length
; 保存原始鼠标位置
MouseGetPos(&originalX, &originalY)
; 按行遍历所有格子
Loop rows {
rowIndex := A_Index
Loop cols {
colIndex := A_Index
; 获取当前格子坐标
currentPos := grid[rowIndex][colIndex]
x := currentPos[1]
y := currentPos[2]
; 显示当前点击位置
ToolTip("点击: 行" rowIndex " 列" colIndex " (" x "," y ")", 500, 30)
; 移动到目标位置并点击
MouseMove(x, y, 0)
Click()
; 停留,确保点击生效
Sleep(1)
}
}
; 返回原始位置
MouseMove(originalX, originalY, 0)
ToolTip("阳光收集完成!", 500, 10)
SetTimer(() => ToolTip(), -2000) ; 2秒后清除提示
}
简单解释一下:
Q:: {}表示定义快捷键为Q(Quickly!),点击 Q 键开始自动收集阳光。- 自动收集的原理是把界面上每个格子都点一下。界面上一共 6 行 9 列,通过前面介绍的
WindowSpy.ahk脚本找到第一格的坐标和最后一格的坐标,然后通过步长计算出所有格子的坐标位置,记录到 grid 数组中。其中用到了 Loop 语法,表示循环语句,举个简单的例子:
ahk
; 循环 5 次
Loop 5 {
MsgBox "这是第 " A_Index " 次循环"
}
其中,A_Index 是内置变量,表示当前循环的次数(需要注意的是,这个值是从 1 开始的,有点反程序员的直觉,我猜测是为了受众更广而做的妥协。)
看一下运行效果:

非常地丝滑!而且这明显不是挂嘛,只是个小小的辅助,用来解放双手罢了。
还能做什么
AutoHotkey 这个脚本工具有很多潜力,听说被誉为 Windows 平台的自动化瑞士军刀。只要发挥想象力,在很多场景下都可以帮我们提高生产力。在不同的人手中可以发挥出不同的威力。
比如以我的格局和眼界,我给每一个卡片槽都定义了一个快捷键,1 表示第一个卡片槽,2 表示第二个卡片槽,以此类推。
再比如说,给植物浇水的时候,花洒需要用一次点一次,实在是不方便:

于是我给花洒设置了一个 W 的快捷键(Water a plant!),点一下键盘上的 W,鼠标就能自动移到花洒的位置,执行一次点击,然后再回到原位,这样浇起水来就相当丝滑了:

唉,就这点儿出息了,有种拿着瞬移的能力去送外卖的感 jio,不过无所谓,反正没什么大的追求,活着就是为了去码头整点儿薯条=,=