# movement_parity_test.gd —— 验证角色与怪物移动对齐 40250 的实现机制: # 1. PlayerController 转向 45° 阻尼减速(5/12)与 ARRIVE_EPS 到达精度。 # 2. PlayerController 遇障碍物切线滑动判定。 # 3. EntityStore 网络命令队列 EMA 滤波与动作速度 fallback。 # 4. NetWorld 远端实体朝向收敛 45° 阻尼。 # # godot --headless --path project --script movement_parity_test.gd extends SceneTree const PlayerController = preload("res://player_controller.gd") const NetWorld = preload("res://net_world.gd") const MobView = preload("res://ui/mob_view.gd") var _fail := 0 func _ck(c: bool, m: String) -> void: if not c: _fail += 1 printerr("FAIL: " + m) func _init() -> void: _run() if _fail == 0: print("PASS: movement_parity_test (40250 rotation damping + arrival epsilon + collision tangent + EMA network gap)") quit(0) else: printerr("%d check(s) failed" % _fail) quit(1) func _run() -> void: # ========================================================================= # 1. PlayerController: 转向 45° 阻尼减速测试 (40250 InstanceBaseMovement.cpp:142-154) # ========================================================================= var pc := PlayerController.new() var player := Node3D.new() get_root().add_child(player) get_root().add_child(pc) pc.player = player pc.rotation_speed_deg = 1200.0 # 角度差 > 45° 时(例如 90° = PI/2):转向速度应为全速 1200°/s player.rotation.y = 0.0 var target_90 := deg_to_rad(90.0) pc._turn_toward(target_90, 0.01) # dt = 10ms -> 预期前进 12° var turned_90: float = rad_to_deg(player.rotation.y) _ck(is_equal_approx(turned_90, 12.0), "Over 45 deg: full speed 1200 deg/s (turned %.2f, expected 12.0)" % turned_90) # 角度差 <= 45° 时(例如 30°):转向速度应降为 5/12(500°/s) player.rotation.y = 0.0 var target_30 := deg_to_rad(30.0) pc._turn_toward(target_30, 0.01) # dt = 10ms -> 预期前进 5° (12 * 5/12 = 5) var turned_30: float = rad_to_deg(player.rotation.y) _ck(is_equal_approx(turned_30, 5.0), "Under 45 deg: damped speed 500 deg/s (turned %.2f, expected 5.0)" % turned_30) # ========================================================================= # 2. PlayerController: ARRIVE_EPS 精准到达测试 (40250 InstanceBase.cpp:1600) # ========================================================================= _ck(pc.ARRIVE_EPS <= 0.05, "ARRIVE_EPS is <= 0.05 (got %f)" % pc.ARRIVE_EPS) player.position = Vector3(10.0, 0.0, 10.0) pc._goto(Vector3(12.0, 0.0, 10.0)) # 距离目标点 2m (> 1m MOVABLE_GROUND_DISTANCE_M) _ck(pc.is_going(), "_goto started (is_going == true)") # 模拟角色走到了距目标 3cm 处 player.position = Vector3(11.97, 0.0, 10.0) pc._process(0.016) _ck(not pc.is_going(), "Within ARRIVE_EPS (3cm <= 5cm) stops immediately (is_going == false)") _ck(is_equal_approx(player.position.x, 12.0), "Player position snapped to exact clicked target X") # ========================================================================= # 3. PlayerController: 切线滑动测试 (40250 AdjustDynamicCollisionMovement) # ========================================================================= var obstacle := Node3D.new() get_root().add_child(obstacle) # 障碍物放在 (11.0, 0, 10.0),半径 0.55m -> combined radius 1.1m obstacle.position = Vector3(11.0, 0.0, 10.0) obstacle.set_meta("kind", 0) pc.pickables.append(obstacle) player.position = Vector3(10.0, 0.0, 10.0) # 阻挡判定:朝向 (10.5, 0.0, 10.0) 会撞击障碍物(距离 0.5m < 1.1m 且更趋近) _ck(pc._actor_blocked(Vector3(10.5, 0.0, 10.0)), "Blocked when moving into obstacle body radius") _ck(pc._get_blocking_actor(Vector3(10.5, 0.0, 10.0)) == obstacle, "_get_blocking_actor returns obstacle") # ========================================================================= # 4. NetWorld: 远端实体朝向 45° 阻尼收敛验证 # ========================================================================= var nw := NetWorld.new() get_root().add_child(nw) var remote_node := Node3D.new() remote_node.rotation.y = 0.0 var target_yaw := deg_to_rad(30.0) var turn_rate := 1200.0 var diff: float = wrapf(target_yaw - remote_node.rotation.y, -PI, PI) if absf(diff) <= deg_to_rad(45.0): turn_rate *= 5.0 / 12.0 remote_node.rotation.y = rotate_toward(remote_node.rotation.y, target_yaw, deg_to_rad(turn_rate) * 0.01) var nw_turned: float = rad_to_deg(remote_node.rotation.y) _ck(is_equal_approx(nw_turned, 5.0), "NetWorld rotation damped within 45 deg: turned %.2f, expected 5.0" % nw_turned) # ========================================================================= # 5. M2Client / EntityStore: 单动作 speed fallback 与 EMA 滤波测试 # ========================================================================= if ClassDB.class_exists("M2Client"): var client = ClassDB.instantiate("M2Client") get_root().add_child(client) _ck(client.has_method("set_entity_motion_speed"), "M2Client has set_entity_motion_speed") client.call("set_entity_motion_speed", 12345, 0.0, 350.0) # 仅有 run 速度 client.queue_free() pc.queue_free() player.queue_free() obstacle.queue_free() remote_node.queue_free() nw.queue_free()