崩铁自动小助手ASR开发实录

文章目录

  • 崩铁小助手ASR
    • 功能计划
    • 功能实现
      • 操作的模拟
      • 窗口的识别
      • 游戏窗口识别
      • 副本导航
        • 和平指南页面识别
        • 页面中高亮位置的寻找
        • 右侧具体副本的寻找
  • 未完待续
  • 开源地址

崩铁小助手ASR

天下苦二游上班坐牢久矣。方舟有MAA造福大众,免去日常之苦,能让我专心于关卡,但是米家游戏就不行了,于是就有了这个崩铁小助手——AutoStarRail的想法。

功能计划

目前初步计划就是能够实现每天自动清体力,领日常奖励,让我不用操心每天还得上线清体力的事情。最后实现的界面如下,大概和方舟的maa差不多。
![[Pasted image 20240621134224.png]]

但是为了防止崩铁全屏运行时难以观察运行信息,所以又做了个始终在前台的message窗口,用于实现实时显示自动化脚本的信息。(窗口可放置在任意位置)
在这里插入图片描述

经过测试,选择好要刷的本(经验\钱、行迹、突破素材、仪器这些都没问题)后能够自动导航至目标副本,然后识别体力,刷到没体力为止。
演示视频如西瓜视频:从重复劳动中解脱-崩铁自动日常小助手
抖音:从重复劳动中解脱-崩铁自动日常小助手
完整开源代码见 AutoStarRail,欢迎大家star。

功能实现

操作的模拟

操作上使用vgamepad创建虚拟手柄来对游戏进行操作。虽然这样会多一个虚拟设备,但是由于手柄操作时对选中部件的高亮,能够更容易的识别当前选中的东西,并进行精确的操作。


class Gamepad:def __init__(self,pigeon = None):# 初始化一个手柄self.pigeon = pigeonself.gamepad = vgamepad.VX360Gamepad()# 初始化手柄状态self.reset_gamepad()def reset_gamepad(self):self.gamepad.reset()#键位扳机摇杆全部重置成初始状态self.gamepad.update()# gamepad 操作def click_button(self,button,duration=0.15):self.gamepad.press_button(button)self.gamepad.update()time.sleep(duration + random.randint(0,int(0.05*100))/100)self.gamepad.release_button(button)self.gamepad.update()if self.pigeon:self.pigeon("click " + button_mapping[button])def press_button(self,button):self.gamepad.press_button(button)self.gamepad.update()if self.pigeon:self.pigeon("press " + button_mapping[button])def release_button(self,button):self.gamepad.release_button(button)self.gamepad.update()def LEFT_TRIGGER(self,value):self.gamepad.left_trigger_float(value)# 左扳机轴 value改成0.0到1.0之间的浮点值,可以精确到小数点后5位self.gamepad.update()def RIGHT_TRIGGER(self,value):    self.gamepad.right_trigger_float(value)# 右扳机轴 value改成0.0到1.0之间的浮点值,可以精确到小数点后5位self.gamepad.update()def LEFT_JOYSTICK(self,theta,amplitude,ran_theta = 2*np.pi/25,ran_amp = 1/25): #x_value, y_value):theta = theta + random.randint(0,ran_theta*100)/100amplitude = amplitude + random.randint(0,ran_amp*100)/100x_value = 1.414*amplitude * np.cos(theta)y_value = 1.414*amplitude * np.sin(theta)self.gamepad.left_joystick_float(x_value, y_value)# 左摇杆XY轴  x_values和y_values改成-1.0到1.0之间的浮点值,可以精确到小数点后5位self.gamepad.update()if self.pigeon:self.pigeon("" + "Left joystick")def RIGHT_JOYSTCIK(self,theta,amplitude,ran_theta = 2*np.pi/25,ran_amp = 1/25):theta = theta + random.randint(0,int(ran_theta*100))/100amplitude = amplitude + random.randint(0,int(ran_amp*100))/100x_value = amplitude * np.cos(theta)y_value = amplitude * np.sin(theta)self.gamepad.right_joystick_float(x_value, y_value)# 右摇杆XY轴  x_values和y_values改成-1.0到1.0之间的浮点值,可以精确到小数点后5位self.gamepad.update()if self.pigeon:self.pigeon("" + "Left joystick")def joystick_movement(self, theta=0, duration=0.5, amplitude=1):start_time = time.time()while time.time() - start_time < duration:# 时间-角度序列theta_time = theta * (time.time() - start_time) / duration# 幅度amplitude_time = amplitude * (time.time() - start_time) / durationself.RIGHT_JOYSTCIK(theta_time, amplitude_time)time.sleep(0.01)

窗口的识别

这部分涉及到图像的一些识别。为了减少计算资源的消耗,本文主要使用paddleocr识别字符来定位。少部分地方用到了矩形框的识别。

游戏窗口识别

脚本启动时应当先识别当前有没有打开启动器、或游戏,再决定是否需要打开游戏。
对于老版本而言由于启动器和游戏名称都为“崩坏:星穹铁道”,因此无法仅从名称上判断窗口是哪个,还需要进一步判断是启动器还是游戏。可以通过窗口上是否有启动器上独有的字符判断是否为游戏。
因此,窗口检测的流程如下图所示。

检查星穹铁道窗口
存在星穹铁道
检查特征字符
当前是旧启动器
游戏已启动
点击打开游戏
不存在星穹铁道
检查米哈游启动器窗口
不存在任何启动器
搜寻启动器并打开
启动了米哈游启动器

其相关代码在start_game.py中,该部分代码能够实现自动识别当前是否有游戏窗口,如果无窗口则逐步实现打开游戏。

副本导航

该部分代码放置在daily_tasks.py中。
导航的第一步是打开星际和平指南,该步较为简单,直接使用虚拟手柄打开轮盘,然后拨到对应位置即可。

def open_star_guide(self):# 打开星际和平指南self.gp.press_button(LEFT_SHOULDER)self.gp.joystick_movement(np.pi * 1 / 4, duration= 1) # 移动到指南time.sleep(0.8)self.gp.joystick_movement(amplitude=0)self.gp.release_button(LEFT_SHOULDER)self.pigeon("打开星际和平指南")time.sleep(0.9)

随后需要进一步识别星际和平指南的页面,以及寻找对应的副本。流程如下:

经验/武器经验/信用点
行迹材料
突破材料
遗器
打开星际和平指南
领取日常奖励
每日实训
清体力
生存索引
拟造花萼金
拟造花萼赤
凝滞虚影
侵蚀隧洞
和平指南页面识别

对于和平指南的页面,如每日实训、生存索引的识别,只需通过ocr识别有无对应字符即可找到该页面

def find_page(self,tag = "生存索引"):# 已经打开星际和平指南后,通过手柄切换标签找到对应的pageif TargetDetector(self.window,self.gp).search_button(tag, RIGHT_SHOULDER):self.pigeon("找到" + tag)else:self.pigeon("未找到" + tag)

其中TargetDetect中的search_button为递归寻找,直到满足条件。

def search_button(self, btn_text, action):"""查找相应按钮:param btn_text: 目标按钮名称:param action: 找不到按钮对应操作:return:"""figure, _, _, _, _ = self.win_action.get_screenshot(self.window)find, _ = self.findText(figure,btn_text)if find:print(f'找到{btn_text}')return Trueelse:self.gp.click_button(action)time.sleep(0.2 + random.randint(0, 10) / 100)return self.search_button(btn_text, action)
页面中高亮位置的寻找

在确定找到页面后,我们需要识别出当前高亮的标签(如拟造花萼、侵蚀隧洞)是哪个。
此处我们可以先使用OCR识别有无目标文字,如果没有,说明当前页面不存在目标标签,需要继续翻页。如果存在,通过灰度阈值识别目标文字所在区域的灰度是否是选中的灰度,如果是则退出寻找,否则继续寻找。

范围内
范围外
查询目标文字
按下down_button
计算目标文字所在区域灰度
结束查找
def find_highlight(self, btn_text, action=None): """ 寻找按钮的高亮状态。通过截图并查找按钮文本,判断按钮是否处于高亮状态。如果按钮未高亮,则点击按钮并重试。 主要用于自动化测试中对按钮状态的判断和操作。 参数: btn_text (str): 按钮的文本内容,用于查找按钮。 action (function, optional): 当按钮未高亮时执行的操作,默认为None。可以是一个函数,该函数会在按钮未高亮时被调用。 返回: bool: 如果按钮处于高亮状态,则返回True;否则返回False。 """ # 截取窗口的屏幕快照 # 转到灰度上看灰度值。先截取字附近的区域 figure, _, _, _, _ = self.win_action.get_screenshot(self.window) # 在屏幕快照中查找按钮文本 find, pos = self.findText(figure, btn_text) # 如果按钮未找到 if not find: # 没找到self.gp.click_button(action)time.sleep(0.2 + random.randint(0, 10) / 100)return self.find_highlight(btn_text, action)ave_gray = self.get_average_gray_value(figure,pos)if ave_gray < 100: # 高亮-黑色print(f'找到{btn_text}')return Trueelse:self.gp.click_button(action)time.sleep(0.2 + random.randint(0, 10) / 100)return self.find_highlight(btn_text, action)
右侧具体副本的寻找

使用手柄的话,右侧选择的副本会有一个橙色的矩形框作为高亮,因此识别矩形框就知道我们当前选中的是哪个了。
使用HSV颜色空间对橙色进行区分的效果并不理想。因此还是采用了矩形边框识别。

    def detect_dungeon_boxes(self,image,text):# 可以找出当前高亮的选择区域gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)edges = cv2.Canny(gray, threshold1=100, threshold2=200)contours, _ = cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)min_area_threshold = 10  # 设定最小面积阈值height, width = image.shape[:2]  # 获取图像高度和宽度area_ratio = 0.2target_area = height * width * area_ratio  # 计算目标最大面积max_area = 0for contour in contours:area = cv2.contourArea(contour)if area > max_area and area < target_area:max_area = areamax_contour = contourfor contour in contours:area = cv2.contourArea(contour)if area > min_area_threshold:# 计算边界框x, y, w, h = cv2.boundingRect(contour)# 绘制矩形cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)# 如果找到了符合条件的轮廓if max_contour is not None:# 获取边界框x, y, w, h = cv2.boundingRect(max_contour)# 截取该矩形区域cropped_image = image[y:y+h, x:x+w]find, pos = self.findText(cropped_image,text)# 显示截取的图像# cv2.imshow('Cropped Rectangle', cropped_image)# cv2.waitKey(0)# cv2.destroyAllWindows()return findelse:# print("Not found.")return Falsedef find_dungeon(self,btn_text, action = None):figure, _, _, _, _ = self.win_action.get_screenshot(self.window)# self.gp.click_button(action)if self.detect_dungeon_boxes(figure,btn_text):print('已选中:' + btn_text)else:self.gp.click_button(action)time.sleep(0.2 + random.randint(0, 10) / 100)return self.find_dungeon(btn_text, action)

未完待续

GUI、消息窗口、邮件等功能以及当前版本未实现的功能待后续更新。

开源地址

  • AutoStarRail

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/31421.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LaTeX教程(013)-LaTeX文档结构(13)

LaTeX教程(013)- LaTeX \LaTeX LATE​X文档结构(13) 接上一篇 一个新的设计案例 首先&#xff0c;我们先建立一个目录文件&#xff0c;并导入到文档中。操作如下: 第一步创建文件test.tex&#xff0c;写入如下代码并编译两次: \documentclass{book} \usepackage[a5paper,m…

Airtest自动化测试框架

airtest是网易出品的一个基于python的跨平台的&#xff0c;基于图像识别的自动化测试框架&#xff0c;适用于游戏和APP&#xff0c;支持多平台&#xff0c;此款框架不需要一行行的写代码&#xff0c;而是用屏幕截屏的方式来进行自动化测试 之前提到过使用weditor工具进行元素定…

什么是OAuth2分布式授权协议?

今天我将和大家一起探讨在系统安全领域非常常见的一种授权协议&#xff0c;这就是OAuth2协议&#xff0c;这个协议通常用于对请求访问进行安全控制。在引入这个协议之前&#xff0c;让我们先来回顾两个基本概念&#xff0c;一个是认证&#xff0c;一个是授权。这两个概念比较容…

探索产业园的独特产业定位与价值

数字影像产业园的产业定位独特且全面&#xff0c;涵盖了数字贸易、数字服务、数字文旅和数字基建四大主导产业方向&#xff0c;体现了园区在数字化转型和产业升级方面的前瞻性和创新性。 一、数字贸易的推动者 数字影像产业园致力于推动数字贸易的发展&#xff0c;搭建全球化、…

mysql中的lead函数和over函数

文章目录 mysql中的lead函数和over函数作用需求场景实现方法group by分组和使用over函数分组有什么区别&#xff1f; mysql中的lead函数和over函数 作用 over函数是用来分组加排序的&#xff0c;然后等over函数分好组排好序之后&#xff0c;再使用lead函数去找当前分组内的下…

NUC980-OLED实现全中文字库的方法

1.背景 有一个产品&#xff0c;客户需要屏幕展示一些内容&#xff0c;要带一些中文&#xff0c;实现了OLED12864的驱动&#xff0c;但是它不带字库&#xff0c;现在要实现OLED全字库的显示 2.制作原始字库 下载软件pctolcd2002 设置 制作字库 打开原始文件 用软件自带的&…

“用友审批+民生付款”,YonSuite让企业发薪更准时

随着现代企业经营模式的不断创新和市场竞争的加剧&#xff0c;企业薪资管理和发放的效率、准确性和及时性已成为企业管理的重要一环。然而&#xff0c;在实际操作中&#xff0c;许多企业面临着薪资管理复杂、发放流程繁琐、数据不准确等难点和痛点。为了解决这些问题&#xff0…

【重磅消息】微软开源了自家的Florence-2,处理各种视觉任务的统一模型

在人工通用智能&#xff08;AGI&#xff09;系统的世界里&#xff0c;一个重要的转变正在发生&#xff0c;那就是利用多功能的、预先训练好的表征&#xff0c;在各种应用中表现出与任务无关的适应性。这种转变始于自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;现在…

机械硬盘和固态硬盘的区别及判断硬盘类型的方法

HDD&#xff08;机械硬盘&#xff09;和 SSD&#xff08;固态硬盘&#xff09;的主要区别 存储介质 HDD&#xff1a;使用磁性盘片&#xff08;磁盘&#xff09;和机械读写头SSD&#xff1a;使用闪存芯片 速度 HDD&#xff1a;读写速度较慢&#xff0c;因为需要机械读写头在…

新学期分班群发话术

尊敬的家长们&#xff1a; 我是XX学校X年级的班主任XXX老师。随着新学期的到来&#xff0c;我带着满心的期待和责任&#xff0c;向各位宣布一个重要的信息&#xff1a;本校即将开始新学年的分班工作。 分班的目的&#xff1a; 分班是为了适应不同学生的学习需求&#xff0c;确…

SaaS企业营销:PLG转型下SaaS企业如何成为赢家

在数字化浪潮的推动下&#xff0c;SaaS&#xff08;软件即服务&#xff09;行业正经历着前所未有的变革。特别是随着产品引领增长&#xff08;PLG&#xff09;模式的兴起&#xff0c;SaaS企业正面临着前所未有的机遇与挑战。如何在PLG转型中脱颖而出&#xff0c;成为行业赢家&a…

汇川学习笔记7 - 雕刻机项目

1、系统上电轴准备好之后&#xff0c;自动复回原点一次&#xff0c; 2、在雕刻机面板上有三个按钮用来控制画三种图形 3、注意cnc代码放置的文件夹 4、FILE0文件内容 5、FILE1文件内容 6、FILE2文件内容 7、程序代码下载地址 https://download.csdn.net/download/qq_6191667…

无需科学上网:轻松实现国内使用Coze.com平台自己创建的Bot(如何实现国内免费使用GPT-4o/Gemini等最新大模型)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 如何在国内使用 Coze.com 创建的 Bot 📒📝 创建Bot📝 实现国内使用📝 测试⚓️ 相关链接 ⚓️📖 介绍 📖 Coze.com 是一个强大的平台,允许用户创建各种类型的 Bot。然而,许多国内用户可能会遇到访问问题,导致无法…

Centos7.9安装openldap

文章目录 一、背景二、正文2.1 openldap服务端必要软件安装2.1.1使用yum命令安装2.1.2安装libdb相关依赖2.1.3复制一个默认配置到指定目录下&#xff0c;并授权&#xff0c;这一步一定要做&#xff0c;然后再启动服务&#xff0c;不然生成密码时会报错2.1.4授权给ldap用户&…

windows系统共享文件时,有权限文件访问被拒绝

我们在使用windows操作系统的时候&#xff0c;需要复制或者更改网络中的共享文件。但是有时候会出现图下的情况&#xff1a;文件访问被拒绝 查看共享文件的安全属性&#xff0c;发现Everyone的权限是完全控制的 这个时候我们可以看到&#xff0c;这个共享文件图标右上方带了一把…

vue2实现一个简易实用的日历(可特殊标记多个日期)

效果如下&#xff1a; <template><div class"calendar"><div class"header"><button click"previousMonth"><</button><h2>{{ currentYear }}-{{ currentMonth }} </h2><button click"nex…

【SpringCloud】Nacos

Nacos简介 2018年6月&#xff0c;Eureka 2.0宣布闭源&#xff08;但1.X版本仍然活跃&#xff09;&#xff0c;同年7月&#xff0c;阿里Nacos宣布开源&#xff0c;并迅速成为国内开发者关注的焦点。作为Eureka的替代品&#xff0c;Nacos目前已经成为国内开发者的首选。 Nacos&…

error: ‘CV_YUV2BGR_UYVY‘ was not declared in this scope

遇到这个问题时&#xff0c;按照如下修改可解决问题。 //cv::cvtColor(yuvImg, rgbImg, CV_YUV2BGR_UYVY);cv::cvtColor(yuvImg, rgbImg, cv::COLOR_YUV2RGB_UYVY);

浅析Vite本地构建原理

前言 随着Vue3的逐渐普及以及Vite的逐渐成熟&#xff0c;我们有必要来了解一下关于vite的本地构建原理。 对于webpack打包的核心流程是通过分析JS文件中引用关系&#xff0c;通过递归得到整个项目的依赖关系&#xff0c;并且对于非JS类型的资源&#xff0c;通过调用对应的loade…

《人人都是产品经理》笔记2:一个需求的奋斗史

一个需求的奋斗史 用户&#xff01;用户&#xff01;为什么会有需求&#xff1f;用户比客户更大以用户为中心的思想&#xff0c;以老板为中心的行动 用户研究方法 需求采集用户需求并不是产品需求&#xff0c;满足需求的三种方式把用户需求转化成产品需求 需求打包 BRD 产品会议…