前期提要:
本文章仅供技术讨论使用。
关于如何通过YOLOV5去检测到王者中的敌方人物,在网上有很多相关的文章和教学视频我在这里就不过多的阐述,本篇文章主要讲的是在实现中比较难处理的一些技术点:如何获取高刷新率的手机屏幕、王者荣耀中的技能遥杆方向和实际技能释放方向不一致的问题要如何解决。
如何获取高刷新率的手机屏幕
目前主流的解决方案是通过scrcpy来实现高刷新率的获取,其原理是让手机上建立一个视频流rtp的服务端,然后电脑通过对接这个rtp视频流就可以直接获取手机屏幕的信息根据这个理论得到的最终时间延迟仅仅5ms
如何实现呢?
scrcpy的文档中的描述如下
这里说好要如何实现了,但是这都是通shell命令来实现了,那么让python去执行这个shell命令,然后让python搭建一个客户端接收来自手机端的视频流数据,最后通过opencv来显示不就可以了吗?是的,当这些都已经有人封装好一个包给你,你只需要调用即可
https://github.com/leng-yue/py-scrcpy-client
它的文档中关于如何使用也是非常简单的:
还有细节:慢放效应如何解决
经过我实际上手使用后发现,一旦我把接收到的视频帧数据进行处理,我在代码上打印出了fps高达100多,但是电脑获取的手机画面就延迟非常高!为什么呢?这是因为接收到一帧后处理花费10ms然后放到opencv显示,而opencv显示的时候会比较慢,实际上1秒钟代码可以处理100张,但是opencv显示只能显示40张,那么剩下60张就会放到第2秒中显示,这样的话第二秒就要显示160张图片,第3秒也就是120+100张,以此类推你就会发现越到后面你发现电脑显示手机屏幕中游戏人物的动作非常流畅,但是游戏里面的人物动作非常慢。解决方法也是非常简单,自己定义一个队列,开启两个线程,一个是显示线程,一个是处理游戏数据的线程,当处理游戏画面线程处理好一帧图片后就把这帧放到大小为3的队列(大小可以自己确定)中去,而显示线程就会一直去队列中取帧来显示,这就确保取到的帧都是最新处理过的。
如何解决遥杆方向和技能释放方向不一致的问题
问题描述:
假设我识别到敌人在我的左上方60°,那么我技能遥杆移动的方向也是左上方60°,但是由于王者是一个3D游戏,遥杆的位置和人物的位置不一样,那么技能遥杆移动的方向也是左上方60°,可能技能释放的反向就是54°。你可能回想到加一个偏移比如60°偏移-6°即可?但实际情况是如果遥杆瞄准方向是65°,那么技能释放方向就是57°,二者相差由6°变味了8°,如果遥杆135°,那么实际技能释放就是150°相差变为+25°,这就很难做一个简单的偏移来解决问题了。
我做了很多信息收集和猜想假设最后得出了公式
当我把技能释放的角度固定为x轴的角度的时候,我发现魔法值变成了线性关系了
通过计算得到 魔法值=-0.0066x+1.6 其中x是敌人和我在x轴的角度
最终得到的效果
如何提升准度呢?
通过机器学习的sklearn工具包以及最新的5个角度数据,通过5个角度的数据进行线性回归,之后预测第6和第7个预测数据,一次提升准确度。示例代码如下:
import numpy as np
from sklearn.linear_model import LinearRegression
class Predict:
def __init__(self):
self.angles = []
def set(self, angle):
self.angles.append(angle)
if len(self.angles) > 5:
self.angles.pop(0)
def predict(self):
if len(self.angles) < 5:
return None
# 将时间和角度映射成一维数组,并reshape成(n, 1)格式,方便模型训练
X = np.array(range(len(self.angles))).reshape(-1, 1)
y = np.array(self.angles).reshape(-1, 1)
model = LinearRegression().fit(X, y)
# 对第6个和第7个时间点进行预测
next_time_steps = np.array([len(self.angles), len(self.angles) + 1]).reshape(-1, 1)
prediction = model.predict(next_time_steps)
return prediction.flatten()
predictor = Predict()
predictor.set(10)
predictor.set(20)
predictor.set(30)
predictor.set(40)
predictor.set(50)
print(predictor.predict()) # Outputs: [60. 70.]
predictor.set(60)
print(predictor.predict()) # Outputs: [70. 80.]