GIF大小限制没录太多,过程中加入了操作延迟*2来保障稳定
(判断速度过快会导致当前位置判断出错导致走过头,细节没有去做判断,就直接双倍延迟处理了)
1.每隔0.1-0.2秒获取一次窗口句柄截图 扫描后得到人物坐标X1,Y1及左上角开始的第一个物品的坐标X2,Y2;
优先级(钱>道具>装备)
2.判断坐标差计算出大致按键时间
1)if(两者距离像素>5) 跳转回第一步继续获取坐标
2)if(两者距离像素>5) 跳转至第三步
3.执行模拟按键X进行道具拾取,如果数据还存在,则偏移量-1或者+1重新进行2(此步骤是防止某些物品的名称过长)
P:如果是要做自动打怪的脚本的话,可以先对怪进行贴图处理,然后获取人与怪的坐标,对每个技能维护一个按键->(范围x,范围y,冷却时间)的key->map对象
判断怪在范围内就按技能打怪,没怪就执行捡道具,没道具就执行过图
emmmm,应该可以实现全自动…吧?
此处就不多做讨论了哈,这个只是一时兴起,以游戏为例实现这一类的思路。
在此声明,本博客仅作学习交流使用,不可用于任何商业途径与任何违法途径。如有侵权,请联系删除。
本博客只是从一个实现思路聊聊,而不会整体的贴代码,所以想要完整脚本的请右转,想要不劳而获的请右转,想要借此谋利的请右转,不要浪费您宝贵的时间在我无聊的博客上面。
从小到大我就很喜欢玩游戏,所以闲下来也就想能不能用编程来做一点辅助程序?于是就网上一点点摸索资料去一步步实现。
做这样一个简单的Demo脚本只是因为生起了一点点兴趣,想通过编程切切实实地做一些有帮助的东西,顺便也能增长一些技术,兴趣使人进步。
语言:Python
用到的包:PIL、Win32、WinIO
环境:WinIO只能模拟PS/2键盘,就是最早的那种圆口接口的键盘,笔记本一般是PS/2,台式外接的我看过了我自己的电脑没有PS/2的接口所以做不了。
第一层想到的要能到操作游戏的层面肯定是要模拟鼠标键盘的输入了。一开始用java调用JNA来使用一些winapi来进行模拟,在游戏外能完美实现键盘的操作,但是游戏内部通常采用了一些机制来防止这些虚拟按键的生效,于是在查阅了许多资料后找到了WinIO的方式来进行驱动级的按键模拟。
一开始用java模拟WinIO并不顺利,java在脚本以及一些底层方法的调用上总是存在问题,比如Use32获取句柄能获取到一般的窗口但是获取不到DNF的界面句柄,又比如在使用WinIO的API时键盘模拟总是会丢失或者延迟,百度查询未果,可能是缓存数据丢失或者冲突。
重复输入abcdefg结果如下
abcdefg
abcdef
abcefg
aefg
abcdefg
abcdf
abcdefg
acde
abcdeg
acdefg
弃用Java转用Python后句柄能正常获取并且键盘模拟没有出现过任何丢失情况,Python中的包为rabird.winio可查阅资料。
WinIO驱动级模拟是给驱动发送指令,主要是两个端口,
KBC_KEY_CMD=0x64命令端口
KBC_KEY_DATA=0x60数据端口
完整的按键模拟方法包引用自网络,以下为发送键盘按下的一段。
def key_down(scancode):
winio = __get_winio()
wait_for_buffer_empty();
winio.set_port_byte(KBC_KEY_CMD, 0xd2);
wait_for_buffer_empty();
winio.set_port_byte(KBC_KEY_DATA, getScanCode(scancode))
scancode为键盘扫描码。
参考自
https://blog.csdn.net/qq_37232329/article/details/79926440
当成功通过程序完成键盘模拟后我就知道我可以用编程来实现一些简单的东西了,那如果要实现它的自动化就需要获取一些数据进行分析,比如人物和怪物的坐标位置,掉落道具的坐标位置,最直观的方式当然是读取内存获取,我也没傻乎乎的去读一个游戏的内存获取修改免得封号,不如采取一些取巧的方式比如说大图找小图?
查阅了大量的资料,通过相似度等方式比较两张大小像素都不相同的图片似乎都不可取,我又想到了能不能通过文字识别的方式,把人物的贴图换成一个字,以识别字的方式来读取文字的坐标,当真正做了之后发现,雪崩般的效率加马赛克般的识别率!
于是手写了一个大图中找小图的Demo,其实就是强行比较像素点,当找到小图左上角第一个相同的像素点时进行一轮四个角的比较,再取中间N个随机点进行比较,如果匹配度有90以上则记录坐标,简单的测试了一下发现效率还可以,从屏幕快照中寻找一个小截图,成功率基本是100%并且时间也只耗费0.5秒就能记录下坐标。
关键性的问题马上就出现了,DNF的图像,只要你一动,图片肉眼看上去长的是一样的,但是!!!!他的内部像素点就出现了一些波动,比如同样是金色,但是RGB在某一个范围内都是金色…大图找小图来定位坐标的想法破灭。
于是直接就改用了大图找某一像素的方式,一张图内如果出现某一个像素就直接定位该坐标,而这个像素,可以通过补丁插件强行用画图软件点一个点上去,图像分析是可以定位出像素点的。
于是制约效率的方式马上就暴露在了屏幕快照上,如果你电脑3秒钟截图一次,那还做什么个脚本呢?正巧Python有一个window的API能在0.2秒左右完成界面的截图,而我需要的只是DNF的界面,这个时间就压缩到了0.05-0.1秒。
快速截图方式如下
def window_capture(filename):
hwnd = win32gui.FindWindow(None, "地下城与勇士")
# 根据窗口句柄获取窗口的设备上下文DC(Divice Context)
hwndDC = win32gui.GetWindowDC(hwnd)
win32gui.SetForegroundWindow(hwnd)
# 根据窗口的DC获取mfcDC
mfcDC = win32ui.CreateDCFromHandle(hwndDC)
# mfcDC创建可兼容的DC
saveDC = mfcDC.CreateCompatibleDC()
# 创建bigmap准备保存图片
saveBitMap = win32ui.CreateBitmap()
# 获取监控器信息
left, top, right, bottom = win32gui.GetWindowRect(hwnd)
width = right - left
height = bottom - top
# MoniterDev = win32api.EnumDisplayMonitors(None, None)
# w = MoniterDev[0][2][2]
# h = MoniterDev[0][2][3]
# print w,h #图片大小
# 为bitmap开辟空间
saveBitMap.CreateCompatibleBitmap(mfcDC, width, height)
# 高度saveDC,将截图保存到saveBitmap中
saveDC.SelectObject(saveBitMap)
# 截取从左上角(0,0)长宽为(w,h)的图片
saveDC.BitBlt((0, 0), (width, height), mfcDC, (0, 0), win32con.SRCCOPY)
saveBitMap.SaveBitmapFile(saveDC, filename)
return width, height
在0.05-0.1秒内获取到图片后就可以通过图片分析找到像素并定位直接返回,也不需要对整张图片的像素进行分析,于是坐标获取就是0.2秒一次
按这种获取坐标的方式效率,完全可以采取循环来一直获取坐标
根据获取到的人物位置与相对位置来进行按键模拟并执行打怪或拾取的动作,直到地图上没有怪物及道具的坐标循环结束,过多的代码我就不贴了,完结。