用Python写了个绝地求生(附源码)

一、概述

1.1 效果

总的来说,这种方式是通过图像识别来完成的,不侵入游戏,不读取内存,安全不被检测。

1.2 前置知识

  1. 游戏中有各种不同的枪械,不同的枪械后坐力不一样,射速也不同。相同的枪械,装上不同的配件后,后坐力也会发生变化。

  2. 枪械的y轴上移是固定的,x轴是随机的,因此我们程序只移动鼠标y轴。x轴游戏中手动操作。

1.3 实现原理简述

  1. 通过python中的pynput模块监听键盘鼠标。

监听鼠标左键按下,这个时候开始移动鼠标。左键抬起,终止移动。监听键盘按键,比如tab键,这时打开背包,截屏开始识别装备栏。

  1. 通过python的pyautogui模块来截屏,可以截取屏幕指定位置。

  2. 通过python的opencv模块来处理截取的图片。

  3. 通过SSIM算法来对比图片相似度,获取到装备栏的武器、配件。

  4. 通过python的pydirectinput操作鼠标移动。

二、详解

2.1 pynput监听键盘

import pynput.keyboard as keyboard  
  
# 监听键盘  
def listen_keybord():  
    listener = keyboard.Listener(on_press=onPressed, on_release=onRelease)  
    listener.start()  

pynput的监听为异步事件,但是会被阻塞,所以如果事件处理事件过长,得用异步处理。

2.2 监听事件

创建了c_equipment类来封装武器信息。重点在tab键的监听,使用异步来检测装备信息。

def onRelease(key):  
    try:  
        if '1' == key.char:  
            c_equipment.switch = 1 #主武器1  
        elif '2' == key.char:  
            c_equipment.switch = 2 #主武器2  
        elif '3' == key.char:  
            c_equipment.switch = 3 #手枪 switch=3的时候不压枪  
        elif '4' == key.char:  
            c_equipment.switch = 3 #刀具  
        elif '5' == key.char:  
            c_equipment.switch = 3 #手雷  
    except AttributeError:  
        if 'tab' == key.name:      #tab键异步操作检测  
            asyncHandle()  
        elif 'num_lock' == key.name:  #小键盘锁用来控制程序开关  
            changeOpen()  
        elif 'shift' == key.name:     
            c_contants.hold = False  

2.3 pyautogui截屏

检测装备,首先要在打开装备栏的时候,截屏。

pyautogui.screenshot(region=[x, y, w, h])

x,y分别表示坐标,w,h表示宽度和高度。截取之后,为了方便对比图片,需要将图片二值化,然后保存到本地。

完整代码如下:

import pyautogui  
  
def adaptive_binarization(img):  
    #自适应二值化  
    maxval = 255  
    blockSize = 3  
    C = 5  
    img2 = cv2.adaptiveThreshold(img, maxval, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, blockSize, C)  
    return img2  
  
# 屏幕截图  
def shotCut(x, y, w, h):  
    im = pyautogui.screenshot(region=[x, y, w, h])  
    screen = cv2.cvtColor(numpy.asarray(im), cv2.COLOR_BGR2GRAY)  
    temp = adaptive_binarization(screen)  
    return temp  
      
def saveScreen():  
    screen1 = shotCut(1780, 125, 614, 570)  
    cv2.imwrite("./resource/shotcut/screen.bmp", screen1)  

2.4 素材准备

屏幕截图处理后如上,在装备识别之前,我们需要先准备很多素材图片用来对比。比如:武器名、枪托、握把、枪口

武器名:

枪托

2.5 裁剪图片

为了方便图片对比,我们需要将截取的装备栏部分的图片裁剪成和素材一样大小的图片。

比如,我们要检测武器一的名字:

#读取之前的截屏  
screen = cv2.imread("./resource/shotcut/screen.bmp", 0)  
#裁剪出武器1名字  
screenWepon1 = screen[0:40, 45:125]  
#拿裁剪的图片和武器素材的目录作为入参,进行对比  
w1Name = compareAndGetName(screenWepon1, "./resource/guns/")  

2.6 对比图片

#对比图片获取名字  
def compareAndGetName(screenImg, dir):  
    #获取目录下所有文件  
    content = os.listdir(dir)  
    name = 'none'  
    max = 0  
    #遍历文件  
    for fileName in content:  
        #使用opencv读取文件  
        curWepone = cv2.imread(dir + fileName, 0)  
        #使用SSIM算法拿到图片相似度  
        res = calculate_ssim(numpy.asarray(screenImg), numpy.asarray(curWepone))  
        #获取相似度最大的  
        if max < res and res > 0.5:  
            max = res  
            name = str(fileName)[:-4]  
    return name  

SSIM算法:

def calculate_ssim(img1, img2):  
    if not img1.shape == img2.shape:  
        raise ValueError('Input images must have the same dimensions.')  
    if img1.ndim == 2:  
        return ssim(img1, img2)  
    elif img1.ndim == 3:  
        if img1.shape[2] == 3:  
            ssims = []  
            for i in range(3):  
                ssims.append(ssim(img1, img2))  
            return numpy.array(ssims).mean()  
        elif img1.shape[2] == 1:  
            return ssim(numpy.squeeze(img1), numpy.squeeze(img2))  
    else:  
        raise ValueError('Wrong input image dimensions.')  

到这,我们就能获取到装备栏1位置的武器名字了。

2.7 操作鼠标

知道武器名字后,同理,我们可以获取到装备的配件。然后,监听鼠标左键按下,然后开始下移鼠标。

我们以m762武器为例:

射速:86, 每一发子弹间隔86毫秒

后坐力:[42, 36, 36, 36, 42, 43, 42, 43, 54, 55, 54, 55, 54, 55, 54, 55, 62, 62, 62, 62, 62, 62, 62, 62,62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 77, 78, 77, 78]

表示每发子弹打出后,需要在y轴下移的距离,用来与后坐力对冲。

def moveMouse():   
    #从识别的数据中,再更具当前选择的武器,获取此刻的武器(比如按下1键,武器装备栏1为m762,那么此时武器就是m762)  
    curWepone = getCurrentWepone()  
    if (curWepone.name == 'none'):  
        return  
    #基础y轴补偿(没任何配件)  
    basic = curWepone.basic  
    #射速  
    speed = curWepone.speed  
    startTime = round(time.perf_counter(), 3) * 1000  
    for i in range(curWepone.maxBullets):  
        #是否可以开火,比如左键抬起,就中断。  
        if not canFire():  
            break  
        #系数,比如按住shift屏息,就需要再原来基础上乘1.33  
        holdK = 1.0  
        if c_contants.hold:  
            holdK = curWepone.hold  
        #乘以系数后实际的移动距离  
        moveSum = int(round(basic[i] * curWepone.k * holdK, 2))  
        while True:  
            if (moveSum > 10):  
                #移动鼠标  
                pydirectinput.move(xOffset=0, yOffset=10, relative=True)  
                moveSum -= 10  
            elif (moveSum > 0):  
                pydirectinput.move(xOffset=0, yOffset=moveSum, relative=True)  
                moveSum = 0  
            elapsed = (round(time.perf_counter(), 3) * 1000 - startTime)  
            if not canFire() or elapsed > (i + 1) * speed + 10:  
                break  
            time.sleep(0.01)  

代码中的while循环:

其实再第一发子弹射出后,我们只需要下移42的距离,然后计算出需要等待的时间(0.086-移动鼠标的时间),然后第二发子弹射出,以此类推。

while循环的作用是防止屏幕抖动太厉害。因为直接移动42的距离,游戏中抖的厉害,所以我们再86毫秒的间隔里分了多次来移动鼠标。

python中的sleep函数不准确,所以我们要自己来计时,防止错过每发子弹的时间间隔。不准确还有个好处,随机,正好不用自己来随机防止检测了。

三、最麻烦的部分

每个枪的后坐力都不一样,我们需要自己去游戏的训练场,一发发子弹的调试,获取准确的补偿数据。

以上就是“用Python写了个绝地求生(附源码)”的全部内容,希望对你有所帮助。

关于Python技术储备

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

在这里插入图片描述

二、Python必备开发工具

img

三、Python视频合集

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

img

四、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

img

五、Python练习题

检查学习结果。

img

六、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

img

最后祝大家天天进步!!

上面这份完整版的Python全套学习资料已经上传至CSDN官方,朋友如果需要可以直接微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】。

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值