# 前言

似乎好久没写东西了,之前一是在公司忙起来了,还有就是感觉 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
    }

# 结语

如此记录一下,以后或许也有用到的。