add 巡逻模式优先上马

This commit is contained in:
王鹏
2026-03-23 09:50:08 +08:00
parent be436b66a7
commit f517c29579
20 changed files with 233 additions and 6 deletions

View File

@@ -15,7 +15,6 @@ ANGLE_DEADZONE_DEG = 5.0 # 死区,此范围内不按 A/D、只按 W
# 随机行为跳跃概率每帧触发概率0.005 ≈ 平均 200 帧一次)
RANDOM_JUMP_PROB = 0.05
class CoordinatePatrol:
"""按航点坐标巡逻,用 pyautogui 按键转向与前进。"""
@@ -26,6 +25,9 @@ class CoordinatePatrol:
angle_threshold_deg=ANGLE_THRESHOLD_DEG,
angle_deadzone_deg=ANGLE_DEADZONE_DEG,
random_jump_prob=RANDOM_JUMP_PROB,
mount_key="x",
mount_hold_sec=1.6,
mount_retry_after_sec=2.0,
):
"""
Args:
@@ -33,6 +35,7 @@ class CoordinatePatrol:
arrival_threshold: 到达判定距离(游戏坐标单位),默认 0.5
angle_threshold_deg: 朝向容差(度),超过此值才按 A/D 转向,默认 ANGLE_THRESHOLD_DEG
angle_deadzone_deg: 转向死区(度),此范围内不按 A/D、只按 W默认 ANGLE_DEADZONE_DEG
mount_key / mount_hold_sec / mount_retry_after_sec: 未上马时先上马(与 game_state_config / GUI 一致)
"""
self.waypoints = waypoints
self.current_index = 0
@@ -43,6 +46,33 @@ class CoordinatePatrol:
self.logger = logging.getLogger(__name__)
self.last_turn_end_time = 0 # 最近一次结束 A/D 转向的时间,供卡死检测排除原地转向
self.stuck_handler = StuckHandler()
self._next_mount_allowed = 0.0
self.mount_key = str(mount_key).strip() or "x"
self.mount_hold_sec = float(mount_hold_sec)
self.mount_retry_after_sec = float(mount_retry_after_sec)
def _ensure_mounted(self, state):
"""
已上马返回 True。
未上马则松开移动键、按住上马键 MOUNT_HOLD_SEC本帧不走路返回 False。
state 无 mounted 字段时视为无法判断,不拦巡逻(兼容未开 LogicBeacon
"""
if "mounted" not in state:
return True
if state.get("mounted"):
return True
self.stop_all()
now = time.time()
if now < self._next_mount_allowed:
return False
self.logger.info(
f">>> 未上马,先按 {self.mount_key} {self.mount_hold_sec:.1f}s 上马"
)
pyautogui.keyDown(self.mount_key)
time.sleep(self.mount_hold_sec)
pyautogui.keyUp(self.mount_key)
self._next_mount_allowed = time.time() + self.mount_retry_after_sec
return False
@staticmethod
def get_distance(p1, p2):
@@ -168,6 +198,9 @@ class CoordinatePatrol:
self.stop_all()
return
if not self._ensure_mounted(state):
return
# 2. 卡死检测:位移检测逻辑保持在巡逻中
if self.stuck_handler.check_stuck(state, self.last_turn_end_time):
self.logger.error("!!! 检测到卡死,启动脱困程序 !!!")
@@ -250,6 +283,9 @@ class CoordinatePatrol:
self.stop_all()
return False
if not self._ensure_mounted(state):
return False
# 1. 卡死检测
if self.stuck_handler.check_stuck(state, self.last_turn_end_time):
self.stop_all()
@@ -311,6 +347,7 @@ class CoordinatePatrol:
"""
按 path 依次走完所有点后返回。每次调用都必须传入 path。
get_state: 可调用对象,每次调用返回当前状态 dict需包含 'x','y','facing'
若含 'mounted'LogicBeacon路径开始前会先上马每段 navigate_to_point 也会校验。
path: [[x,y], ...] 或 [(x,y), ...](如 json.load 得到),本次要走的全部航点。
forward: True=正序0→nFalse=倒序n→0
阻塞直到走完 path 中所有点或出错,走完返回 True。内含卡死检测。
@@ -321,6 +358,17 @@ class CoordinatePatrol:
points = [(float(p[0]), float(p[1])) for p in path]
if not forward:
points = points[::-1]
# 路径开始前:若 state 含 mounted 且未上马,先完成上马再逐点移动
while True:
state = get_state()
if state is None:
self.stop_all()
return False
if self._ensure_mounted(state):
break
time.sleep(0.05)
for i, target in enumerate(points):
self.logger.info(f">>> 路径点 {i + 1}/{len(points)}: {target}")
while True: