键盘按键从 pyautogui 迁移到 pydirectinput
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -156,7 +156,7 @@ class AutoBotMove:
|
|||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
|
|
||||||
# 每次攻击前选中目标
|
# 每次攻击前选中目标
|
||||||
pydirectinput.press(KEY_LOOT)
|
# pydirectinput.press(KEY_LOOT)
|
||||||
for step in cfg['steps']:
|
for step in cfg['steps']:
|
||||||
key = step.get('key') or KEY_ATTACK
|
key = step.get('key') or KEY_ATTACK
|
||||||
delay = float(step.get('delay', 0.5))
|
delay = float(step.get('delay', 0.5))
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
import pyautogui
|
import pyautogui
|
||||||
|
import pydirectinput
|
||||||
from config import GameConfig
|
from config import GameConfig
|
||||||
from text_finder import TextFinder
|
from text_finder import TextFinder
|
||||||
from combat_detector import CombatDetector
|
from combat_detector import CombatDetector
|
||||||
@@ -41,10 +42,10 @@ class CombatEngine:
|
|||||||
"""在屏幕上寻找怪物目标"""
|
"""在屏幕上寻找怪物目标"""
|
||||||
try:
|
try:
|
||||||
# 先按3键
|
# 先按3键
|
||||||
pyautogui.press('3')
|
pydirectinput.press('3')
|
||||||
# 等待一段时间,确保画面更新
|
# 等待一段时间,确保画面更新
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
pyautogui.press('4')
|
pydirectinput.press('4')
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
if self.combat_detector.is_in_combat():
|
if self.combat_detector.is_in_combat():
|
||||||
return True
|
return True
|
||||||
@@ -61,15 +62,15 @@ class CombatEngine:
|
|||||||
|
|
||||||
if(self.combat_detector.is_in_combat()):
|
if(self.combat_detector.is_in_combat()):
|
||||||
while(self.combat_detector.is_in_combat()):
|
while(self.combat_detector.is_in_combat()):
|
||||||
pyautogui.press('2')
|
pydirectinput.press('2')
|
||||||
# time.sleep(1)
|
# time.sleep(1)
|
||||||
pyautogui.press('4')
|
pydirectinput.press('4')
|
||||||
else:
|
else:
|
||||||
# time.sleep(1)
|
# time.sleep(1)
|
||||||
# 怪物死亡,按4键拾取物品
|
# 怪物死亡,按4键拾取物品
|
||||||
pyautogui.press('4')
|
pydirectinput.press('4')
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
pyautogui.press('4')
|
pydirectinput.press('4')
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise RuntimeError(f"攻击执行失败: {str(e)}")
|
raise RuntimeError(f"攻击执行失败: {str(e)}")
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import math
|
|||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
import pyautogui
|
import pydirectinput
|
||||||
from stuck_handler import StuckHandler
|
from stuck_handler import StuckHandler
|
||||||
|
|
||||||
# 转向与死区常量(度)
|
# 转向与死区常量(度)
|
||||||
@@ -73,9 +73,9 @@ class CoordinatePatrol:
|
|||||||
self.logger.info(
|
self.logger.info(
|
||||||
f">>> 未上马,先按 {self.mount_key} {self.mount_hold_sec:.1f}s 上马"
|
f">>> 未上马,先按 {self.mount_key} {self.mount_hold_sec:.1f}s 上马"
|
||||||
)
|
)
|
||||||
pyautogui.keyDown(self.mount_key)
|
pydirectinput.keyDown(self.mount_key)
|
||||||
time.sleep(self.mount_hold_sec)
|
time.sleep(self.mount_hold_sec)
|
||||||
pyautogui.keyUp(self.mount_key)
|
pydirectinput.keyUp(self.mount_key)
|
||||||
self._next_mount_allowed = time.time() + self.mount_retry_after_sec
|
self._next_mount_allowed = time.time() + self.mount_retry_after_sec
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -235,16 +235,16 @@ class CoordinatePatrol:
|
|||||||
# --- [平滑移动核心:边走边转控制层] ---
|
# --- [平滑移动核心:边走边转控制层] ---
|
||||||
|
|
||||||
# A. 始终保持前进动力
|
# A. 始终保持前进动力
|
||||||
pyautogui.keyDown("w")
|
pydirectinput.keyDown("w")
|
||||||
|
|
||||||
# B. 转向决策逻辑
|
# B. 转向决策逻辑
|
||||||
if abs_diff <= self.angle_deadzone_deg:
|
if abs_diff <= self.angle_deadzone_deg:
|
||||||
if random.random() < self.random_jump_prob: # 频率建议设低,约每 200 帧跳一次
|
if random.random() < self.random_jump_prob: # 频率建议设低,约每 200 帧跳一次
|
||||||
self.logger.info(">>> 随机跳跃:模拟真人并辅助脱困")
|
self.logger.info(">>> 随机跳跃:模拟真人并辅助脱困")
|
||||||
pyautogui.press("space")
|
pydirectinput.press("space")
|
||||||
# 在死区内:绝对直线行驶,松开所有转向键
|
# 在死区内:绝对直线行驶,松开所有转向键
|
||||||
pyautogui.keyUp("a")
|
pydirectinput.keyUp("a")
|
||||||
pyautogui.keyUp("d")
|
pydirectinput.keyUp("d")
|
||||||
|
|
||||||
elif abs_diff > self.angle_threshold_deg:
|
elif abs_diff > self.angle_threshold_deg:
|
||||||
# 超出阈值:执行平滑脉冲转向
|
# 超出阈值:执行平滑脉冲转向
|
||||||
@@ -252,24 +252,24 @@ class CoordinatePatrol:
|
|||||||
other_key = "a" if angle_diff > 0 else "d"
|
other_key = "a" if angle_diff > 0 else "d"
|
||||||
|
|
||||||
# 确保不会同时按下左右键
|
# 确保不会同时按下左右键
|
||||||
pyautogui.keyUp(other_key)
|
pydirectinput.keyUp(other_key)
|
||||||
|
|
||||||
# 获取针对平滑移动优化的短脉冲时长
|
# 获取针对平滑移动优化的短脉冲时长
|
||||||
duration = self._turn_duration_from_angle(abs_diff)
|
duration = self._turn_duration_from_angle(abs_diff)
|
||||||
|
|
||||||
# 关键:执行短促转向脉冲
|
# 关键:执行短促转向脉冲
|
||||||
pyautogui.keyDown(turn_key)
|
pydirectinput.keyDown(turn_key)
|
||||||
# 这里的 sleep 极短 (建议 < 0.1s),不会造成移动卡顿
|
# 这里的 sleep 极短 (建议 < 0.1s),不会造成移动卡顿
|
||||||
time.sleep(duration)
|
time.sleep(duration)
|
||||||
pyautogui.keyUp(turn_key)
|
pydirectinput.keyUp(turn_key)
|
||||||
|
|
||||||
self.last_turn_end_time = time.time()
|
self.last_turn_end_time = time.time()
|
||||||
# self.logger.debug(f"修正航向: {turn_key} | 角度差: {angle_diff:.1f}°")
|
# self.logger.debug(f"修正航向: {turn_key} | 角度差: {angle_diff:.1f}°")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# 在死区与阈值之间:为了平滑,不进行任何按键动作,仅靠 W 前进
|
# 在死区与阈值之间:为了平滑,不进行任何按键动作,仅靠 W 前进
|
||||||
pyautogui.keyUp("a")
|
pydirectinput.keyUp("a")
|
||||||
pyautogui.keyUp("d")
|
pydirectinput.keyUp("d")
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -306,8 +306,8 @@ class CoordinatePatrol:
|
|||||||
if dist < threshold:
|
if dist < threshold:
|
||||||
# 到点后保持平滑过渡:不松开 W,只松开左右修正键
|
# 到点后保持平滑过渡:不松开 W,只松开左右修正键
|
||||||
# 避免 patrol 连续多点时出现“刹一下再走”的抖动。
|
# 避免 patrol 连续多点时出现“刹一下再走”的抖动。
|
||||||
pyautogui.keyUp("a")
|
pydirectinput.keyUp("a")
|
||||||
pyautogui.keyUp("d")
|
pydirectinput.keyUp("d")
|
||||||
self.reset_stuck()
|
self.reset_stuck()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -319,37 +319,37 @@ class CoordinatePatrol:
|
|||||||
# --- 平滑移动核心逻辑 ---
|
# --- 平滑移动核心逻辑 ---
|
||||||
|
|
||||||
# 只要没到终点,始终保持前进 W 键按下
|
# 只要没到终点,始终保持前进 W 键按下
|
||||||
pyautogui.keyDown("w")
|
pydirectinput.keyDown("w")
|
||||||
|
|
||||||
# 4. 根据偏角决定转向动作
|
# 4. 根据偏角决定转向动作
|
||||||
if abs_diff <= self.angle_deadzone_deg:
|
if abs_diff <= self.angle_deadzone_deg:
|
||||||
if random.random() < self.random_jump_prob: # 频率建议设低,约每 200 帧跳一次
|
if random.random() < self.random_jump_prob: # 频率建议设低,约每 200 帧跳一次
|
||||||
self.logger.info(">>> 随机跳跃:模拟真人并辅助脱困")
|
self.logger.info(">>> 随机跳跃:模拟真人并辅助脱困")
|
||||||
pyautogui.press("space")
|
pydirectinput.press("space")
|
||||||
# 在死区内,确保转向键松开,直线前进
|
# 在死区内,确保转向键松开,直线前进
|
||||||
pyautogui.keyUp("a")
|
pydirectinput.keyUp("a")
|
||||||
pyautogui.keyUp("d")
|
pydirectinput.keyUp("d")
|
||||||
elif abs_diff > self.angle_threshold_deg:
|
elif abs_diff > self.angle_threshold_deg:
|
||||||
# 超出阈值:执行平滑脉冲转向
|
# 超出阈值:执行平滑脉冲转向
|
||||||
turn_key = "d" if angle_diff > 0 else "a"
|
turn_key = "d" if angle_diff > 0 else "a"
|
||||||
other_key = "a" if angle_diff > 0 else "d"
|
other_key = "a" if angle_diff > 0 else "d"
|
||||||
|
|
||||||
# 松开反方向键
|
# 松开反方向键
|
||||||
pyautogui.keyUp(other_key)
|
pydirectinput.keyUp(other_key)
|
||||||
|
|
||||||
# 获取针对平滑移动优化的短脉冲时长
|
# 获取针对平滑移动优化的短脉冲时长
|
||||||
duration = self._turn_duration_from_angle(abs_diff)
|
duration = self._turn_duration_from_angle(abs_diff)
|
||||||
# 关键:执行短促转向脉冲
|
# 关键:执行短促转向脉冲
|
||||||
pyautogui.keyDown(turn_key)
|
pydirectinput.keyDown(turn_key)
|
||||||
# sleep 极短 (建议 < 0.1s),不会造成移动卡顿
|
# sleep 极短 (建议 < 0.1s),不会造成移动卡顿
|
||||||
time.sleep(duration)
|
time.sleep(duration)
|
||||||
pyautogui.keyUp(turn_key)
|
pydirectinput.keyUp(turn_key)
|
||||||
|
|
||||||
self.last_turn_end_time = time.time()
|
self.last_turn_end_time = time.time()
|
||||||
else:
|
else:
|
||||||
# 在死区与阈值之间:为了平滑,不进行任何按键动作,仅靠 W 前进
|
# 在死区与阈值之间:为了平滑,不进行任何按键动作,仅靠 W 前进
|
||||||
pyautogui.keyUp("a")
|
pydirectinput.keyUp("a")
|
||||||
pyautogui.keyUp("d")
|
pydirectinput.keyUp("d")
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -405,9 +405,9 @@ class CoordinatePatrol:
|
|||||||
ok = self._ensure_mounted(state)
|
ok = self._ensure_mounted(state)
|
||||||
if not ok:
|
if not ok:
|
||||||
return False
|
return False
|
||||||
pyautogui.keyDown(str(takeoff_key))
|
pydirectinput.keyDown(str(takeoff_key))
|
||||||
time.sleep(float(takeoff_hold_sec))
|
time.sleep(float(takeoff_hold_sec))
|
||||||
pyautogui.keyUp(str(takeoff_key))
|
pydirectinput.keyUp(str(takeoff_key))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# 计算距离
|
# 计算距离
|
||||||
@@ -419,23 +419,23 @@ class CoordinatePatrol:
|
|||||||
if f_signal < 10:
|
if f_signal < 10:
|
||||||
# 退化:直接按 mount_key 一次并等待
|
# 退化:直接按 mount_key 一次并等待
|
||||||
self.logger.info(">>> 飞行阶段检测:未上马,先按 %s", self.mount_key)
|
self.logger.info(">>> 飞行阶段检测:未上马,先按 %s", self.mount_key)
|
||||||
pyautogui.press(self.mount_key)
|
pydirectinput.press(self.mount_key)
|
||||||
time.sleep(float(mount_wait_sec))
|
time.sleep(float(mount_wait_sec))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# --- 2. 起飞阶段(兼容你的阈值写法:100~200) ---
|
# --- 2. 起飞阶段(兼容你的阈值写法:100~200) ---
|
||||||
if 100 < f_signal < 200:
|
if 100 < f_signal < 200:
|
||||||
self.logger.info(">>> 起飞:按住 %s %.1f 秒", takeoff_key, float(takeoff_hold_sec))
|
self.logger.info(">>> 起飞:按住 %s %.1f 秒", takeoff_key, float(takeoff_hold_sec))
|
||||||
pyautogui.keyDown(str(takeoff_key))
|
pydirectinput.keyDown(str(takeoff_key))
|
||||||
time.sleep(float(takeoff_hold_sec))
|
time.sleep(float(takeoff_hold_sec))
|
||||||
pyautogui.keyUp(str(takeoff_key))
|
pydirectinput.keyUp(str(takeoff_key))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# --- 3. 巡航与降落判定(兼容你的阈值写法:>240) ---
|
# --- 3. 巡航与降落判定(兼容你的阈值写法:>240) ---
|
||||||
if f_signal > 240:
|
if f_signal > 240:
|
||||||
if dist > float(arrival_threshold):
|
if dist > float(arrival_threshold):
|
||||||
# A. 始终按住 W 前进
|
# A. 始终按住 W 前进
|
||||||
pyautogui.keyDown("w")
|
pydirectinput.keyDown("w")
|
||||||
|
|
||||||
# B. 修正方向(使用与本模块一致的朝向计算)
|
# B. 修正方向(使用与本模块一致的朝向计算)
|
||||||
target_heading = self.get_target_heading_deg((float(curr_x), float(curr_y)), (float(target_x), float(target_y)))
|
target_heading = self.get_target_heading_deg((float(curr_x), float(curr_y)), (float(target_x), float(target_y)))
|
||||||
@@ -444,8 +444,8 @@ class CoordinatePatrol:
|
|||||||
|
|
||||||
# 在死区内:确保转向键松开,减少左右抖动
|
# 在死区内:确保转向键松开,减少左右抖动
|
||||||
if abs_diff <= float(turn_deadzone_deg):
|
if abs_diff <= float(turn_deadzone_deg):
|
||||||
pyautogui.keyUp("a")
|
pydirectinput.keyUp("a")
|
||||||
pyautogui.keyUp("d")
|
pydirectinput.keyUp("d")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# 防止“上一个修正刚结束,下一帧立刻反向再修正”造成摆头
|
# 防止“上一个修正刚结束,下一帧立刻反向再修正”造成摆头
|
||||||
@@ -456,8 +456,8 @@ class CoordinatePatrol:
|
|||||||
|
|
||||||
key = "d" if angle_diff > 0 else "a"
|
key = "d" if angle_diff > 0 else "a"
|
||||||
other_key = "a" if key == "d" else "d"
|
other_key = "a" if key == "d" else "d"
|
||||||
pyautogui.keyUp(other_key)
|
pydirectinput.keyUp(other_key)
|
||||||
pyautogui.keyDown(key)
|
pydirectinput.keyDown(key)
|
||||||
|
|
||||||
# 修正脉冲时长随角度误差变化,避免固定 0.05s 过冲/欠冲
|
# 修正脉冲时长随角度误差变化,避免固定 0.05s 过冲/欠冲
|
||||||
duration = self._turn_duration_from_angle(abs_diff)
|
duration = self._turn_duration_from_angle(abs_diff)
|
||||||
@@ -467,17 +467,17 @@ class CoordinatePatrol:
|
|||||||
safe_duration = min(safe_duration, 0.04)
|
safe_duration = min(safe_duration, 0.04)
|
||||||
|
|
||||||
time.sleep(safe_duration)
|
time.sleep(safe_duration)
|
||||||
pyautogui.keyUp(key)
|
pydirectinput.keyUp(key)
|
||||||
setattr(self, "_last_simple_flight_turn_time", now)
|
setattr(self, "_last_simple_flight_turn_time", now)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# C. 到达目标,执行降落
|
# C. 到达目标,执行降落
|
||||||
pyautogui.keyUp("w")
|
pydirectinput.keyUp("w")
|
||||||
self.logger.info(">>> 到达目标,执行降落:按住 %s %.1f 秒", land_key, float(land_hold_sec))
|
self.logger.info(">>> 到达目标,执行降落:按住 %s %.1f 秒", land_key, float(land_hold_sec))
|
||||||
pyautogui.keyDown(str(land_key))
|
pydirectinput.keyDown(str(land_key))
|
||||||
time.sleep(float(land_hold_sec))
|
time.sleep(float(land_hold_sec))
|
||||||
pyautogui.keyUp(str(land_key))
|
pydirectinput.keyUp(str(land_key))
|
||||||
pyautogui.press(dismount_key)
|
pydirectinput.press(dismount_key)
|
||||||
self.logger.info(">>> 降落完成:已按 %s", dismount_key)
|
self.logger.info(">>> 降落完成:已按 %s", dismount_key)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -532,10 +532,10 @@ class CoordinatePatrol:
|
|||||||
"""只按下指定键,抬起其他移动键。"""
|
"""只按下指定键,抬起其他移动键。"""
|
||||||
for k in ("w", "a", "d"):
|
for k in ("w", "a", "d"):
|
||||||
if k == key:
|
if k == key:
|
||||||
pyautogui.keyDown(k)
|
pydirectinput.keyDown(k)
|
||||||
else:
|
else:
|
||||||
pyautogui.keyUp(k)
|
pydirectinput.keyUp(k)
|
||||||
|
|
||||||
def stop_all(self):
|
def stop_all(self):
|
||||||
for key in ["w", "a", "s", "d"]:
|
for key in ["w", "a", "s", "d"]:
|
||||||
pyautogui.keyUp(key)
|
pydirectinput.keyUp(key)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import time
|
import time
|
||||||
import math
|
import math
|
||||||
import pyautogui
|
import pydirectinput
|
||||||
|
|
||||||
|
|
||||||
class DeathManager:
|
class DeathManager:
|
||||||
@@ -24,7 +24,7 @@ class DeathManager:
|
|||||||
self.corpse_pos = (state['x'], state['y'])
|
self.corpse_pos = (state['x'], state['y'])
|
||||||
self.is_running_to_corpse = True
|
self.is_running_to_corpse = True
|
||||||
print(f">>> [系统] 记录死亡坐标: {self.corpse_pos},准备释放灵魂...")
|
print(f">>> [系统] 记录死亡坐标: {self.corpse_pos},准备释放灵魂...")
|
||||||
pyautogui.press('9') # 绑定宏: /run RepopMe()
|
pydirectinput.press('9') # 绑定宏: /run RepopMe()
|
||||||
time.sleep(5) # 等待加载界面
|
time.sleep(5) # 等待加载界面
|
||||||
|
|
||||||
def run_to_corpse(self, state):
|
def run_to_corpse(self, state):
|
||||||
@@ -36,7 +36,7 @@ class DeathManager:
|
|||||||
# 如果距离尸体很近(0.005 约等于 10-20 码)
|
# 如果距离尸体很近(0.005 约等于 10-20 码)
|
||||||
if is_arrived:
|
if is_arrived:
|
||||||
print(">>> 已到达尸体附近,尝试复活...")
|
print(">>> 已到达尸体附近,尝试复活...")
|
||||||
pyautogui.press('0') # 绑定宏: /run RetrieveCorpse()
|
pydirectinput.press('0') # 绑定宏: /run RetrieveCorpse()
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
self.is_running_to_corpse = False
|
self.is_running_to_corpse = False
|
||||||
self.corpse_pos = None
|
self.corpse_pos = None
|
||||||
|
|||||||
@@ -59,3 +59,8 @@
|
|||||||
|
|
||||||
- **轮询间隔**:`coordinate_patrol.py` 的 `navigate_path` 阻塞等待轮询由固定 `time.sleep(0.05)` 调整为局部 `poll_sleep_sec = 0.02`,让阻塞模式控制频率更接近 `navigate`,减少航点/转向后的抖动。
|
- **轮询间隔**:`coordinate_patrol.py` 的 `navigate_path` 阻塞等待轮询由固定 `time.sleep(0.05)` 调整为局部 `poll_sleep_sec = 0.02`,让阻塞模式控制频率更接近 `navigate`,减少航点/转向后的抖动。
|
||||||
|
|
||||||
|
### 键盘按键从 `pyautogui` 迁移到 `pydirectinput`
|
||||||
|
|
||||||
|
- 将项目中所有键盘按键调用(`pyautogui.keyDown/keyUp/press`)替换为对应的 `pydirectinput.keyDown/keyUp/press`
|
||||||
|
- 涉及文件:`coordinate_patrol.py`、`stuck_handler.py`、`death_manager.py`、`player_movement.py`、`combat_engine.py`
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import math
|
import math
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
import pyautogui
|
import pydirectinput
|
||||||
from player_position import PlayerPosition
|
from player_position import PlayerPosition
|
||||||
|
|
||||||
# 游戏朝向约定:正北=0°,正西=90°,正南=180°,正东=270°(逆时针递增)
|
# 游戏朝向约定:正北=0°,正西=90°,正南=180°,正东=270°(逆时针递增)
|
||||||
@@ -81,9 +81,9 @@ class PlayerMovement:
|
|||||||
f"[转向 {attempt + 1}] 当前 {current_heading:.1f}° → 目标 {target_heading:.1f}°,"
|
f"[转向 {attempt + 1}] 当前 {current_heading:.1f}° → 目标 {target_heading:.1f}°,"
|
||||||
f"按 '{key}' {turn_duration:.2f}s(需转 {angle_to_turn:.1f}°)"
|
f"按 '{key}' {turn_duration:.2f}s(需转 {angle_to_turn:.1f}°)"
|
||||||
)
|
)
|
||||||
pyautogui.keyDown(key)
|
pydirectinput.keyDown(key)
|
||||||
time.sleep(turn_duration)
|
time.sleep(turn_duration)
|
||||||
pyautogui.keyUp(key)
|
pydirectinput.keyUp(key)
|
||||||
time.sleep(0.15) # 等待游戏刷新朝向
|
time.sleep(0.15) # 等待游戏刷新朝向
|
||||||
|
|
||||||
self.logger.warning(f"转向失败:超过最大尝试次数 {max_attempts}")
|
self.logger.warning(f"转向失败:超过最大尝试次数 {max_attempts}")
|
||||||
@@ -96,9 +96,9 @@ class PlayerMovement:
|
|||||||
duration: 移动时间(秒)
|
duration: 移动时间(秒)
|
||||||
"""
|
"""
|
||||||
self.logger.info(f"向前移动 {duration:.2f}s")
|
self.logger.info(f"向前移动 {duration:.2f}s")
|
||||||
pyautogui.keyDown('w')
|
pydirectinput.keyDown('w')
|
||||||
time.sleep(duration)
|
time.sleep(duration)
|
||||||
pyautogui.keyUp('w')
|
pydirectinput.keyUp('w')
|
||||||
|
|
||||||
def _escape_stuck(self):
|
def _escape_stuck(self):
|
||||||
"""卡死脱困组合拳:后退 + 随机转向 + 跳跃。
|
"""卡死脱困组合拳:后退 + 随机转向 + 跳跃。
|
||||||
@@ -109,23 +109,23 @@ class PlayerMovement:
|
|||||||
self.logger.warning("检测到角色卡死,执行脱困动作")
|
self.logger.warning("检测到角色卡死,执行脱困动作")
|
||||||
|
|
||||||
# 1. 松开前进键,后退 0.8s
|
# 1. 松开前进键,后退 0.8s
|
||||||
pyautogui.keyUp('w')
|
pydirectinput.keyUp('w')
|
||||||
pyautogui.keyDown('s')
|
pydirectinput.keyDown('s')
|
||||||
time.sleep(0.8)
|
time.sleep(0.8)
|
||||||
pyautogui.keyUp('s')
|
pydirectinput.keyUp('s')
|
||||||
|
|
||||||
# 2. 随机左转或右转 0.3~0.5s
|
# 2. 随机左转或右转 0.3~0.5s
|
||||||
turn_key = random.choice(['a', 'd'])
|
turn_key = random.choice(['a', 'd'])
|
||||||
turn_dur = random.uniform(0.3, 0.5)
|
turn_dur = random.uniform(0.3, 0.5)
|
||||||
pyautogui.keyDown(turn_key)
|
pydirectinput.keyDown(turn_key)
|
||||||
time.sleep(turn_dur)
|
time.sleep(turn_dur)
|
||||||
pyautogui.keyUp(turn_key)
|
pydirectinput.keyUp(turn_key)
|
||||||
|
|
||||||
# 3. 跳跃(按空格)同时向前冲 0.5s
|
# 3. 跳跃(按空格)同时向前冲 0.5s
|
||||||
pyautogui.keyDown('w')
|
pydirectinput.keyDown('w')
|
||||||
pyautogui.press('space')
|
pydirectinput.press('space')
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
pyautogui.keyUp('w')
|
pydirectinput.keyUp('w')
|
||||||
|
|
||||||
self.logger.info("脱困动作完成,重新开始前进")
|
self.logger.info("脱困动作完成,重新开始前进")
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ class PlayerMovement:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# 按住 w 开始持续前进
|
# 按住 w 开始持续前进
|
||||||
pyautogui.keyDown('w')
|
pydirectinput.keyDown('w')
|
||||||
# 卡死检测:记录最近 STUCK_CHECK_COUNT 次坐标,用于判断是否停滞
|
# 卡死检测:记录最近 STUCK_CHECK_COUNT 次坐标,用于判断是否停滞
|
||||||
recent_positions = []
|
recent_positions = []
|
||||||
try:
|
try:
|
||||||
@@ -204,7 +204,7 @@ class PlayerMovement:
|
|||||||
if moved < self.STUCK_MOVE_THRESHOLD:
|
if moved < self.STUCK_MOVE_THRESHOLD:
|
||||||
self._escape_stuck()
|
self._escape_stuck()
|
||||||
recent_positions.clear()
|
recent_positions.clear()
|
||||||
pyautogui.keyDown('w')
|
pydirectinput.keyDown('w')
|
||||||
|
|
||||||
# x 和 y 都在容差范围内即视为到达
|
# x 和 y 都在容差范围内即视为到达
|
||||||
if abs(dx) <= position_tolerance and abs(dy) <= position_tolerance:
|
if abs(dx) <= position_tolerance and abs(dy) <= position_tolerance:
|
||||||
@@ -213,7 +213,7 @@ class PlayerMovement:
|
|||||||
|
|
||||||
# 接近目标时松开 w 停下,再做一次静止判定,避免冲过头后死循环
|
# 接近目标时松开 w 停下,再做一次静止判定,避免冲过头后死循环
|
||||||
if distance <= position_tolerance * 2:
|
if distance <= position_tolerance * 2:
|
||||||
pyautogui.keyUp('w')
|
pydirectinput.keyUp('w')
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
final_pos = self.player_position.get_position_with_retry()
|
final_pos = self.player_position.get_position_with_retry()
|
||||||
if final_pos is not None:
|
if final_pos is not None:
|
||||||
@@ -223,7 +223,7 @@ class PlayerMovement:
|
|||||||
self.logger.info(f"已到达目标位置 ({target_x}, {target_y})")
|
self.logger.info(f"已到达目标位置 ({target_x}, {target_y})")
|
||||||
return True
|
return True
|
||||||
# 静止后仍未到达,重新按住 w 继续前进
|
# 静止后仍未到达,重新按住 w 继续前进
|
||||||
pyautogui.keyDown('w')
|
pydirectinput.keyDown('w')
|
||||||
|
|
||||||
# 每隔 HEADING_CHECK_INTERVAL 次读一次朝向,减少 OCR 频率
|
# 每隔 HEADING_CHECK_INTERVAL 次读一次朝向,减少 OCR 频率
|
||||||
if iteration % self.HEADING_CHECK_INTERVAL != 0:
|
if iteration % self.HEADING_CHECK_INTERVAL != 0:
|
||||||
@@ -239,12 +239,12 @@ class PlayerMovement:
|
|||||||
|
|
||||||
if abs_diff > self.COARSE_TURN_THRESHOLD:
|
if abs_diff > self.COARSE_TURN_THRESHOLD:
|
||||||
# 偏差过大:停步原地粗修正,再重新按住 w
|
# 偏差过大:停步原地粗修正,再重新按住 w
|
||||||
pyautogui.keyUp('w')
|
pydirectinput.keyUp('w')
|
||||||
self.logger.info(f"偏差 {abs_diff:.1f}° 过大,停步原地修正")
|
self.logger.info(f"偏差 {abs_diff:.1f}° 过大,停步原地修正")
|
||||||
if not self.turn_to_heading(required_heading):
|
if not self.turn_to_heading(required_heading):
|
||||||
self.logger.warning("修正转向失败,移动中止")
|
self.logger.warning("修正转向失败,移动中止")
|
||||||
return False
|
return False
|
||||||
pyautogui.keyDown('w')
|
pydirectinput.keyDown('w')
|
||||||
|
|
||||||
elif abs_diff > self.ANGLE_TOLERANCE:
|
elif abs_diff > self.ANGLE_TOLERANCE:
|
||||||
# 小幅偏差:边走边转,同时按住 w 和转向键
|
# 小幅偏差:边走边转,同时按住 w 和转向键
|
||||||
@@ -254,15 +254,15 @@ class PlayerMovement:
|
|||||||
self.logger.info(
|
self.logger.info(
|
||||||
f"边走边转:按 '{turn_key}' {turn_time:.2f}s(偏差 {abs_diff:.1f}°)"
|
f"边走边转:按 '{turn_key}' {turn_time:.2f}s(偏差 {abs_diff:.1f}°)"
|
||||||
)
|
)
|
||||||
pyautogui.keyDown(turn_key)
|
pydirectinput.keyDown(turn_key)
|
||||||
time.sleep(turn_time)
|
time.sleep(turn_time)
|
||||||
pyautogui.keyUp(turn_key)
|
pydirectinput.keyUp(turn_key)
|
||||||
else:
|
else:
|
||||||
# 方向已对齐,让角色多走一段再重新检测,减少 OCR 频率
|
# 方向已对齐,让角色多走一段再重新检测,减少 OCR 频率
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
pyautogui.keyUp('w')
|
pydirectinput.keyUp('w')
|
||||||
|
|
||||||
self.logger.warning(f"移动失败:超过最大迭代次数 {max_iterations}")
|
self.logger.warning(f"移动失败:超过最大迭代次数 {max_iterations}")
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import math
|
import math
|
||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
import pyautogui
|
import pydirectinput
|
||||||
|
|
||||||
class StuckHandler:
|
class StuckHandler:
|
||||||
# 针对 0.xxxx 坐标系优化
|
# 针对 0.xxxx 坐标系优化
|
||||||
@@ -61,27 +61,27 @@ class StuckHandler:
|
|||||||
|
|
||||||
# 1. 全停
|
# 1. 全停
|
||||||
for k in ("w", "a", "d", "s"):
|
for k in ("w", "a", "d", "s"):
|
||||||
pyautogui.keyUp(k)
|
pydirectinput.keyUp(k)
|
||||||
|
|
||||||
# 2. 倒车并转向(组合动作更有效)
|
# 2. 倒车并转向(组合动作更有效)
|
||||||
pyautogui.keyDown("s")
|
pydirectinput.keyDown("s")
|
||||||
turn_key = random.choice(["a", "d"])
|
turn_key = random.choice(["a", "d"])
|
||||||
pyautogui.keyDown(turn_key)
|
pydirectinput.keyDown(turn_key)
|
||||||
|
|
||||||
# 倒车时间稍长一点,离开障碍物
|
# 倒车时间稍长一点,离开障碍物
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
||||||
# 3. 尝试跳跃脱离地形卡位
|
# 3. 尝试跳跃脱离地形卡位
|
||||||
pyautogui.press("space")
|
pydirectinput.press("space")
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
||||||
pyautogui.keyUp(turn_key)
|
pydirectinput.keyUp(turn_key)
|
||||||
pyautogui.keyUp("s")
|
pydirectinput.keyUp("s")
|
||||||
|
|
||||||
# 4. 往前稍微走一步,重新锁定坐标
|
# 4. 往前稍微走一步,重新锁定坐标
|
||||||
pyautogui.keyDown("w")
|
pydirectinput.keyDown("w")
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
pyautogui.keyUp("w")
|
pydirectinput.keyUp("w")
|
||||||
|
|
||||||
self.reset()
|
self.reset()
|
||||||
print(">>> 脱困尝试结束")
|
print(">>> 脱困尝试结束")
|
||||||
|
|||||||
Reference in New Issue
Block a user