金铲铲S13双城之战自动拿牌助手2.0
书接上文:
金铲铲S13双城之战自动拿牌助手1.0
更新了UI界面做配置和控制;
新增异常突变参数;
打开程序有2个窗口
1个黑窗口显示日志信息
1个Coordinate App窗口用来配置和控制
点击按钮:“获取坐标” 即可开始自动拿牌
点击停止按钮可以停止拿牌
打开程序以前要先打开【雷电模拟器】
并且雷电模拟器的Title要为:雷电模拟器
比较适配1080p的显示器
雷电模拟器设置
https://help.ldmnq.com/docs/7oTh0M
雷电模拟器快捷键设置
代码在GitHub链接
import threading
import tkinter as tk
from tkinter import ttk
import pyautogui
import time
import datetime
from paddleocr import PaddleOCR
import logging
max_screen_width, max_screen_height = pyautogui.size()
welcome = f'注意:请遵守一下规则:\n您当前屏幕像素宽度:{max_screen_width} 屏幕高度:{max_screen_height}\n' \
f'因此,在填入x,y参数的时候\nx的值要在1到当前屏幕像素宽度 {max_screen_width} 之间\n' \
f'y的值要在1到屏幕高度:{max_screen_height}之间'
pyautogui.alert(welcome)
# 定义全局变量大拇指的;异常突变的
x_coords = [720, 914, 1104, 1299, 1492]
y_coord = 968
param_yctb_name = ""
# 记录打印日志时间,设置打印等待日志间隔
global_now = datetime.datetime.now()
global_init_sec = global_now.second
thumbs_x_y = (
(x_coords[0], y_coord),
(x_coords[1], y_coord),
(x_coords[2], y_coord),
(x_coords[3], y_coord),
(x_coords[4], y_coord)
)
class CoordinateApp:
def __init__(self, root):
self.root = root
self.find_Ld_module()
self.root.title("Coordinate App")
self.thread = None
# 创建全局停止事件
global stop_event
stop_event = threading.Event()
# 创建标签和输入框
print("CoordinateApp run")
self.start_bt = None
self.stop_bt = None
self.create_widgets()
# 设置窗口大小和位置 (宽x高+X偏移+Y偏移)
self.root.geometry("550x350+100+100")
# 绑定关闭事件
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
def create_widgets(self):
self.x_entries = []
self.y_entry = None
self.param_entry = None
# 只允许输入数字的验证函数
def only_numbers(char):
return char.isdigit()
validation = self.root.register(only_numbers)
for i in range(5):
# X 坐标标签和输入框
x_label = ttk.Label(self.root, text=f"X 坐标 {i + 1}:")
x_label.grid(column=0, row=i, padx=5, pady=5, sticky="W")
x_entry = ttk.Entry(self.root, validate="key", validatecommand=(validation, '%S'))
x_entry.grid(column=1, row=i, padx=5, pady=5, sticky="W")
x_entry.insert(i, x_coords[i]) # 设置默认值
self.x_entries.append(x_entry)
# Y 坐标标签和输入框
y_label = ttk.Label(self.root, text="Y 坐标:")
y_label.grid(column=0, row=5, padx=5, pady=5, sticky="W")
self.y_entry = ttk.Entry(self.root, validate="key", validatecommand=(validation, '%S'))
self.y_entry.grid(column=1, row=5, padx=5, pady=5, sticky="W")
self.y_entry.insert(0, y_coord)
# 异常突变参数标签和输入框
param_label = ttk.Label(self.root, text="异常突变:")
param_label.grid(column=0, row=6, padx=5, pady=5, sticky="W")
self.param_entry = ttk.Entry(self.root)
self.param_entry.grid(column=1, row=6, padx=5, pady=5, sticky="W")
self.param_entry = ttk.Combobox(self.root, values=["超高速", "狂战之怒", "力量训练", "防御型护盾", "即兴发挥", "双刀流", "壁垒", "终结者", "坚不可破", "荆棘满途", "恃强凌弱", "护甲山崩", "石头皮肤", "斥力发生器", "地下拳王", "魔法训练", "鹰眼", "奥术浩荡", "隐形", "友谊之力", "泰坦打击", "最后机会", "慢炖", "法师护甲", "恕瑞玛的传承", "千刀斩", "重量级打击手", "分享你的能量", "名片", "势不可挡", "真的会蟹", "史莱姆时间", "魔法专家", "翻盘故事", "防御专家", "物理专家", "冰霜触摸", "小我多多", "巨人体型", "根深蒂固", "连杀", "猎头者", "法强吸收", "攻击吸收", "火球", "贪财化身", "双狼佣兽", "剔除弱者", "深入敌阵", "迷失于未知", "龙魂", "绝不浪费", "镭射眼", "终极英雄", "震撼登场", "渴望能量", "星原之准"])
self.param_entry.grid(column=1, row=6, padx=5, pady=5, sticky="W")
self.param_entry.set('超高速') # 设置默认值
# 获取坐标按钮
get_button = ttk.Button(self.root, text="获取坐标", command=self.get_coordinates)
get_button.grid(column=0, row=7, padx=5, pady=5, sticky="W")
self.start_bt = get_button
# 显示坐标的标签
self.coord_label = ttk.Label(self.root, text="当前坐标: ")
self.coord_label.grid(column=0, row=8, columnspan=2, padx=5, pady=5)
# 创建按钮2:停止线程
stop_button = ttk.Button(self.root, text="停止", command=self.stop_thread_func)
stop_button.grid(column=1, row=7, padx=10, pady=10)
stop_button.config(state='disabled') # 初始状态为禁用
self.stop_bt = stop_button
def get_coordinates(self):
global x_coords, y_coord, param_yctb_name, thumbs_x_y
x_coords = [int(entry.get()) for entry in self.x_entries]
y_coord = int(self.y_entry.get())
param_yctb_name = self.param_entry.get()
self.coord_label.config(text=f"当前坐标: {[(x, y_coord) for x in x_coords]}, 异常突变参数: {param_yctb_name}")
thumbs_x_y = (
(x_coords[0], y_coord),
(x_coords[1], y_coord),
(x_coords[2], y_coord),
(x_coords[3], y_coord),
(x_coords[4], y_coord)
)
print(f"输入参数:{thumbs_x_y} 异常突变:{param_yctb_name}")
if self.thread is None or not self.thread.is_alive():
stop_event.clear()
self.thread = threading.Thread(target=GetCard().get_cards_and_yctb)
self.thread.start()
self.start_bt.config(state='disabled') # 禁用启动按钮
self.stop_bt.config(state='normal') # 启用停止按钮
def stop_thread_func(self):
print(f'stop_thread_func: self.thread={self.thread}')
if self.thread is not None:
stop_event.set()
self.thread.join()
self.thread = None
self.start_bt.config(state='normal') # 禁用启动按钮
self.stop_bt.config(state='disabled') # 启用停止按钮
def on_closing(self):
print('关闭窗口')
self.stop_thread_func()
self.root.destroy()
# 找到雷电模拟器
def find_Ld_module(self):
try:
# 获取雷电模拟器 将雷电模拟器窗口最大化,使窗口处于最前面
win = pyautogui.getWindowsWithTitle('雷电模拟器')
if len(win) > 0:
print('找到雷电模拟器窗口了')
win[0].maximize()
win[0].activate()
except BaseException as e:
print('没找到雷电模拟器窗口')
pyautogui.alert('没找到雷电模拟器窗口,请先打开雷电模拟器,再重新启动本程序,点击确认后程序就会关闭')
exit(0)
class GetCard:
def __init__(self):
# 控制识别组件日志频率
logging.basicConfig(level=logging.INFO)
# 假设ppocr使用的是名为'ppocr'的logger
logger_ppocr = logging.getLogger('ppocr')
logger_ppocr.setLevel(logging.INFO)
def get_cards_new(self):
global global_init_sec, thumbs_x_y
for index, thumb in enumerate(thumbs_x_y):
thumb_color = pyautogui.pixel(thumb[0], thumb[1])
# print(index, f'x={thumb[0]},y={thumb[1]}', thumb_color[0], thumb_color[1], thumb_color[2])
# RGB三色
red = 240 < thumb_color[0]
green = 240 < thumb_color[1]
blue = 200 < thumb_color[2]
# not_white_color 白色背景会影响程序判断,对白色的处理
if thumb_color[0] == 255 and thumb_color[1] == 255 and thumb_color[2] == 255:
print('当前屏幕显示背景在5个大拇指的位置有白色,请使用ALT+Tab组合键切出此窗口或关闭程序')
time.sleep(3)
continue
if thumb_color[0] == 245 and thumb_color[1] == 245 and thumb_color[2] == 245:
print('当前屏幕显示背景在5个大拇指的位置有杂色,请使用ALT+Tab组合键切出此窗口或关闭程序')
time.sleep(3)
continue
if red and green and blue:
print(index + 1, "真的有true,即将点击", thumb[0], thumb[1],datetime.datetime.now())
# pyautogui.click(thumb[0], thumb[1])
# 改为模拟键盘按钮
pyautogui.press(str(index + 1))
# 获取当前时间
now = datetime.datetime.now()
# 格式化时间为“时:分:秒”
formatted_time = now.strftime("%H:%M:%S")
if abs(now.second - global_init_sec) >= 10:
# print("当前时间(时:分:秒):", formatted_time)
print("da等待大拇指出现...", formatted_time)
global_init_sec = now.second
def get_cards_and_yctb(self):
global param_yctb_name, thumbs_x_y
print(f'get_cards_and_yctb:{thumbs_x_y},{param_yctb_name}')
# 4-6阶段有异常突变,记录4-6出现的位置
left4_6 = 686
top4_6 = 42
width4_6 = 60
height4_6 = 25
# 异常突变 名称 出现的位置 一个字 宽38
left_yctb = 574
top_yctb = 870
width_yctb = 118
height_yctb = 36
# 4-6得算作英文来识别
ocr_en = PaddleOCR(use_angle_cls=True, lang="en")
ocr = PaddleOCR(use_angle_cls=True, lang="ch")
stage_flag = False
# 记录打印日志时间,设置打印等待日志间隔
init_sec2 = datetime.datetime.now().second
yctb_stage = '4-6'
yctb_stage_recycle = '4-6'
# 和启动停止按钮线程联动
while not stop_event.is_set():
time.sleep(0.06)
screen4_6 = pyautogui.screenshot(region=(left4_6, top4_6, width4_6, height4_6))
screen4_6.save(f"stage_screenshot4_6.png")
screen4_6 = pyautogui.screenshot(region=(left_yctb, top_yctb, width_yctb, height_yctb))
screen4_6.save(f"yctb_screenshot.png")
ocr_en_result_list = ocr_en.ocr('stage_screenshot4_6.png', cls=True)
ocr_en_result = ocr_en_result_list[0]
if ocr_en_result is not None:
# 捕获到字符了
stage_num = ocr_en_result[0][1][0]
# 4-6
if yctb_stage == stage_num:
print('ocr到4-6阶段')
stage_flag = True
# 记录开始时间的时间戳
start_time = time.time()
# 判断 异常突变 名称
while stage_flag:
screen4_6 = pyautogui.screenshot(region=(left_yctb, top_yctb, width_yctb, height_yctb))
screen4_6.save(f"yctb_screenshot.png")
ocr_result_list = ocr.ocr('yctb_screenshot.png', cls=True)
ocr_result = ocr_result_list[0]
if ocr_result is not None:
# 获取当前时间的时间戳
current_time = time.time()
# 计算时间差
time_difference = current_time - start_time
# 判断时间差是否达到或超过60秒 # 退出循环
if time_difference >= 60:
print('4-6选择异常突变超时')
stage_flag = False
yctb_stage = ''
# 异常突变名6称str
print('异常突变名称:', ocr_result[0][1][0])
# 最长5个字的,最短2个字的; 2个字的会俩字(
# 先对上2个字 3个字的又2个魔法训练,魔法专家
if len(str(ocr_result[0][1][0])) == 3:
if param_yctb_name[:3] == ocr_result[0][1][0]:
print('====名称对上了,准备按钮6===')
pyautogui.press('6')
stage_flag = False
yctb_stage = ''
print('****按了6,异常突变暂时结束!****')
if len(str(ocr_result[0][1][0])) > 3:
if param_yctb_name[:2] == str(ocr_result[0][1][0])[:2]:
print('====名称对上了,准备按钮6===')
pyautogui.press('6')
stage_flag = False
yctb_stage = ''
print('****按了6,异常突变暂时结束!****')
else:
# 不是4-6,但是是2和3阶段
if stage_num is not None and str(stage_num).startswith('2-'):
print('ocr二阶段,时间:', datetime.datetime.now().strftime("%H:%M:%S"))
yctb_stage = yctb_stage_recycle
if stage_num is not None and str(stage_num).startswith('3-'):
print('ocr三阶段,时间:', datetime.datetime.now().strftime("%H:%M:%S"))
yctb_stage = yctb_stage_recycle
# 获取当前时间
now = datetime.datetime.now()
# 格式化时间为“时:分:秒”
formatted_time = now.strftime("%H:%M:%S")
if abs(now.second - init_sec2) >= 10:
print('ocr截取回合数:', stage_num, "等待匹配到正确的回合数", formatted_time)
init_sec2 = now.second
# 没有捕获4-6阶段的字符,执行拿卡操作
self.get_cards_new()
else:
self.get_cards_new()
if __name__ == "__main__":
root = tk.Tk()
app = CoordinateApp(root)
root.mainloop()
目前基本可用,但还不是很好用,欢迎沟通交流!
标签:yctb,金铲,thumb,S13,self,ocr,print,2.0,stage From: https://blog.csdn.net/weixin_40967156/article/details/144638499