机器人之用python做了一个QQ炫舞机器人,很简单没什么技术含量
小标 2018-10-11 来源 : 阅读 1357 评论 0

摘要:本文主要向大家介绍了机器人之用python做了一个QQ炫舞机器人,很简单没什么技术含量,通过具体的内容向大家展现,希望对大家学习机器人有所帮助。

本文主要向大家介绍了机器人之用python做了一个QQ炫舞机器人,很简单没什么技术含量,通过具体的内容向大家展现,希望对大家学习机器人有所帮助。


2个晚上的时间,累计大约有6个多小时吧,用 python 实现了一个 qq炫舞 的机器人。
qq炫舞这个游戏就是很多年前比较流行的,出现 一排上下左右,在规定时间内正确输入,然后再在关键点狠拍空格键的那种游戏。

里面把关键技术都说的差不多了,我在这里只大概总结一下自己的心得。

实现思路是

一个死循环不停在游戏中截图,

检测到该按方向键的时候, 检测所有方向键,并给游戏发送 方向键 键盘事件

检测到该按空格键的时候, 按下空格键

所有的检测都是基于 像素颜色来检测的

了解到 python 有 autopy 这个库, 可以模拟一些窗口消息。
但是我在这个例子里没有用到,而是用的 win32api 这个库。
win32api 这个库,可以像 windows sdk 一样,调用 windows sdk 的函数,非常方便,也更接近 windows 底层

用到了 PIL 库 , 尤其是 PIL 库 截图的部分.

图像检测,是哪个方向键(上下左右?),以及是不是该按方向键,还是该按空格键,都是基于像素颜色的检验。
参考的文章中,给出了 匹配相似图的算法,但是我发现在我这里 貌似不能用。
他们的做法我大概看了一下,印象是取图片 所有像素 数值的和,与 目标图片的 像素和 做比对。
但是我这里 上下左右4个按钮 ,像素和应该基本一样,所以这种方法不能用,采取了最笨拙的 ,比对关键点颜色是否为蓝色 来判定的。

4.了解了一下 python的多线程,虽然最后没有用上。

windows sdk 的 keybd_event 第二个参数是 硬件扫描码。
如果传0 的话,在模拟 键盘消息时候,会出现 在游戏中模拟 无效的情况,必须用 MapVirtualKey() 填写正确的 值,游戏才认为输入有效。

大量使用了 windows 的画图工具量坐标。。

本来想用 python  面向对象一下, 想封装一下。。可是太晚了,今天把功能实现了很高兴了,来不及封装。代码就先这样吧。

由于本轮开始的判定,写的不那么精确,导致偶尔出现 本轮开始判定不准确,不会输入方向键的情况。但是只要多花点时间,是能够改好的。

用自己的 "挂" 和其他 “选手“ 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!'


本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标人工智能智能机器人频道!


本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved