python用实现FGO自动挂机战斗思路

您所在的位置:网站首页 fgo脚本使用方法 python用实现FGO自动挂机战斗思路

python用实现FGO自动挂机战斗思路

2023-12-16 02:04| 来源: 网络整理| 查看: 265

 

主要需要用到的库有:pywin32gui,PIL,cv2(opencv-python),pywin32api,pyautogui

这篇文章是用于记录我自己的思路,当初在淘宝买了fgo的挂后,也买了商家的自动刷图脚本,但奈何老是更新用不了,我就打算用python写一个简单的战斗选牌以及重复刷图的脚本。(这个脚本是基于模拟器以及能一键秒杀的情况下,挂自己上某宝搜,基本所有商家都是一个产的(指搬运汉化外国大神卖二手国内))。

实现自动挂机,需要实现两个基本功能,一是图像匹配,二是鼠标移动定位,三是自动选牌。

一,图像匹配和鼠标移动

图像匹配自然分为截图和匹配

截图那自然就是自己预先截图保证到一个文件夹中,然后调用图片(使用PIL的Image函数,opencv的我试过不知道为什么不行,懒得想了),再使用pyautogui.locateCenterOnScreen进行对屏幕的图像匹配,im2是这个攻击按钮的图片,confidence是置信度。

然后如果匹配成功,会返回x值,这个x值是图片的中心坐标。我使用win32api.SetCursorPos进行鼠标移动定位,然后再用pyautogui.click实现鼠标单击。(我也不知道为什么我当时要用两个库实现一个功能,可能是为了学习多一个库的用法吧。)

f1715f3f9831421593916459f6934f54.png

from PIL import Image import pyautogui import win32api def attack_star(): im2 = Image.open('./fgo国服截图/开始.png') x = pyautogui.locateCenterOnScreen(im2, confidence=0.9) if x: win32api.SetCursorPos(x) pyautogui.click() return x

 

二,自动选牌 

这一点是脚本的核心所在!

因为fgo的5张牌是随机生成,如果按顺序直接选前3张牌,有可能不能一波结束一个回合,而我需要写一个小算法,简单实现匹配出3张不一样的牌,用列表保存3张牌的图片,在依次用图像匹配寻找坐标位置,在用鼠标点击即可实现快速结束战斗。

1,截取窗口位置

因为我使用的是逍遥模拟器,我需要先定位模拟器窗口的坐标信息

0a1a485db96e4a7aa8f58db6e955f44c.png

0b49853f3dac4470b68b08a7c04cf25b.png 这里我用的是win32gui.FindWindow先获取窗口的权柄,然后再win32gui.GetWindowRect(handle)返回窗口的坐标信息,返回的坐标(x1,y1,x2,y2),(x1,y1)是窗口的左上角位于屏幕的坐标,而(x2,y2)是窗口右下角的坐标。

import win32gui def get_windows_info():#获取窗口信息 # wdname = u'Fate/GO - MuMu模拟器' wdname = u'逍遥模拟器' handle = win32gui.FindWindow(0, wdname) #注意大写 if handle == 0: return None else: return win32gui.GetWindowRect(handle)#窗口坐标位置

 2,截取模拟器窗口内的卡牌位置

思路是,卡牌是永远固定再模拟器窗口里面的固定位置,而我们需要的卡牌坐标自然也是相对于模拟器的坐标(即从模拟器左上角为0点开始计算卡牌坐标位置),而用鼠标选牌的时候,再加上模拟器左上角的坐标(x1,y1),就能得出绝对坐标(相对于电脑屏幕的坐标位置)。

但要注意的第一点是,模拟器的窗口是可以变大变小的,所以我们计算坐标的时候,需要用比例关系算出卡牌位于模拟器的位置。这样一来,无论窗口变化,按照对应的比例我们都能截取到卡牌的位置。

930b3e30b53f4320bf6fe6ce18983b52.png

 计算公式可能有点复杂,我们需要知道,基于逍遥模拟器,是有两个边框的(上边和右边),这两个边框的宽度是不变的,所以需要再计算比例的时候留意这个固定数值。

def abc_zh(i): # 五张攻击卡的截图位置(i=0,1,2,3,4),基于逍遥模拟器 s(1) x1, y1, x2, y2 = get_windows_info() # 得到模拟器窗口坐标 x_in = (x2 - x1 - 52) // 1600 # 游戏实际窗口的x坐标的比例系数 =(模拟器窗口的宽-模拟器右边框的宽)//某次游戏窗口的宽 y_in = (y2 - y1 - 39) // 900 # 游戏实际窗口的y坐标的比例系数 =(模拟器窗口的高-模拟器上边框的高)//某次游戏窗口的高 x_dis = 193 # 某次游戏卡牌的宽 y_dis = 123 # 某次游戏卡牌的高 '''''' xu =(64 + 320 * i) * x_in + x1 # 卡牌左上角的x绝对坐标 = (某次相对于游戏窗口的第一张卡牌左上角x坐标 + 距离第 i+1 卡牌的距离)* x比例系数 + 模拟器窗口左上角x坐标 yu =530 * y_in + y1 # 卡牌左上角的y绝对坐标 = 某次相对于游戏窗口的第一张卡牌左上角y坐标 +y比例系数 + 模拟器左上角x坐标 xd =xu + x_dis * x_in # 卡牌右下角的x绝对坐标 = 左上角坐标 + 卡牌宽度 * x比例系数 yd =yu + y_dis * y_in # 卡牌右下角的y绝对坐标 = 左上角坐标 + 卡牌高度 * y比例系数 return (xu,yu,xd,yd) # 返回卡牌坐标信息

简单解读一下代码,例如x_in的注释里的

(模拟器窗口的宽-模拟器右边框的宽)//某次游戏窗口的宽

(模拟器窗口的宽-模拟器右边框的宽)= 当前游戏窗口的宽

而里面的固定数字,都是我在某次写代码的时候,游戏窗口的长宽(游戏窗口指的是除去固定的边框后,只有游戏画面的窗口。),这些数据都是用qq截图的坐标显示记录下来的,用qq截图一个一个获取对应卡牌的相对坐标。

i值为1的时候,就是第二张牌的x相对位置坐标,因为牌与牌之间的间隔是一样的,而高度y不变,所以只需要知道第一个牌的坐标就能推导出其他卡牌位置。

对了,卡牌的截取并不是整一张牌,因为我们需要的是打出不同角色的牌,而同一个角色的牌会有三种文字,匹配的时候如果匹配整张牌,会把同一个角色的红绿蓝牌匹配为不同角色的牌,所以我们需要截取的位置是卡牌的人物头像部分即可。

5b2419525afe4606b8f9e7bac4805c3a.png

 3,给图片进行排位置

这是自动选牌的核心所在,思路是通过图片与图片匹配,得出置信度,当置信度高于一个阈值,则把这两张牌认为是同一个人。(这里用的是cv2.TM_SQDIFF_NORMED,返回的值越低反而代表图片越相似,如果需要正常的置信度值,可以找cv2.matchTemplate的用法。)

图片匹配:

import cv2 from PIL import ImageGrab import time def s(i): return time.sleep(i) def fenlei(img1,img2): # 匹配图片相似度,接近 0 为相似 result = cv2.matchTemplate(img1, img2, cv2.TM_SQDIFF_NORMED) return result # 返回一个值,范围为(0,1), 接近 0 表示相似

选牌算法:

def attack_list(l): # 用于判断5张卡牌图片的排序,返回的a表包含3张牌 # set = 0.55 set = 0.4 # 设定一个阈值 a =[] if not fenlei(l[0],l[1])


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3