利用python编写一个pc模拟器明日方舟脚本
前言
首先,我知道通过按键精灵等插件实现类似的效果,但是我主要是无聊了想写一个。。
其次,更关键的是,该脚本除了可以自动刷图+自动嗑体力药剂以外,还能够在体力药剂用完的时候,不会碎石去恢复体力哦!(即脚本自动停止)(这是按键精灵做不到的吧,嘿嘿)
最后另外再废话两句,我写该脚本的另一个目的是想学习下python捕捉窗口,鼠标这些信息的函数,之前从来没有干过类似的事,就顺便学习下了,就算对游戏无兴趣的也可以看看
主要内容
获取模拟器窗口
from win32gui import *
titles = set()
def foo(hwnd,mouse):global titlesif IsWindow(hwnd) and IsWindowEnabled(hwnd) and IsWindowVisible(hwnd):titles.add(GetWindowText(hwnd))EnumWindows(foo, 0)
lt = [t for t in titles if t]
lt.sort()
for t in lt:if(t.find('MuMu模拟器')) >= 0: #我用的是MuMU模拟器,自己可以根据需求进行修改hwnd = win32gui.FindWindow(None, t)print(hwnd)
这个hwnd就是我们模拟器窗口的句柄啦,我们可以根据这个句柄对模拟器进行一些操作。
为了方便后面鼠标自动点击的位置的准确性,对窗口进行位置和大小的唯一性调整肯定是必要的
模拟器位置调整
def play_game():global titlesEnumWindows(foo, 0)lt = [t for t in titles if t]lt.sort()for t in lt:print(t)if(t.find('MuMu模拟器')) >= 0:hwnd = win32gui.FindWindow(None, t)print(hwnd)#重点!!!调整模拟器的位置到左上角,且宽为620,高为360#另外几个参数类别居多,我也没有一个个去研究明白,建议保持不变#这一部如果失败的话,八成是最小化了模拟器,切记一定不能最小化模拟器!!!建议把模拟器打开放在最外层(意思就是能鼠标直接点到)win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST,0,0,620, 360,win32con.SWP_SHOWWINDOW)hwnd=win32gui.FindWindow(None, t)print(hwnd)size = win32gui.GetWindowRect(hwnd)print(size)return size
下面是执行这段代码的示意图
执行前:
执行后:
可以明显的看到,模拟器的位置和大小都发生了改变哈
脚本核心逻辑
其实核心逻辑非常简单,就是不断地在几个点之间来回点就完事了。直接上代码:
import win32gui
import win32api
import win32con
import time
def game():size = play_game() #上面说到的,调整模拟器到合适的大小和位置哈topx, topy = size[0], size[1]while True:#把鼠标放在屏幕的这个位置win32api.SetCursorPos([size[0] + 550, size[1] + 300]) #叫做点1#按下左键!!!win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)#停止一秒,按太快电脑会炸的哦time.sleep(1)win32api.SetCursorPos([size[0] + 550, size[1] + 300]) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)time.sleep(1)win32api.SetCursorPos([size[0] + 495, size[1] + 260])#点2win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)time.sleep(1)win32api.SetCursorPos([size[0] + 495, size[1] + 260])win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)time.sleep(1)win32api.SetCursorPos([size[0] + 570, size[1] + 300])#点3win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)time.sleep(1)
好,细心的同学会留意到上面的这段代码看起来有些冗余。
问题1:因正常来说我们只需要持续来回的点2个点就够了,但为什么上面设计到了三个点?
答:最后结算界面,会出现掉落物品展示,而点1和点2都恰好会点到掉落物品上,如果只有这两个点来回点的话会导致卡在结算界面无法退出,所以引入了第三个点来退出结算界面。
问题2:为什么点1和点2都要点2次?
答:其实最开始这三个点都只点一次,但是因为实际中,可能会出现一个死循环(当点1+点3的次数偶数次时,会卡在吃药水的环节,所以需要将其改成奇数次。。这个感觉讲不清楚,实在是太偏业务了,自己实现的时候就会发现这个问题)。反正最后经过实践,发现按照上面的点击循环设计是一定不会在某个环节卡住的!大家可以自己尝试有没有更好的循环方式,但是建议不要改动。。
重点来了!!!
按照上面的脚本,当你的体力药剂用光的时候,他是会继续吃你的石头(手游充值得到,相当于钻石一类的)来恢复体力继续刷本!!!这显然是我们不想脚本做的事情,所以这时候就需要设计一个有点巧妙的方法来阻止这个事情发生。。
简单来说分为以下几步:
1.找到花完药水和体力,出现消耗源石来补充体力的界面,对这个界面的石头进行截图保存。
2.上面的点击循环的执行过程中,在每一次鼠标点击之前,都确认一下此时的界面是否含有源石(坐标也很关键哦)
3.如果在此时的模拟器上没找到这个石头,则继续刷图,如果有该石头,则强制退出程序。
ps:吃石头的图大概就是这个页面:
废话不多说了,进入我们的第一步,保存源石的截图
from PIL import Image, ImageGrab
save_path='E:/python_code/little tool/srk scrpit/imgs/stone_img.jpg'
'''
这里有个坑注意一下,Image函数所用的坐标,均为win32坐标的2倍。
即win32认为的点(0,0,100,100)在Image函数中为(0,0,200,200)。
其实Image才是真正以分辨率为坐标,win32的坐标等于分辨率/2!!!!
'''
ImageGrab.grab((topx + 680, topy + 250, topx + 850, topy + 400)).save(save_path)
保存的图片大概长这样:
接下来是第二步,就是每次点击行为之前,都判断一下此时在坐标(topx + 680, topy + 250, topx + 850, topy + 400)是否有这个石头,我们可以用imagehash来做一个简单的判断:
def is_using_stone(topx, topy):now_pic_path = 'E:/python_code/little tool/srk scrpit/imgs/now_img.jpg'#把该坐标当前的图当然也得先保存下来。。ImageGrab.grab((topx + 680, topy + 250, topx + 850, topy + 400)).save(now_pic_path)hash_stone = imagehash.average_hash(Image.open(save_path), hash_size=6)hash_now = imagehash.average_hash(Image.open(now_pic_path), hash_size=6)#计算源石的图片和当前位置图片的一种hash值,表示图片的相识度hash_diff = 1 - (hash_now - hash_stone) / len(hash_now.hash) ** 2print(hash_diff)#如果该值很大(>0.9),说明这两张图片很相似,返回true,否则返回false。if(hash_diff >= 0.9):return Trueelse:return False
第三部就是把这个函数(is_using_stone)和循环点击的函数合一起就完事啦
def game():size = play_game()topx, topy = size[0], size[1]while True:win32api.SetCursorPos([size[0] + 550, size[1] + 300])#嗯 真正做到每次点击行为之前都判断一下当前界面是不是使用源石的界面哦!if is_using_stone(topx, topy):breakwin32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)time.sleep(1)win32api.SetCursorPos([size[0] + 550, size[1] + 300])if is_using_stone(topx, topy):breakwin32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)time.sleep(1)win32api.SetCursorPos([size[0] + 495, size[1] + 260])if is_using_stone(topx, topy):breakwin32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)time.sleep(1)win32api.SetCursorPos([size[0] + 495, size[1] + 260])if is_using_stone(topx, topy):breakwin32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)time.sleep(1)win32api.SetCursorPos([size[0] + 570, size[1] + 300])if is_using_stone(topx, topy):breakwin32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)time.sleep(1)
完整代码
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from win32gui import *
import win32gui
import win32api
import win32con
import time
from pygame import event
import pygame
import imagehash
from PIL import Image, ImageGrabpygame.init()
titles = set()
hash_stone = imagehash.average_hash(Image.open('E:/python_code/little tool/srk scrpit/imgs/stone_img.jpg'), hash_size=6)
now_pic_path = 'E:/python_code/little tool/srk scrpit/imgs/now_img.jpg'def foo(hwnd,mouse):#去掉下面这句就所有都输出了,但是我不需要那么多if IsWindow(hwnd) and IsWindowEnabled(hwnd) and IsWindowVisible(hwnd):titles.add(GetWindowText(hwnd))
def play_game():global titlesEnumWindows(foo, 0)lt = [t for t in titles if t]lt.sort()for t in lt:print(t)if(t.find('MuMu模拟器')) >= 0:hwnd = win32gui.FindWindow(None, t)print(hwnd)win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST,0,0,620, 360,win32con.SWP_SHOWWINDOW)hwnd=win32gui.FindWindow(None, t)print(hwnd)size = win32gui.GetWindowRect(hwnd)print(size)return sizedef is_using_stone(topx, topy):ImageGrab.grab((topx + 680, topy + 250, topx + 850, topy + 400)).save(now_pic_path)hash_now = imagehash.average_hash(Image.open(now_pic_path), hash_size=6)hash_diff = 1 - (hash_now - hash_stone) / len(hash_now.hash) ** 2print(hash_diff)if(hash_diff >= 0.9):return Trueelse:return Falsedef game():size = play_game()topx, topy = size[0], size[1]while True:win32api.SetCursorPos([size[0] + 550, size[1] + 300])if is_using_stone(topx, topy):breakwin32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)time.sleep(1)win32api.SetCursorPos([size[0] + 550, size[1] + 300])if is_using_stone(topx, topy):breakwin32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)time.sleep(1)win32api.SetCursorPos([size[0] + 495, size[1] + 260])if is_using_stone(topx, topy):breakwin32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)time.sleep(1)win32api.SetCursorPos([size[0] + 495, size[1] + 260])if is_using_stone(topx, topy):breakwin32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)time.sleep(1)win32api.SetCursorPos([size[0] + 570, size[1] + 300])if is_using_stone(topx, topy):breakwin32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)time.sleep(1)
if __name__ == '__main__':game()
写在最后
本篇文章还是以记录自己学习制作脚本的过程为主吧。
所以如果真的有小伙伴有脚本需求但是又不会写代码,可以在评论去留言哦。
利用python编写一个pc模拟器明日方舟脚本相关推荐
- 利用python编写一个pc模拟器明日方舟脚本_明日方舟脚本1.0(python\adb\cv2)
一.目的 <Python从入门到实践>第14章拉拉杂杂"抄"完,急于练手,便捡起以前一直想写却没写完的"鼠标键盘模拟"程序. 二.思考 图1.0 a ...
- 利用android实现汇率计算器,利用python编写一个汇率计算器
利用python编写一个汇率计算器 发布时间:2020-11-10 15:03:44 来源:亿速云 阅读:137 作者:Leah 这篇文章运用简单易懂的例子给大家介绍利用python编写一个汇率计算器 ...
- 利用Python编写一个高斯正反算程序
一.前言 这次的高斯正反算程序是使用的Python编写的. 环境信息是:Win10.PyCharm 2021.3.1.PySide6 6.3.1.Python 3.9.9,基于QT Designer设 ...
- python数据预测_利用Python编写一个数据预测工具
利用Python编写一个数据预测工具 发布时间:2020-11-07 17:12:20 来源:亿速云 阅读:96 这篇文章运用简单易懂的例子给大家介绍利用Python编写一个数据预测工具,内容非常详细 ...
- python编写一个软件-软件代做:利用Python编写一个行业专用的小计算器
前言:本文讲述的是如何利用python编程制作一个适用于指定行业的计算器,方便计算结果,涵盖的知识点由Python编写GUI界面程序,利用爬虫采集实时的汇率数据,将Python文件打包成可以单独运行的 ...
- 小程序一:利用Python编写一个简单的图书管理系统
完成项目的流程: 想要完成某个项目基本都是按这个流程进行编写 想要实现的功能 代码的实现 class Book:def __init__(self,name,author,recommendation ...
- 利用Python编写一个AI脚本自动控制2048网页小游戏
前言 本文将使用python+selenium自动控制游戏运行.当然采用的是伪随机数进行键盘控制.只作为一个抛砖迎玉的参考,不涉及专业算法. – 一.前期准备(必须有) 1.在安装好的pyCharm中 ...
- python简单代码编写-Python | 编写一个简单的Excel处理脚本
前段时间,温老师找我说财务处的某老师平日处理大量的Excel,很多都是机械的重复劳动,不胜其烦.和我简单说了下需求,看我能不能写个程序帮一下忙. 需求简述如下: 一个多行多列的Excel文档有一列为& ...
- python自动导出数据脚本_利用python生成一个导出数据库的bat脚本文件的方法
# 环境: python3.x def getExportDbSql(db, index): # 获取导出一个数据库实例的sql语句 sql = 'mysqldump -u%s -p%s -h%s - ...
最新文章
- 解决geoserver跨域问题
- 基于Visual C++2013拆解世界五百强面试题--题18-程序结果分析2-终结篇
- CSP认证201609-2	火车购票[C++题解]:模拟、vector、排序
- 学机械可以转计算机吗,本人合工大车辆工程大一新生,但是机械类前景都不太好,我要不要转计算机,求教?...
- 分享到facebook链接原格式_神马?!你还不知道Facebook广告怎么操作?
- ionic tab显示到顶部去了
- 【POJ - 3159】Candies (差分约束,卡SPFA)
- java 替换多个字符串_Java一次(或以最有效的方式)替换字符串中的多个不同子字符串...
- python3.4和3.6的区别_详解Python3.6正式版新特性
- 【script】python 使用json模块实现字符串与字典的相互转换
- 【提醒】刷脸取件被小学生“破解”!丰巢紧急下线
- CTO 离职、研发变动,百度外卖与饿了么组织架构融合公布
- 将空闲空间合并到现有分区时出现错误: 检测到下列文件系统错误,分区容量未做调整, 无效的的文件记录
- herom2 mysql_Hero引擎 竞标员NPC
- PHP网上书店销售系统
- 电脑文件被杀毒软件误删了怎么恢复?
- 爬虫项目开发与实践,附东方财富7x24小时实时信息代码
- 天使轮、A轮、B轮、C轮、D轮融资 究竟是什么?
- 视频:中国首届微博开发者大会杨卫华演讲
- 使用fsck修复文件系统错误
热门文章
- 如何利用万用表判断芯片和PCB之间良好焊接及防护二极管作用
- Coding and Paper Letter(六十六)
- flutter 动画展开菜单_Flutter 动画详解(一)
- What to do when the Chinese Characters are messed up when extracting from zip archive?
- 计算机网络路由转发题
- 罗马时钟 基于前端CSS、JS 实现
- 31条指令单周期cpu设计(Verilog)-(九)上代码→基本模块
- 测试用例怎么写——黑盒测试
- 文件上传的20种骚方法
- 会议室大屏幕使用什么显示设备好?