吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 12570|回复: 467
上一主题 下一主题
收起左侧

[Python 原创] 金铲铲利用paddleocr+pyautogui来实现自动买牌。妈妈再也不用担心我漏牌了

    [复制链接]
跳转到指定楼层
楼主
无阻 发表于 2024-10-2 01:32 回帖奖励
本帖最后由 无阻 于 2024-10-2 11:36 编辑



国庆放假玩了一天金铲铲之战。
因为手残每次后面梭哈都手忙脚乱要么就是手速不够要么就是漏牌
搞得我追不出来想要的牌
一气之下写了个自动买牌的

但是目前只实现了识别英雄名之后自动买牌的功能
CPU优化啥的都没做
后续继续开发吧。弄个金铲铲游戏助手啥的来玩




2024.10.2  优化了截图 触发方式等功能来实现CPU优化
[Python] 纯文本查看 复制代码
# coding = utf-8
import traceback
import numpy as np
from paddleocr import PaddleOCR
from pyautogui import *
import win32gui
import win32api
import logging
import pynput, time
import keyboard
import loguru
import pathlib
import datetime
import os
from concurrent.futures import ThreadPoolExecutor, as_completed, ALL_COMPLETED, wait

# 创建日志目录
log_dir = pathlib.Path('./logs')
log_dir.mkdir(exist_ok=True)
if not os.path.exists(f"/logs/"):
    os.mkdir(f"/logs/")
current_date = datetime.datetime.now().strftime('%Y-%m-%d')
if not os.path.exists(f"/logs/{current_date}/"):
    os.mkdir(f"/logs/{current_date}/")
log_file = log_dir.joinpath(f'./logs/{current_date}/' + "log_{time: YYYY_MM_DD}.log")
log = loguru.logger

# 只允许一条线程同时识别,解决CPU占用
pool = ThreadPoolExecutor(max_workers=1)

# 关闭paddleocr的打印功能,不需要关闭的话去掉下面两行代码
logging.disable(logging.DEBUG)  # 关闭DEBUG日志的打印
logging.disable(logging.WARNING)  # 关闭WARNING日志的打印



#主要识别并且购买函数
def ocr_hero_buy(heroname, windowTitle="腾讯手游助手(64位)", isClick=True):
    time.sleep(0.25)  # 键盘或鼠标按下后0.3秒后触发
    """
    自动截图模拟器窗口并且OCR指定英雄然后点击购买
    :param heroname:英雄名称,多个请直接传入数组
    :param windowName:模拟器窗口名称
    :param isClick:识别到了是否自动点击
    :return:
    """
    if type(heroname) == str:
        # 如果传入的是单个英雄或者不为数组就转换为数组
        heroname = [heroname]

    # 获取指定窗口在屏幕的位置大小函数
    def get_window_rect(window_title):
        # 获取指定窗口标题的窗口在系统中的位置
        hwnd = win32gui.FindWindow(0, window_title)
        if hwnd:
            rect = win32gui.GetWindowRect(hwnd)
            return rect
        return None
    rect = get_window_rect(windowTitle)
    if rect:
        # 计算模拟器窗口在桌面的起始位置和终点位置 启动StartLeft,StartTop这两个参数是窗口在桌面的坐标位置,后面OCR识别到指定英雄的位置的时候必须要加回去
        StartLeft, StartTop, right, bottom = rect
        width = right - StartLeft
        height = bottom - StartTop
    else:
        StartLeft, StartTop, right, bottom = 0, 0, 1, 1
        width = right - StartLeft
        height = bottom - StartTop
    # 调用 pyautogui 进行窗口截图
    image = screenshot(region=(StartLeft, StartTop, width, height))

    # 这里是处理裁剪掉模拟器窗口图片的上面80%的图片面积,因为图片越小识别越快,0.8代表80%。如果识别不准确请少截取一点,但是我个人测试只留下20%下方图片即可
    heroBoxheight = image.height * 0.95
    # 这里是处理裁剪掉模拟器窗口图片的左边10%的图片面积,因为图片越小识别越快
    heroBoxwidth = image.width * 0.2

    # 记录一下截取掉的位置,后期识别到了点击的时候要架上,因为这部分位置被裁剪掉了
    StartLeft = StartLeft + heroBoxwidth
    StartTop = StartTop + heroBoxheight
    #裁剪图片到适合识别的大小
    image = image.crop((int(heroBoxwidth), int(heroBoxheight), image.width, image.height))
    oimage = image
    # 下面开始OCR
    image = np.array(image)
    result = ocr.ocr(image, cls=False)
    # 一堆if是在检查是否ocr成功,for是遍历识别结果
    point = win32api.GetCursorPos()
    if result is not None:
        for line in result:
            if line is not None:
                for word in line:
                    # 遍历识别结果
                    log.error(word)
                    for hero in heroname:

                        if str(word).find(hero) > -1 or heroname == "":
                            log.success(
                                f"发现英雄牌:{hero},坐标位置,x:{word[0][0][0] + StartLeft},y:{word[0][0][1] + StartTop}")
                            if isClick:
                                moveTo(word[0][0][0] + StartLeft, word[0][0][1] + StartTop)
                                click()

    return ""


if __name__ == '__main__':
    # 要截图的窗口标题,目前是腾讯手游模拟器,可以改成别的模拟器的标题一样通用
    windowName = "腾讯手游助手(64位)"
    # 要购买的卡牌名称
    heros = ['雷克顿', '莎弥拉', '卡西奥佩娅', '崔丝塔娜', '烬']


    # 监听键盘按键,如果是在手游模拟器里面按下的指定按键就启动识别
    def keyboardDown():
        currentWindow(windowName)


    # 监听鼠标按键,如果是在手游模拟器里面按下的按键就启动识别
    def on_click(x, y, button, pressed):
        if not pressed:
            currentWindow(windowName)
            return True


    # 判断当前鼠标所在窗口是否是指定模拟器窗口
    def currentWindow(windowTitle):
        point = win32api.GetCursorPos()
        hwnd = win32gui.WindowFromPoint(point)  # 请填写 x 和 y 坐标
        hwnd = win32gui.GetParent(hwnd)
        if hwnd == 0:
            hwnd = win32gui.WindowFromPoint(point)  # 请填写 x 和 y 坐标
        title = win32gui.GetWindowText(hwnd)
        if title == windowTitle:
            pool.submit(lambda cxp: ocr_hero_buy(*cxp),
                        (heros, windowTitle, True))


    log.success("正在载入OCR金铲铲自动识别选牌工具,正在初始化PaddleOCR模块")
    # 初始化 PaddleOCR
    ocr = PaddleOCR(use_angle_cls=False, lang="ch", use_gpu=False, debug=False, show_log=False)
    log.success("PaddleOCR模块初始化成功,您可以在游戏里按下D键或者鼠标任意键来触发自动选牌")
    # 监听D键 按一次d键启动一次卡牌识别功能并且购买
    keyboard.add_hotkey('d', keyboardDown)
    # 监听鼠标键 按一次启动一次卡牌识别功能并且购买解决死循环D牌导致的CPU占用问题。但是这样也很高,这里还能优化
    with pynput.mouse.Listener(
            on_click=on_click) as listener:
        listener.join()

免费评分

参与人数 62吾爱币 +60 热心值 +58 收起 理由
cdj1258 + 1 + 1 谢谢@Thanks!
datalai + 1 我很赞同!
kanbekotaro + 1 谢谢@Thanks!
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
Mist_G + 1 我很赞同!
风风魔王 + 1 + 1 我很赞同!
黑色小星星 + 1 + 1 我很赞同!
dxw709822 + 1 + 1 谢谢@Thanks!
xuna2009 + 1 + 1 我很赞同!
来学习的5558 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
xxxlsy + 1 + 1 我很赞同!
peihcheng + 1 + 1 我很赞同!
玄冥岚 + 1 + 1 我很赞同!
yy20240721 + 1 + 1 我很赞同!
liangkuai + 1 + 1 谢谢@Thanks!
bigzhang + 1 + 1 谢谢@Thanks!
ngfc + 1 热心回复!
Clousa95 + 1 + 1 谢谢@Thanks!
cloudy520 + 1 + 1 谢谢@Thanks!
card628 + 1 热心回复!
demigod.dww + 1 + 1 我很赞同!
liudongssnh + 1 + 1 谢谢@Thanks!
xiaomr1990 + 1 + 1 谢谢@Thanks!
一人孤看夜空 + 1 + 1 我很赞同!
CrazyNut + 1 + 1 训练个AI来玩玩吧
xuemantian0304 + 1 谢谢@Thanks!
qingne0130 + 1 + 1 热心回复!
pdsxiang + 1 + 1 热心回复!
john1628 + 1 + 1 谢谢@Thanks!
xljh888 + 1 + 1 谢谢@Thanks!
moonrabbit + 1 + 1 谢谢@Thanks!
hpjfcc23 + 1 + 1 热心回复!
qjlfl + 1 + 1 我很赞同!
zbh666 + 1 + 1 我很赞同!
DUDU666 + 1 + 1 谢谢@Thanks!
拜鳌 + 1 + 1 用心讨论,共获提升!
Only丶爱你 + 1 + 1 我很赞同!
iBlackHawk + 1 + 1 用心讨论,共获提升!
ZhaoLingyang + 1 + 1 热心回复!
PastorBonus + 1 + 1 谢谢@Thanks!
xxxcool + 1 + 1 谢谢@Thanks!
萌新00X + 1 + 1 我很赞同!
红太520 + 1 + 1 用心讨论,共获提升!
无知简单 + 1 + 1 热心回复!
kyctt + 1 + 1 我很赞同!
211aaa + 1 我很赞同!
boy2918 + 1 + 1 用心讨论,共获提升!
yxpp + 1 谢谢@Thanks!
xc00713 + 1 + 1 我很赞同!
pdcba + 1 + 1 谢谢@Thanks!
guoruihotel + 1 + 1 谢谢@Thanks!
rlaals0212 + 1 + 1 谢谢@Thanks!
adsgood + 1 好耶 这样我也有机会拥有三星了
small_天 + 1 用心讨论,共获提升!
dadao815 + 1 + 1 用心讨论,共获提升!
theStyx + 1 + 1 热心回复!
pluso + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
csq0216 + 1 我很赞同!
HTAED + 1 + 1 我很赞同!
han163426 + 1 热心回复!
25983600 + 1 + 1 我很赞同!
Naive2021 + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
HundSimon 发表于 2024-10-6 17:41
本帖最后由 HundSimon 于 2024-10-6 17:43 编辑

那个if循环嵌套看的有点难受,可以改成这样的

if result:
    for line in result:
        for word in line:
            if any(hero in str(word) for hero in heroname):
                log.success(
                    f"发现英雄牌:{hero},坐标位置,x:{word[0][0][0] + StartLeft},y:{word[0][0][1] + StartTop}")
                if isClick:
                    moveTo(word[0][0][0] + StartLeft, word[0][0][1] + StartTop)
                    click()

挺多代码也能复用,比如这样

rect = get_window_rect(windowTitle)
if rect:
    StartLeft, StartTop, right, bottom = rect
else:
    StartLeft, StartTop, right, bottom = 0, 0, 1, 1
width = right - StartLeft
height = bottom - StartTop
推荐
Eaglecad 发表于 2024-10-2 04:55
3#
 楼主| 无阻 发表于 2024-10-2 01:33 |楼主
目前代码只是适腾讯手游助手

想要换成别的模拟器就把窗口标题改成别的模拟器窗口标题就OK
4#
p297615 发表于 2024-10-2 01:34
感谢大佬分享
5#
jacky98617 发表于 2024-10-2 02:51
看看大佬的OCR是如何處理
6#
xixicoco 发表于 2024-10-2 04:17
占用啥的没办法嘛?
7#
liangqz 发表于 2024-10-2 06:29
有没有安卓版
8#
nzy8513 发表于 2024-10-2 07:19
看起来不错
9#
Yifan2007 发表于 2024-10-2 07:41
xixicoco 发表于 2024-10-2 04:17
占用啥的没办法嘛?

搞个定时释放内存的或者用按键精灵,他这个不知道为啥不用opencv会好一点,ocr就是占用高
10#
铁头张 发表于 2024-10-2 07:59
游戏没玩过,好奇一下怎么实现的。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 09:23

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表