Files
mtgodot-poc/project/test_wasd_steering_parity.gd
T
shenandshen 66d217b313 feat(client): 完成40250客户端核心功能1:1对齐与桥梁高度采样修复
- 桥梁与静态物体高度采样修复:
  - 严格对齐 40250 CMapOutdoor::GetHeight 与 CAttributeInstance::GetHeight
  - 解析 .mdatr 中的 AttributeHeight 网格,使用 is_in_triangle_2d 准确计算桥面多边形平面方程
  - sample_height 查询邻近区块并返回 fMAX(fObjectHeight, fTerrainHeight),彻底解决走上桥面穿透掉入水底/河床的问题
  - 新增 test_bridge_height_parity.gd 自动化对拍测试
- 40250 怪物击杀经验动效:
  - 1:1 实现 FLY_EXP(0) / FLY_HP / FLY_SP 粒子轨迹与爆炸吸附
- 40250 客户端全系统功能对齐(Batches 1-31):
  - 包含公会、交易、骑乘、变身、钓鱼、采矿、商城、信件、结婚、地牢等 134 套对拍系统与自动化回归测试
- 文档沉淀:
  - 新增 docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md 客户端对拍缺陷发现与修复工程指南
2026-09-19 08:51:25 -07:00

105 lines
3.8 KiB
GDScript

# test_wasd_steering_parity.gd —— 验证 WASD 转向与连续方向切换对齐 40250:
# 1. 连续快速切换方向(W -> S, A -> D, 对角线切换等),俯仰角(X)与翻滚角(Z)始终保持 0,无翻跟头/倾倒。
# 2. 偏航角(Y)平滑过渡且严格归一化在 [-PI, PI],越过 ±PI 边界时不发生每帧方向往复震荡。
# 3. 40250 按键优先级(Up 优先于 Down,Left 优先于 Right):切换瞬间两键同时按住时不归零卡顿。
#
# godot --headless --path project --script test_wasd_steering_parity.gd
extends SceneTree
const PlayerController = preload("res://player_controller.gd")
var _fail := 0
func _ck(c: bool, m: String) -> void:
if not c:
_fail += 1
printerr("FAIL: " + m)
else:
print(" [PASS] " + m)
func _init() -> void:
await process_frame
_run()
if _fail == 0:
print("=== ALL WASD STEERING PARITY TESTS PASSED ===")
quit(0)
else:
printerr("=== FAILED: %d check(s) failed ===" % _fail)
quit(1)
func _run() -> void:
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
# -------------------------------------------------------------------------
# Test 1: 边界跨越平滑度与无翻跟头(X/Z 严格为 0)
# -------------------------------------------------------------------------
print("\n--- Test 1: 边界跨越(±PI)平滑转向与 X/Z 稳定性 ---")
player.rotation = Vector3.ZERO
# 模拟从北(+PI)到西(-PI/2)再到南(0)再到东(PI/2)再到北(-PI)
var targets: Array[float] = [
PI - 0.05,
-PI + 0.05,
0.0,
PI / 2.0,
-PI / 2.0,
PI
]
var flipped := false
var xz_tilted := false
for t in targets:
for step in range(30):
pc._turn_toward(t, 0.016)
if absf(player.rotation.x) > 1e-4 or absf(player.rotation.z) > 1e-4:
xz_tilted = true
if absf(player.rotation.y) > PI + 1e-3:
flipped = true
_ck(not xz_tilted, "Player rotation.x and rotation.z strictly remain 0.0 (no pitch/roll somersault)")
_ck(not flipped, "Player rotation.y strictly remains in [-PI, PI] without unbounded growth")
# -------------------------------------------------------------------------
# Test 2: 180° 急转弯不发生往复震荡(单向收敛)
# -------------------------------------------------------------------------
print("\n--- Test 2: 180° 急转弯单向平滑收敛 ---")
player.rotation.y = 3.0
var target_yaw := -2.8
var prev_diff := 1e9
var monotonic := true
for step in range(20):
var cur_yaw: float = wrapf(player.rotation.y, -PI, PI)
var diff: float = absf(wrapf(target_yaw - cur_yaw, -PI, PI))
pc._turn_toward(target_yaw, 0.016)
var new_diff: float = absf(wrapf(target_yaw - player.rotation.y, -PI, PI))
if new_diff > diff + 1e-4:
monotonic = false
if is_equal_approx(player.rotation.y, target_yaw):
break
_ck(monotonic, "Turn toward target is monotonic across the PI boundary (no back-and-forth oscillation)")
_ck(is_equal_approx(player.rotation.y, target_yaw), "Turn converges exactly to target_yaw")
# -------------------------------------------------------------------------
# Test 3: 连续 WASD 快速方向切换无卡死或翻滚
# -------------------------------------------------------------------------
print("\n--- Test 3: 连续高频 WASD 切换稳定性 ---")
var dirs := [
Vector3(0, 0, -1), # W
Vector3(0, 0, 1), # S
Vector3(-1, 0, 0), # A
Vector3(1, 0, 0), # D
Vector3(-0.707, 0, -0.707), # WA
Vector3(0.707, 0, 0.707), # SD
Vector3(0.707, 0, -0.707), # WD
Vector3(-0.707, 0, 0.707), # SA
]
var ok := true
for d in dirs:
var yaw := atan2(d.x, d.z)
for _step in range(15):
pc._turn_toward(yaw, 0.016)
if absf(player.rotation.x) > 1e-4 or absf(player.rotation.z) > 1e-4:
ok = false
_ck(ok, "Continuous 8-way rapid directional changes maintain perfect upright orientation")