一些疑问和一点点示例代码(
fatinghenji opened this issue · 12 comments
基于内存的外挂自瞄原理是可以拿到三维坐标,直接修改方向角来瞄准敌人,而基于计算机视觉的外挂只能拿到目标在屏幕上的投影,这是一个二维坐标,要解算出移动的向量很依赖游戏底层的参数(视场角等),目前还没想明白怎么一帧锁敌,也许将来会去实现。
这段话我没太理解。既然已经是一个二维平面上的两点间的直线运动[比如从A(1,1)到B(1,2)仅需要直线移动],为什么要计算三维空间中的滑动角度?
加入PID平滑控制鼠标
class PID:
def __init__(self, Kp, Ki, Kd):
self.Kp = Kp
self.Ki = Ki
self.Kd = Kd
self.P = 0
self.I = 0
self.D = 0
self.last_error = 0
self.last_time = time.time()
self.first_time = None
self.first_pos = None
self.last_pos = None
self.Kc = None
self.Tu = None
self.auto_tune = False
def pid_control(self, error, dt):
self.P = error
self.I += error * dt
self.D = (error - self.last_error) / dt
self.last_error = error
control = self.Kp * self.P + self.Ki * self.I + self.Kd * self.D
return control
def auto_tune_pid(self):
if not self.auto_tune:
return
if self.first_time is None:
self.first_time = time.time()
self.first_pos = get_current_pos()
return
self.last_pos = get_current_pos()
if self.Kc is None:
self._find_critical_gain()
else:
self._calculate_pid_parameters()
# 更新鼠标位置
dt = time.time() - self.last_time
error = self.first_pos - self.last_pos
control = self.pid_control(error, dt)
new_pos = get_current_pos() + control
set_mouse_pos(new_pos)
self.last_time = time.time()
def _find_critical_gain(self):
Kp = 0.1
while True:
self.Kp = Kp
error = self.first_pos - get_current_pos()
if self.last_error * error < 0:
self.Kc = self.Kp
self.Tu = time.time() - self.first_time
break
self.last_error = error
time.sleep(0.01)
Kp += 0.1
def _calculate_pid_parameters(self):
self.Kp = 0.6 * self.Kc
self.Ki = 1.2 * self.Kp / self.Tu
self.Kd = 0.075 * self.Kp * self.Tu
- 使用
Ziegler-Nichols
方法来自动调节 PID 参数。- 首先检查是否需要自动调节,如果不需要则直接返回。
- 如果需要自动调节,则记录下当前时间和鼠标位置,并逐渐增加比例系数
Kp
,直到系统出现持续的振荡。 - 记录下临界增益
Kc
和振荡周期Tu
后,根据公式计算出合适的 PID 参数。 - 使用了
time.sleep
函数来降低计算频率,从而避免 CPU 过度占用。
感谢提问:)
第一个问题是因为当我们在FPS游戏中移动鼠标时,视角也会跟着转动,敌人也会向我们移动的反方向运动,这会产生一个负反馈,导致与正常移动鼠标不同的结果。
就拿README.md中那个示意图来说,这个示意图是一个从屏幕上方向下的俯视图,点A是敌人真实位置,LR是屏幕,O是准星,A'是敌人A在屏幕上的投影,也就是我们在屏幕上看到的敌人位置。在FPS游戏中鼠标的移动实际距离大小与视角转动的角度成正比,在图中就是正比于
用二维的距离直线移动是可以在几步之内将鼠标准星收敛到目标身上的(因为整个程序只检测屏幕中心640*640像素的区域,这个区域比较小,所以
不知道这样解释是和否能解释清楚
感谢你提供的关于PID的代码,我会在之后的更新中实现它,如果你有兴趣可以尝试提交PR😉
关于FPS游戏FOV、DPI、手感一致的一切,这篇文章介绍的十分清晰。我觉得我们两个的实现思路是不同的。
你希望达到的是:
360度距离感知的是[目标在3D空间里的真实方位],尽可能忽略FOV变化所带来的影响。
你说的:
也可以用这样的方式实现锁敌,缺陷就是不能一步到位,但是实现了准星吸附的效果。
对应的应该是:
对照标准:开启一倍镜,A敌人恰好在屏幕左边缘,鼠标移动X cm后击杀;开启二倍镜,视野变窄,B敌人也在屏幕左边缘,鼠标移动X cm后击杀......缺点:肌肉记忆。因为不同FOV的畸变差异,一次可能拉不到位,依赖二次修正。
那么能否使用里面提到的网站mouse sensitivity来解决呢?
感谢分享,这些资源我在写这个项目初期都翻阅过,我之前的表达有点简陋,没有表达清楚,我先简单回答你的问题,然后重新表述一遍我之前的回答,然后再回答你的疑问。
你希望达到的是:
360度距离感知的是[目标在3D空间里的真实方位],尽可能忽略FOV变化所带来的影响。
这一句话我没太理解,我是想找到一个鼠标移动函数,这个移动函数的移动向量可以实现一次移动就把准星放在敌人的身上,但是这个移动向量的计算需要涉及到真实的FOV,所以需要找和FOV之间的关系
对应的应该是:
对照标准:开启一倍镜,A敌人恰好在屏幕左边缘,鼠标移动X cm后击杀;开启二倍镜,视野变窄,B敌人也在屏幕左边缘,鼠标移动X cm后击杀......缺点:肌肉记忆。因为不同FOV的畸变差异,一次可能拉不到位,依赖二次修正。
这是我如果实现了依赖FOV的一帧拉枪之后会碰到的问题,但是我目前的处理方法是使用最简单的移动函数
那么能否使用里面提到的网站mouse sensitivity来解决呢?
这个网站只能解决不同游戏间的FOV和鼠标灵敏度对应问题,对于一个游戏内的应该是没什么帮助的
一帧锁敌
首先是一帧锁敌,我想实现的是一次定位,就是能够一次移动鼠标将准星瞄准在敌人的身上,而不是在几次瞄准内逐步逼近敌人最后收敛到敌人的身上
先定义一下
在游戏中的
需要注意的是,游戏设置里的[视野范围值]并不代表真正的”角度”,如APEX 106代表120度水平视野;cai'hong'l 89代表垂直89度,换算为水平120度 作者:灰機Harukidayo https://www.bilibili.com/read/cv15218452/ 出处:bilibili
而我并没有查到关于Apex中设置里的
设准星的坐标为
我曾经设想的鼠标移动方向向量为
而这个移动的向量需要考虑上这一点,所以我将这个问题放到三维中去考虑了。还是用那个示意图,因为鼠标移动实际上是在转动人物的视角,而当鼠标匀速移动时视角也是匀速转动的,可以认为视角变化的角度是正比于鼠标移动的距离的。
可以认为水平方向和竖直方向的移动是独立的,因为当水平移动鼠标的时候,敌人的投影对应的纵坐标应该是不变的,竖直移动鼠标也是这样。所以我将这个问题分开考虑了,分成了水平的移动和竖直的移动。
设
在游戏中经过实验发现
-
$fov$ 同时管控水平FOV和竖直FOV -
$fov$ 其实是对角线上的FOV,这样当FOV发生变化时水平和竖直两个方向的可视范围都会变化
我个人倾向于第二种猜测,毕竟这是简洁的,并且对于不同的屏幕比例都可以适应
其实到这里已经可以实验验证了,但是后续是因为鼠标驱动的dll文件是从网上扒的(自己不会写,github上开源的没有微软驱动证书,过不了Apex检测),我并不是很懂里面的鼠标移动函数的原理。我在游戏中实验的时候会发现一些奇怪的问题,比如一次向右移动3000个像素甚至不如向右移动5次200像素移动的远(排除了移动太远而导致转过整数圈的情况),所以实验就中止了 。
如果这些都解决了,就会碰到你所说的那个问题:
对照标准:开启一倍镜,A敌人恰好在屏幕左边缘,鼠标移动X cm后击杀;开启二倍镜,视野变窄,B敌人也在屏幕左边缘,鼠标移动X cm后击杀......缺点:肌肉记忆。因为不同FOV的畸变差异,一次可能拉不到位,依赖二次修正。
这就需要对于每个倍镜都去验证对应的FOV和鼠标灵敏度,相当于使用不同的倍镜下,需要使用不同的鼠标移动向量
后来用
对于这个网站mouse sensivity,它更像是一个跨游戏的
不知道能否回答你的疑问
非常感谢。理解了。
编辑,如果真的做到一帧拉枪,应该需要相当不错的显卡,即使以90帧来运行游戏,1帧的时间约为1/90≈11ms,本项目采用的截图方式按readme中所述已经有5ms。留给模型的时间仅剩6ms,应当需要相当好的显卡才能做到这么短的推理时间吧。
非常感谢。理解了。 编辑,如果真的做到一帧拉枪,应该需要相当不错的显卡,即使以90帧来运行游戏,1帧的时间约为1/90≈11ms,本项目采用的截图方式按readme中所述已经有5ms。留给模型的时间仅剩6ms,应当需要相当好的显卡才能做到这么短的推理时间吧。
目前并不能实现真正的一帧拉枪(游戏的一帧)是因为在原理上的不足而不是硬件上的不足,就算硬件非常的强大仍然不能实现真正的一帧拉枪。目前的方案是能够在几次推理内锁定敌人,而推理的帧率的上限就是游戏的帧率,所以就算能够达到代码一次循环时间小于游戏一帧的刷新时间,在作出鼠标移动命令之后仍然需要等待下一帧的刷新来看到鼠标移动的反馈,所以仍然需要几帧来实现锁敌。
这是因为目前的鼠标移动函数并不能一次移动就将准星对准敌人,需要几次来逼近。目前的方案能实现的是能够在比较短的时间内锁定目标,而这个时间并没有短到人感受不到,但是可以感受到准星的比较强的吸附感(可能跟手柄的辅助瞄准一样)。要实现真正的一帧拉枪,就只能在原理上优化。
如果不在原理上优化,那么能够争取的就是感受上的一帧拉枪(可以称为伪一帧拉枪),如果能通过优化模型和并行加速来达到锁敌时间小于人的反应时间,那么也可以认为是一帧拉枪,当然这样的情况下屏幕刷新率也要比较高。
非常感谢。理解了。 编辑,如果真的做到一帧拉枪,应该需要相当不错的显卡,即使以90帧来运行游戏,1帧的时间约为1/90≈11ms,本项目采用的截图方式按readme中所述已经有5ms。留给模型的时间仅剩6ms,应当需要相当好的显卡才能做到这么短的推理时间吧。
其实6ms的推理并不是很难达到的,目前的时间主要消耗在主要功能没有并行上(每次推理的开始都需要等待截图)
我的显卡是RTX 3050Laptop,在我的显卡上单独跑代码的话推理时间稳定在10ms,我用的是Yolov5s模型,而Yolov5n的模型计算量是v5s的四分之一,如果换成v5n的话理论上推理会快四倍,推理时间也许可以挺进3ms,换个好点的显卡1ms也是可能的。
如果并行和模型都优化了剩下的优化空间就是python的龟速了,那时候可能会尝试用C++重写
突然意识到一个逻辑问题。
所以随着视角的转动,敌人会和准星“双向奔赴”。
可是“双向奔赴”发生在下一帧,而不是已经推理完毕的本帧。而做到本帧的一帧拉枪是可以的。如果要解决你提到的问题,是否需要引入预测算法呢?如果需要引入,那么应当预测未来多少帧呢?
突然意识到一个逻辑问题。
所以随着视角的转动,敌人会和准星“双向奔赴”。
可是“双向奔赴”发生在下一帧,而不是已经推理完毕的本帧。而做到本帧的一帧拉枪是可以的。如果要解决你提到的问题,是否需要引入预测算法呢?如果需要引入,那么应当预测未来多少帧呢?
本帧的一帧拉枪是很难实现的,因为之前的回答,而设计预测算法其实就是去解决一帧拉枪的问题,要么就是找到了一帧拉枪的公式,要么就是通过大量数据训练或者实验找到一个拟合公式,而前者需要有游戏的
似乎网站有计算方法。示例
好像是付费才能使用的功能,不清楚为啥我发的这个链接可以直接看。注意:只需要调整箭头所指的部分即可,调整转换到
的部分会蹦出来付费提示。
有一个更好的计算?Apex Legends Calculator,网址里面的note部分很有意思:
Notes
Apex Legends' FOV is 4:3, but the in-game value is not accurate. The actual rendered 4:3 FOV is cl_fovScale * 70, however the conversion from the ingame slider to cl_fovScale is a mess. If you set the FOV to 110, it will become 1.55 cl_fovScale, resulting in 108.5° instead of 110°.
Apex Legends' ADS sensitivity scales by the amount zoomed in, maintaining a 1:1 tracking speed across all FOVs. However the calculation uses the rounded hipfire FOV value which makes the scaling slightly inaccurate.
The weapon optics actually zoom in the amount they say they do, but only at 70 FOV, cl_fovScale 1. The zoom will be higher than what it says it is at higher FOVs, with a 10x optic zooming in ~12.77x at 110 FOV.
For best results, set the fov using the config file since you will know 100% what your value is. Set your ADS sensitivity to the corrected multipliers for the correct conversion. Alternatively you can match the rotation distance, but it will get increasingly more sensitive the more you zoom in.
ADS 1x is for SMG, SG, and Pistol ironsights (except RE-45). ADS 1x is identical to Optic 1x. ADS 2x is for AR, LMG, and Sniper ironsights.
更详细的说明:Apex Legends Calculator blog
似乎网站有计算方法。示例 好像是付费才能使用的功能,不清楚为啥我发的这个链接可以直接看。注意:只需要调整箭头所指的部分即可,调整
转换到
的部分会蹦出来付费提示。 有一个更好的计算?Apex Legends Calculator,网址里面的note部分很有意思:Notes
Apex Legends' FOV is 4:3, but the in-game value is not accurate. The actual rendered 4:3 FOV is cl_fovScale * 70, however the conversion from the ingame slider to cl_fovScale is a mess. If you set the FOV to 110, it will become 1.55 cl_fovScale, resulting in 108.5° instead of 110°.
Apex Legends' ADS sensitivity scales by the amount zoomed in, maintaining a 1:1 tracking speed across all FOVs. However the calculation uses the rounded hipfire FOV value which makes the scaling slightly inaccurate.
The weapon optics actually zoom in the amount they say they do, but only at 70 FOV, cl_fovScale 1. The zoom will be higher than what it says it is at higher FOVs, with a 10x optic zooming in ~12.77x at 110 FOV.
For best results, set the fov using the config file since you will know 100% what your value is. Set your ADS sensitivity to the corrected multipliers for the correct conversion. Alternatively you can match the rotation distance, but it will get increasingly more sensitive the more you zoom in.
ADS 1x is for SMG, SG, and Pistol ironsights (except RE-45). ADS 1x is identical to Optic 1x. ADS 2x is for AR, LMG, and Sniper ironsights.更详细的说明:Apex Legends Calculator blog
非常感谢你的分享!我之后会在更新中试图实现之前的一帧拉枪想法
一帧拉枪如果知道相机参数(FOV)等,应该可以直接用迭代方法求出鼠标移动距离,这个问题不一定有解析解,但是近似总是可以做到很精确的
一帧拉枪如果知道相机参数(FOV)等,应该可以直接用迭代方法求出鼠标移动距离,这个问题不一定有解析解,但是近似总是可以做到很精确的
因为不会搞(悲),最近也一直没时间去学习qaq