- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
105 lines
3.8 KiB
GDScript
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")
|