使用pyautogui完成简单的游戏功能--皇室战争降杯
背景简介
有时候我们需要进行游戏的简单完成日常任务,例如皇室战争这个手机游戏,这种卡牌游戏很吃卡牌等级,由于我是国际服新号,等级不太高,不想打到太高分数,避免碰到高等级高卡牌高强度对手,但手动降低杯数太麻烦,这里使用pyautogui完成一些基础操作:

requirements:

实际上并不需要那么多
opencv-python4.12.0.88
PyAutoGUI0.9.54
func-timeout
pyinstaller # 用来将程序打包成exe,不打包就不需要装,为了方便打包建议新建个虚拟环境!
图中看起来很多是因为装他们的时候会附带一些其他的,必装opencv,否则无法识别图像!

程序实际运行流程如下:

1.先人工手动进入mumu模拟器,进入游戏;
2.切换到点击开始主界面,此时程序开始接手,会将游戏窗口移动到最右侧(上图红框所示),并限定图像匹配搜索范围到屏幕右下角,这样可以加快速度!
3.查找对战fight.png按钮,如果是英文版的应该是start,可以自己更换截图,替换掉即可,注意两个图和exe必须在同一文件夹中。
4.会要求输入对战的次数(此时会检查是否输入的数字,输其他的会要求重输)一般同一个竞技场基本是500杯的差距,一句输赢基本在30杯左右,所以设定个15基本差不多,如果是0则为死循环一直运行(不建议设为0);
5.会要求输入拖拽卡牌的次数,进游戏一个卡牌不放等输也不是办法,有时候对面以为你是玩空城计,双方就这样耗着都不放牌白白浪费时间,会选择四个卡牌的位置,隔三秒放一次牌,会使用拖动的方式释放,好处是避免瞬间点击,瞬间的话被检测的概率很可能比较高。【会随机选择四张里面的某一张卡,释放在左右随机的一个公主塔的后方,位置都有随机性小范围浮动,避免被检测】由于纯脚本刷数据刷伤害,听说会被封号,虽然该功能把拖拽卡牌的次数设高点的确可以用来刷伤害,但危险系数太大,所以一般设为10以内的数字即可。
6.对战结束后,检查是否出现“确定”图标,用来返回游戏主界面。
7.整个程序每次做完判定后,例如检查一轮是否有 fight,confirm图标后,会休眠5秒,在点进游戏后也会休眠一下,如果检查太频繁会占用太多系统资源。【感觉这游戏现在进入和退出每一局,都要花大几秒,非常怀疑在收集数据和上传数据,所以真的要悠着点!】
注意事项
1.仅在mumu模拟器上实测完美运行,其他模拟器不敢保证,源码在下面可以手动修改;
2.国际服会检查脚本,虽然可以用来刷卡牌大师伤害,但太过了①是可能被封号,我自己降杯弄了一两个星期都没啥事,我最多一次执行十几局。②是如果拖拽数字太高,本局游戏已经结束,还在那里拖,可能造成混乱,解决办法是隔一定时间或者一定拖拽次数,检查时候有对局结束signal之类的,当然我没有做这个,刷伤害数据太危险。
3.我的分辨率为2560X1440,如果是其他分辨率,可能会找不到图像,特别是高度这块,我看到卡牌的中心位置大概在1440-180这样,如果是1080的话,应该相对少减去一些,不过懒得调了,可以自己改改!
4.程序到设定的对局数完成后,会自动关闭。
5.由于使用了图像匹配和点击,在执行操作的时候会跟人抢鼠标,所以比较适合在看视频的时候,给模拟器留出右边750宽度的空间,让程序慢慢降杯。
6.mumu模拟器实测正常玩偶尔会崩溃,跟脚本无关,该脚本无打开游戏和关闭模拟器功能。
import pyautogui as pa
import time
import random
import pygetwindow as gw
import func_timeout
# 安全模式:当鼠标移动到屏幕左上角时自动中止程序
pa.FAILSAFE = True # 默认为True,强烈建议保持启用
global_count = 0
def move_to_side():
# 打印当前所有窗口,给用户提示
window = gw.getWindowsWithTitle('安卓设备')[0]
print(f'找到了{window.title}')
window.activate()
window.resizeTo(750, pa.size().height)
window.moveTo(pa.size().width - 750, 0)
# 缩小图像匹配范围,为屏幕右侧750的下方区域
nice_region = (window.left + 10, pa.size().height/2-1 ,window.width - 20, pa.size().height/2-1)
# 浮点转整数
nice_region = (int(nice_region[0]), int(nice_region[1]), int(nice_region[2]), int(nice_region[3]))
return nice_region
@func_timeout.func_set_timeout(5)
def get_drag_num():
"""
选择拖拽几次卡牌,如果5秒内无操作,则使用默认次数8
"""
try:
drag_num = input("请输入拖拽次数,不输入则5秒后自动设为8次-->")
except func_timeout.exceptions.FunctionTimedOut as e:
drag_num = 8
return int(drag_num)
def low_trophy(in_region):
# 让用户手动输入执行次数,为0则为死循环,输入非数字则让用户再次输入
while True:
exe_num = input('请输入执行次数,为0则无限循环:')
if exe_num.isdigit() == False:
print('检查到输入的非数字,请重新输入数字')
continue
if exe_num.isdigit():
break
drag_num = get_drag_num()
exe_num = int(exe_num)
print(f'执行次数为{exe_num},拖拽次数为{drag_num}')
global global_count
while True:
if exe_num > 0:
if global_count >= exe_num:
print('程序运行结束')
raise SystemExit("终止程序")
try:
location_confirm = pa.locateOnScreen('./confirm.png',confidence=.8,limit=1,region=in_region)
if location_confirm:
confirm_center = pa.center(location_confirm)
# 左右略微移动
new_center_1 = (confirm_center.x+random.randint(-5,5),confirm_center.y+random.randint(-5,5))
pa.click(new_center_1)
print('点击确认返回主界面,等待10秒')
time.sleep(10)
except:
pass
try:
location_start = pa.locateOnScreen('./fight.png', confidence=.8, limit=1, region=in_region)
if location_start:
# print(pa.center(location))
start_center = pa.center(location_start)
# 随机左右移动
new_center_2 = (start_center.x+random.randint(-5,5),start_center.y+random.randint(-5,5))
pa.click(new_center_2)
time.sleep(10)
run_fun(drag_num)
global_count += 1
print(f"释放卡牌程序执行了{global_count}次")
time.sleep(20)
except:
# print('未找到开始游戏,休眠5秒')
time.sleep(5)
def drag_to(first_po,second_po):
pa.moveTo(first_po,duration=.5)
pa.dragTo(second_po,duration=.5,tween=pa.easeInOutQuad)
# print("完成一次卡牌释放")
def get_two_po():
"""
该模块为2560X1440分辨率下,其他分辨率可能出问题,如果点不到则大概率是高度的原因
1.找到四张卡牌对应位置的中央
2.找到公主塔后方,上述两个位置都会随机小范围浮动
"""
# 以左边第一张牌的大概中心为基准
fixed_x = pa.size().width - 750 + 230
fixed_y = pa.size().height - 180
# 四张卡牌的中心点位置
first_center = (fixed_x, fixed_y)
second_center = (fixed_x + 140, fixed_y)
third_center = (fixed_x + 280, fixed_y)
fourth_center = (fixed_x + 420, fixed_y)
# 公主塔的后方
target_position_1 = (fixed_x, fixed_y - 260)
target_position_2 = (fixed_x + 280, fixed_y - 260)
# 随机选择一张卡来释放
choice_1 = random.choice([first_center, second_center, third_center, fourth_center])
# 起始、目标位置都进行一定的浮动
choice_1 = (choice_1[0]+random.randint(-5,5),choice_1[1]+random.randint(-5,5))
choice_2 = random.choice([target_position_1,target_position_2])
choice_2 = (choice_2[0]+random.randint(-5,5),choice_2[1]+random.randint(-5,5))
return choice_1,choice_2
def click_some():
choice_1,choice_2 = get_two_po()
drag_to(choice_1,choice_2)
def run_fun(drag_num):
print('进入游戏,准备拖拽卡牌')
for i in range(drag_num):
click_some()
time.sleep(3)
if __name__ == '__main__':
low_trophy(move_to_side())
# CMD打包命令 pyinstaller -F -c low_tro.py

浙公网安备 33010602011771号