使用python完成光明旅者冲刺挑战成就
前言
最近在玩游戏光明旅者(Hyper Light Drifter),真的很好玩,强烈推荐。
其中的冲刺有一定的冷却CD,但是抓住时机以一定频率冲刺就可以破除CD不停地冲刺,我尝试了一下连续冲刺十五次是没有问题的,但是冲刺挑战成就竟然需要连续冲刺800下!
于是就有了这篇说明使用python刷成就的方法的文章。
如果不想看探索历程的,可以直接跳转到文章的解决方案。
探索历程
首先冲刺挑战的判定仅仅是连续冲刺,并不需要绕圈。
所以要想利用python冲刺的话,改为键鼠操作,然后把鼠标放在固定位置,控制键盘以一定频率按动,让人物不停来回横跳就行了。
我打算先实现用python操控游戏,然后再调试频率。
试验开始。
寻找键鼠操纵库
pykeyboard
在网上寻求答案的时候,我找到的第一个库是pykeyboard,当时我二话不说就用了起来。
from pykeyboard import PyKeyboard
from time import sleep
k = PyKeyboard()
while True:
k.press_key(k.space_key)
sleep(0.2)
然后确实在vscode运行程序之后,光标处不停地输入着空格。
大喜过望的我把光明旅者游戏界面打开,然而并没有预想中的效果。
主人公还是一动不动地站在原地,而当我按下空格的时候才会冲刺。
第一次尝试失败。而且我还不知道失败的原因。
pyautogui
我认为可能是库的原因,所以又换了一个库。这次是热门的pyautogui。
import time
import pyautogui
while True:
pyautogui.press('space')
time.sleep(0.2)
然而不知道为什么还是不行。
郁闷中我又去网上查找答案,我先是觉得是光标的问题,如果把光标移动进入游戏界面,就可以顺利操控游戏。但是我并没有找到相关的内容。
然后我又把键位调成了鼠标右键冲刺,原本按空格的代码改成了
pyautogui.rightClick()
但还是不行。
我十分地迷茫。程序根本没有在游戏中进行操作,任何的实际键鼠操作都可以顺利地在游戏中响应。
甚至没有被程序影响。
这时候我忽然明白如果程序确实没有干涉到游戏读入键鼠的操作,因为如果它们读入的是同一个键鼠的话,那么在程序运行的时候是不可能用实际的键鼠流畅操作游戏的,而是会被程序所影响变得迟钝。
python也许只是在模拟键鼠的输入,而不是真正的键鼠操作。
这时候我醒悟了。在网上冲浪一番后找到了这个说明
https://www.zhihu.com/question/68458175
在进入游戏后鼠标模式就会从 raw input 切换为 direct input 模式,所以这时候你即使用python改了你本机的鼠标坐标,也移动不了游戏视角的。
这个模式应该是DirectX那家公司创的,就是众所周知的DX9,DX11。而这些都是基于C语言和Windows环境。所以目前只知道能在windows中实现调用 direct mouse input,而 linux / mac 目前还未知。所以开发游戏脚本/强化学习算法,最好还是在windows上做。
调用方法就是楼下提到的 win32api 库,或者下文中的 ctypes 库,再或者是专门为控制游戏视角而开发的python库 pydirectinput 都可以,后两者本质也是调用 win32api。
pydirectinput
然后我立刻去试了这个库。
import time
import pydirectinput
while True:
pydirectinput.press('SPACE')
time.sleep(0.2)
确实可以了。
下面就是设定冲刺频率了。
冲刺频率
sleep尝试
首先我使用sleep函数。
但是很快就发现不太对劲,不管我调休眠多少时间都太慢了。
time观察
然后我用time察看了程序运行时间。
import time
import pydirectinput
while True:
t0=time.time()
pydirectinput.press('SPACE')
print(time.time()-t0)
结果是0.32秒左右按键一次。
然后我测试了在游戏中达到连续冲刺实际需要的按键间隔。
这里使用了keyboard.hook来监听键盘事件。
import keyboard
import time
keyboard.hook(lambda e: print(e, time.time()))
可以看到按下space的间隔大约是0.22秒左右。
这就很尴尬了。需要的时间间隔比程序可以做到的最少时间间隔整整多了0.1秒。
起初我以为是电脑配置的问题,程序运行得不够快。
但是后来我发现,pydirectinput库的函数是自带暂停休眠的!
https://www.likecs.com/ask-672805.html
还多亏了上面这位。
pause解决
然后我多加了一句代码。
import time
import pydirectinput
while True:
t0=time.time()
pydirectinput.press('SPACE')
pydirectinput.PAUSE=0.03
print(time.time()-t0)
输出是这个样子:
由于太快了所以把pause时间改成0.14秒,这样正好就是0.22秒。
但是我进入游戏界面还是一抖一抖冲刺很慢。
然后我试着改成了0.08秒,结果非常成功。
可能是玩游戏的时候占用了CPU,程序在后台运行会变慢吧。
以下是最终解决方案。
解决方案
import keyboard
import time
import pydirectinput
#需要提前安装pydirectinput库,使用pip即可
while True:
pydirectinput.press('SPACE')
pydirectinput.PAUSE=0.08
#可能每个人电脑配置不一样,不行的话试试修改数值)
改成键鼠操作,运行然后进入游戏界面即可。
参考资料
- directinput科普:https://www.zhihu.com/question/68458175
- pydirectinput库介绍:https://blog.csdn.net/lylelo/article/details/119882006
- PUASE问题解决:https://www.likecs.com/ask-672805.html
- keyboard库介绍:https://blog.csdn.net/weixin_39614322/article/details/111431131