用python做了一个 qq炫舞 机器人
2015-09-29 02:09
666 查看
2个晚上的时间,累计大约有6个多小时吧,用 python 实现了一个 qq炫舞 的机器人。
qq炫舞这个游戏就是很多年前比较流行的,出现 一排上下左右,在规定时间内正确输入,然后再在关键点狠拍空格键的那种游戏。
媳妇最近去了这个公司上班,工作需要,去接触了这款游戏。我也在旁边观摩了一阵,自己怎么也玩不好,然后就想到是不是可以自己动手做一个自动玩这个游戏的机器人。
主要参考了这几篇文章,
1,用Python实现QQ找茬游戏外挂工具
http://cpiz.net/blog/2012/03/a_qq_zhaocha_assistant_by_python/
2.用Python***游戏外挂
http://eyehere.net/2012/python-game-bot-autopy-1/
里面把关键技术都说的差不多了,我在这里只大概总结一下自己的心得。(时间太晚。。困死了,明天还要上班)
实现思路是
一个死循环不停在游戏中截图,
检测到该按方向键的时候, 检测所有方向键,并给游戏发送 方向键 键盘事件
检测到该按空格键的时候, 按下空格键
所有的检测都是基于 像素颜色来检测的
1. 了解到 python 有 autopy 这个库, 可以模拟一些窗口消息。
但是我在这个例子里没有用到,而是用的 win32api 这个库。
win32api 这个库,可以像 windows sdk 一样,调用 windows sdk 的函数,非常方便,也更接近 windows 底层
2. 用到了 PIL 库 , 尤其是 PIL 库 截图的部分.
3. 图像检测,是哪个方向键(上下左右?),以及是不是该按方向键,还是该按空格键,都是基于像素颜色的检验。
上面参考的文章里面,给出了 匹配相似图的算法,但是我发现在我这里 貌似不能用。
他们的做法我大概看了一下,印象是取图片 所有像素 数值的和,与 目标图片的 像素和 做比对。
但是我这里 上下左右4个按钮 ,像素和应该基本一样,所以这种方法不能用,采取了最笨拙的 ,比对关键点颜色是否为蓝色 来判定的。
4.了解了一下 python的多线程,虽然最后没有用上。但是做了一下科普.
5. windows sdk 的 keybd_event 第二个参数是 硬件扫描码。
如果传0 的话,在模拟 键盘消息时候,会出现 在游戏中模拟 无效的情况,必须用 MapVirtualKey() 填写正确的 值,
游戏才认为输入有效。
6. 大量使用了 windows 的画图工具量坐标。。
7. 本来想用 python 面向对象一下, 想封装一下。。可是太晚了,今天把功能实现了很高兴了,来不及封装。代码就先这样吧。
8. 由于本轮开始的判定,写的不那么精确,导致偶尔出现 本轮开始判定不准确,不会输入方向键的情况。但是只要多花点时间,是能够改好的。
9. 用自己的 "挂" 和其他 “选手“ pk了一把, 3个人里面我排第2。。至少证明我的挂在不做调优的情况下,是能够战胜一批对手的。。是管用的。
嗯,大概关于这个脚本就到这里吧。
奶奶最近的病吓了我好几天,好在是病情在好转,让人欣慰。
睡得这么晚,明天的跑步计划又泡汤了。
赶紧去睡觉。
最后上代码,功能实现了,但是很乱,凑合看吧,当个留念。纪念自己第一个没啥技术含量的 “外挂"
qq炫舞这个游戏就是很多年前比较流行的,出现 一排上下左右,在规定时间内正确输入,然后再在关键点狠拍空格键的那种游戏。
媳妇最近去了这个公司上班,工作需要,去接触了这款游戏。我也在旁边观摩了一阵,自己怎么也玩不好,然后就想到是不是可以自己动手做一个自动玩这个游戏的机器人。
主要参考了这几篇文章,
1,用Python实现QQ找茬游戏外挂工具
http://cpiz.net/blog/2012/03/a_qq_zhaocha_assistant_by_python/
2.用Python***游戏外挂
http://eyehere.net/2012/python-game-bot-autopy-1/
里面把关键技术都说的差不多了,我在这里只大概总结一下自己的心得。(时间太晚。。困死了,明天还要上班)
实现思路是
一个死循环不停在游戏中截图,
检测到该按方向键的时候, 检测所有方向键,并给游戏发送 方向键 键盘事件
检测到该按空格键的时候, 按下空格键
所有的检测都是基于 像素颜色来检测的
1. 了解到 python 有 autopy 这个库, 可以模拟一些窗口消息。
但是我在这个例子里没有用到,而是用的 win32api 这个库。
win32api 这个库,可以像 windows sdk 一样,调用 windows sdk 的函数,非常方便,也更接近 windows 底层
2. 用到了 PIL 库 , 尤其是 PIL 库 截图的部分.
3. 图像检测,是哪个方向键(上下左右?),以及是不是该按方向键,还是该按空格键,都是基于像素颜色的检验。
上面参考的文章里面,给出了 匹配相似图的算法,但是我发现在我这里 貌似不能用。
他们的做法我大概看了一下,印象是取图片 所有像素 数值的和,与 目标图片的 像素和 做比对。
但是我这里 上下左右4个按钮 ,像素和应该基本一样,所以这种方法不能用,采取了最笨拙的 ,比对关键点颜色是否为蓝色 来判定的。
4.了解了一下 python的多线程,虽然最后没有用上。但是做了一下科普.
5. windows sdk 的 keybd_event 第二个参数是 硬件扫描码。
如果传0 的话,在模拟 键盘消息时候,会出现 在游戏中模拟 无效的情况,必须用 MapVirtualKey() 填写正确的 值,
游戏才认为输入有效。
6. 大量使用了 windows 的画图工具量坐标。。
7. 本来想用 python 面向对象一下, 想封装一下。。可是太晚了,今天把功能实现了很高兴了,来不及封装。代码就先这样吧。
8. 由于本轮开始的判定,写的不那么精确,导致偶尔出现 本轮开始判定不准确,不会输入方向键的情况。但是只要多花点时间,是能够改好的。
9. 用自己的 "挂" 和其他 “选手“ pk了一把, 3个人里面我排第2。。至少证明我的挂在不做调优的情况下,是能够战胜一批对手的。。是管用的。
嗯,大概关于这个脚本就到这里吧。
奶奶最近的病吓了我好几天,好在是病情在好转,让人欣慰。
睡得这么晚,明天的跑步计划又泡汤了。
赶紧去睡觉。
最后上代码,功能实现了,但是很乱,凑合看吧,当个留念。纪念自己第一个没啥技术含量的 “外挂"
#!/usr/bin/python #coding=utf-8 import math import win32gui import win32con import win32api # import autopy from PIL import ImageGrab from PIL import Image import time import threading # game window handler g_game_window = None; # upper-left corner coordinate of game window g_game_window_x = None; g_game_window_y = None; g_game_rect = None; # upper-left corner coordinate of arrows box g_input_box_x = None; g_input_box_y = None; g_input_box_width = 330; g_input_box_height = 44; # const numbers k_window_name = u"QQ炫舞" k_input_offset_x = 366; k_input_offset_y = 486; k_arrow_width = 25; k_arrow_height = 25; #k_arrow_space = 9; k_arrow_space = 10; k_arrow_first_offset_x = 33; k_arrow_first_offset_y = 10; k_max_arrows_count = 8; # enum of dir k_dir_up = 0; k_dir_down = 1; k_dir_left= 2; k_dir_right = 3; k_dir_unknown = 4; # color of flag k_flag_r = 255 k_flag_g = 125 k_flag_b = 90 # flag pos start_x = 539 start_y = 464 dest_x = 652 dest_y = 464 check_offset = 100; def getGameWindow(): print 'getGameWindow'; global k_window_name wind = win32gui.FindWindow(None,k_window_name) return wind; ''' 初始化 参数值 ''' def initSettings(): global g_game_window; global g_game_window_x; global g_game_window_y; global g_input_box_x; global g_input_box_y; global k_input_offset_x; global k_input_offset_y; # get window handle g_game_window = getGameWindow(); if g_game_window == 0: print "Please launch game before run this script!" return False; print "Game window handle: " + str(g_game_window); # place window to foreground win32gui.ShowWindow(g_game_window,win32con.SW_RESTORE); win32gui.SetForegroundWindow(g_game_window); # get game window aabb box g_game_rect = win32gui.GetWindowRect(g_game_window); g_game_window_x = g_game_rect[0]; g_game_window_y = g_game_rect[1]; # input box coordinate g_input_box_x = g_game_window_x + k_input_offset_x; g_input_box_y = g_game_window_y + k_input_offset_y; print "input box coordinate: (" + str(g_input_box_x) + "," + str(g_input_box_y) + ")" return True; ''' 判断是否是箭头的颜色 ''' def isArrowColor(colorVal): if colorVal[2] >= 190 and colorVal[0] < 140: # blue 210? return True; return False; ''' 检查箭头数量是否是奇数 ''' def isArrowsNumOdd(imgInputBox): global g_input_box_x global g_input_box_y # for curCheckBoxNum in range(k_max_arrows_count): # for eachPt in range() isOdd = False; imgWidth = imgInputBox.size[0]; imgHeight = imgInputBox.size[1]; if isArrowColor(imgInputBox.getpixel((imgWidth/2,imgHeight/2))): isOdd = True; return isOdd; ''' 获取箭头坐标列表 ''' def getArrowsList(img,isOdd): imgWidth = img.size[0]; imgHeight = img.size[1]; length = 0; loopTimes = int(k_max_arrows_count / 2); if isOdd: length = 1; loopTimes = loopTimes - 1; baseCoordX = 0; baseCoordY = imgHeight / 2 - k_arrow_height / 2; if isOdd: baseCoordX = imgWidth / 2 - k_arrow_width/2 - loopTimes * (k_arrow_width + k_arrow_space); else: baseCoordX = imgWidth / 2 - k_arrow_space / 2 - (loopTimes - 1) * k_arrow_space - loopTimes * k_arrow_width; #baseCoordX = baseCoordX + g_input_box_x baseCoordX = baseCoordX + g_input_box_x + 1 # +1 fix offset baseCoordY = baseCoordY + g_input_box_y arrowsList = []; for i in range(k_max_arrows_count): curX = baseCoordX + i * (k_arrow_width + k_arrow_space); curY = baseCoordY; arrowBox = (curX,curY,curX + k_arrow_width,curY + k_arrow_height); image = ImageGrab.grab(arrowBox); #image.save("./output/" + str(i) + ".png","png"); arrowsList.append(image); return arrowsList; ''' 箭头截图 ''' def grabArrows(): print 'grabArrows'; global g_input_box_x; global g_input_box_y; global k_arrow_space; global k_arrow_width; global k_arrow_height; global k_max_arrows_count; global g_input_box_width; global g_input_box_height; inputBox = (g_input_box_x,g_input_box_y,g_input_box_x + g_input_box_width , g_input_box_y + g_input_box_height); imgInputBox = ImageGrab.grab(inputBox); #imgInputBox.save("./output/inputBox.png","png"); isOdd = isArrowsNumOdd(imgInputBox); return getArrowsList(imgInputBox,isOdd); ''' 根据图片,检测是哪个方向键 ''' def checkDir(img): ''' key points coordinate: (6,8) (18,8) (6,17) (18,17) ''' if isArrowColor(img.getpixel((6,8))) and isArrowColor(img.getpixel((18,8))): print "up" return k_dir_up; elif isArrowColor(img.getpixel((6,17))) and isArrowColor(img.getpixel((18,17))): print "down" return k_dir_down; elif isArrowColor(img.getpixel((6,8))) and isArrowColor(img.getpixel((6,17))): print "left" return k_dir_left; elif isArrowColor(img.getpixel((18,8))) and isArrowColor(img.getpixel((18,17))): print "right" return k_dir_right; print "unknown" return k_dir_unknown; ''' 根据箭头列表,确定方向键列表 ''' def getArrowsKeys(arrowsList): print "keys -------------------- " keysList = []; for i in range(len(arrowsList)): checkResult = checkDir(arrowsList[i]); if checkResult != k_dir_unknown: keysList.append(checkResult); return keysList; def pressDirKey(keyList): for i in range(len(keyList)): dir = keyList[i]; keyCode = 0; if dir == k_dir_up: keyCode = 38; elif dir == k_dir_down: keyCode = 40; elif dir == k_dir_left: keyCode = 37; elif dir == k_dir_right: keyCode = 39; hardwareScanCode = win32api.MapVirtualKey(keyCode,0) win32api.keybd_event(keyCode,hardwareScanCode,0,0); win32api.keybd_event(keyCode,hardwareScanCode,win32con.KEYEVENTF_KEYUP,0); def pressSpaceKey(): keyCode = 32; hardwareScanCode = win32api.MapVirtualKey(keyCode,0) win32api.keybd_event(keyCode,hardwareScanCode,0,0); win32api.keybd_event(keyCode,hardwareScanCode,win32con.KEYEVENTF_KEYUP,0); ''' 检测是否是 flag 节奏标 的 颜色 ''' def isFlagColor(colorVal): # for i in range(len(colorVal)): # print colorVal[i]; #if colorVal[0] == k_flag_r and colorVal[1] == k_flag_g and colorVal[2] == k_flag_b: #if colorVal[0] < 255: if colorVal[0] < 240: return False; if colorVal[1] <= 90 or colorVal[1] >= 120: return False; if colorVal[2] <= 50 or colorVal[2] >= 85: return False; return True; is_in_turn = True; def startTurn(): print "start turn"; global is_in_turn; is_in_turn = True; arrowsList = grabArrows(); keyList = getArrowsKeys(arrowsList); pressDirKey(keyList); def endTurn(): print "end turn"; global is_in_turn; is_in_turn = False; def triggerSpace(): print "trigger space" pressSpaceKey(); ''' todo 检测 什么时候 开始新一轮,什么时候 要按 space 键 # 并且按下 空格键 ''' def checkTimer(): global start_x global start_y global dest_x global dest_y global is_in_turn; start_x = start_x + g_game_window_x; start_y = start_y + g_game_window_y; dest_x = dest_x + g_game_window_x; dest_y = dest_y + g_game_window_y; # startBlockImg = ImageGrab.grab((start_x,start_y,start_x + check_offset,start_y + check_offset)); # startBlockImg.save("./output/check.png","png"); while True: # time.sleep(0.01); # print "is in turn?" + str(is_in_turn); if not is_in_turn: startBlockImg = ImageGrab.grab((start_x,start_y,start_x + check_offset,start_y + check_offset)); if isFlagColor(startBlockImg.getpixel((1,3))): startTurn(); else: destBlockImg = ImageGrab.grab((dest_x,dest_y,dest_x + check_offset,dest_y + check_offset)); if isFlagColor(destBlockImg.getpixel((1,3))): triggerSpace(); endTurn(); def mainFunc(): if not initSettings(): return; checkTimer(); # th = threading.Thread(target = checkTimer) # th.setDaemon(True); # th.start(); # dealFunc(); if __name__ == '__main__': print 'AutoDance' mainFunc(); print 'AutoDance exit!'
相关文章推荐
- enumerate sorted
- Python学习----进程和线程
- Python磁盘监控、日志分析监控脚本
- numpy教程:矩阵matrix及其运算
- Python中bisect模块用法,及实现方式
- numpy教程 - 矩阵及其运算
- python3.4 + django1.8的环境搭建
- python模拟登录网易邮箱
- Python3+Opencv3的安装
- python实现文件查找
- DDMS
- Python - 缩写(capwords) 和 创建转换表(maketrans) 详细说明
- Python进阶 - HTML获取与解析
- python中logging包的使用小结
- python 批量ping一个网段 返回结果 的程序
- python 操作json
- python模拟浏览器登录人人网,并使用代理IP和发送表单数据
- LeetCode----Kth Largest Element in an Array
- python简单图片转字符
- Python: NLTK几个入门函数