# 前言
似乎好久没写东西了,之前一是在公司忙起来了,还有就是感觉 Github 国内变得越来越难用,经常网都连不上的,作为托管 Git 的博客,点个提交十几次都不一定能成功,修改起来也变得实在麻烦。
最近在玩一个游戏,玩起来非常『费手』,于是后面就在找有没有减轻操作的方法,查到了 AHK,然后自己鼓捣起来了。
开始是简单地不断让它自动按键,后面看文档看到 PixelGetColor ,查了用法之后,就加上了更复杂的操作逻辑。
而在这之间,家里的显示器的杂牌 2K,公司电脑显示器是 1080P,取色函数取值出现了差异,一边能够工作一边不行。
于是找寻解决方式。
# 问题
首先,感觉 AHK 的限制其实不少,特别是针对游戏,至少在我玩的这个游戏中,问题还是一堆,例如:
- 无法后台操作,查到的 ControlSend、ControlClick 毫无作用
- 直接 Send 按键在公司电脑有效,自己家里的笔记本无效,得用
Send, {%key% down}
Sleep KeyDownTime
Send, {%key% Up}
Sleep KeyUpTime
这种代码才行
- MouseGetPos、PixelGetColor 等坐标采样函数跟屏幕的物理分辨率有关,跟界面设置的分辨率无关。
例如,一个 2K 的显示器和一个 1080P 的显示器,开启同一个游戏,游戏分辨率同样设置为 1080P,实际采样的同一个点,其坐标都不一样。 - ImageSearch 确实有用,但是只针对 2D 情况,且 2D 界面不能透明,稍微有点差异就不行了。
# 解决 PixelGetColor 对比颜色值屏幕差异问题
# 简述
这里其它问题先不论,先说说第三个问题的个人解决方式。
由于自己目前了解 AHK ,纯靠官方文档和 Bing,因此或许解决方式并非最优,不过那就待以后再说了。
首先,为何需要用到 PixelGetColor 呢?
大家都知道,游戏技能都是有 CD (冷却时间) 的,一般情况下,一个技能处『冷却中』以及『可释放』状态时,都会有不同的表现。
如此,就可以考虑采样一个正常的颜色值进行比较,如当前颜色值与正常颜色值相等,那么说明该技能已经冷却完成,可以释放了。
这种比较方式不仅用于技能,还可以用来判断当前血量比例,然后增加对应的逻辑,再考虑释放某些已经可以释放的治疗技能等。
然后如同上面说的问题一样,同一个位置在不同分辨率屏幕下会是完全不同的两个坐标,或许在 1080P 屏幕下坐标点是一个技能,但在 2K 分辨率下实际上什么都没有。
于是根据表现,猜测 MouseGetPos、PixelGetColor 与显示器的物理像素点相关,跟系统或功能逻辑上设置的分辨率并不一致。
如图所示:
# 解决
刚开始我还试图各采样一套坐标点,但是由于那会也没写工具,全靠手动对比较:具体就是打开 WindowSpy ,查看坐标,然后运行代码采样正常坐标颜色,然后再复制出来。
总之事情非常麻烦,采样一套就够呛了,于是就查不同分辨率下坐标颜色采样问题。
然而网上并没有找到什么好方法,基本上是搜索不到相关信息,看别人用于游戏的代码,都没做什么坐标处理的。
后来,偶然查到 AHK 内置提供的一个变量 A_ScreenDPI ,打印出来显示,公司的屏幕该值为 96,自己的笔记本外接显示器为 120。
于是就想到,可不可以按照一个比例将其转换一下,然后在同一的转换坐标下采样?
采样代码:
MouseGetPos, MouseRawX, MouseRawY
PixelGetColor, LastValueColor, MouseX/96*A_ScreenDPI, MouseY/96*A_ScreenDPI,
后续搜索代码:
X1:=x/96*A_ScreenDPI
Y1:=y/96*A_ScreenDPI
PixelSearch, OutputVarX, OutputVarY,X1-5,Y1-5,X1+5,Y1+5,colorValue,10,Fast
采样代码将鼠标位置转换为以 96DPI 为准的坐标进行采样,搜索代码则将以 96DPI 为准的坐标转化为当前 DPI 分辨率下的坐标点进行搜索。
由于这种转化必然存在小的误差,因此允许正负 5 个像素区域的差异,同时允许 10 个像素值的渐变。
经测试后,自己的和在公司的时候逻辑都运行良好。
(注:以上所述均为 Client 坐标系坐标)
# 代码
# 取色代码
CoordMode, Pixel|Mouse,Client
; =======用于在Clentm模式下的坐标及颜色快捷获取===============
; Control+Alt+Z 热键 开启 p键固定坐标,按下c键复制,Esc退出
; Author:cwhisme
; qq:785300468
;==========================================================
IsRun:=false
^!z:: ; Control+Alt+Z 热键.
FixedPos:=False
IsRun:=True
Loop{
if(!IsRun)
Break
; ControlSend, ,1,ahk_class iworld
if(!FixedPos)
{
MouseGetPos, MouseRawX, MouseRawY
MouseRawX:=MouseRawX+1
MouseRawY:=MouseRawY+1
}
PixelGetColor, RawValueColor, MouseRawX, MouseRawY,
MouseX:=MouseRawX/A_ScreenDPI*96
MouseY:=MouseRawY/A_ScreenDPI*96
PixelGetColor, LastValueColor, MouseX/96*A_ScreenDPI, MouseY/96*A_ScreenDPI,
ToolTip, %MouseX% %MouseY%(%MouseRawX% %MouseRawY%) %A_ScreenDPI% %A_ScreenWidth% %A_ScreenHeight% RawValueColor:%RawValueColor% LastValueColor:%LastValueColor% (p键固定坐标,按下c键复制,Esc退出[固定:%FixedPos%]),MouseX+30, MouseY-30
}
ToolTip,
Return
p::
FixedPos:=!FixedPos
Return
c::
Clipboard=%MouseX%,%MouseY%,%LastValueColor%
Return
Stop:
IsRun:=False
Return
; 停止执行
esc::IsRun:=False
Return
# 搜索代码
CheckClick(x,y,colorValue,key)
{
X1:=x/96*A_ScreenDPI
Y1:=y/96*A_ScreenDPI
PixelSearch, OutputVarX, OutputVarY,X1-5,Y1-5,X1+5,Y1+5,colorValue,10,Fast
if(!ErrorLevel)
{
if(key)
{
SendKey(key)
}
Return True
} else Return False
}
# 结语
如此记录一下,以后或许也有用到的。