Files
mtgodot-poc/project/player_move_test.gd
T

145 lines
5.6 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# player_move_test —— §3.1 Src/Dst 移动模型(player_controller.gdheadless 自检。
# godot --headless --path project --script player_move_test.gd
# 覆盖:NEW_Goto 设 Src/Dst/is_going、__IsMovableGroundDistance 太近不动、
# 三门(frozen/lock/moving_skill)、__ReserveClickGround 的 0.1s delay 重试。
extends SceneTree
const PlayerCtl = preload("res://player_controller.gd")
var _fail := 0
func _ck(c: bool, m: String) -> void:
if not c:
_fail += 1
printerr("FAIL: " + m)
func _init() -> void:
await _run()
if _fail == 0:
print("PASS: player_move_test (Src/Dst move model / gates / reserved ground)")
quit(0)
else:
printerr("%d check(s) failed" % _fail)
quit(1)
func _run() -> void:
# SceneTree._init() 早于 root 就绪;等一帧再建 Node3D,避免 !is_inside_tree()。
await process_frame
var pc: Node = PlayerCtl.new()
get_root().add_child(pc)
pc.player = Node3D.new()
get_root().add_child(pc.player)
pc.player.position = Vector3.ZERO
# 1) NEW_Goto:远点 -> 设 Dst + is_going + 面向
var ok: bool = pc._goto(Vector3(10, 0, 0))
_ck(ok, "_goto(far) returns true")
_ck(pc.is_going(), "_goto -> is_going()")
_ck(pc._dst_pos.is_equal_approx(Vector3(10, 0, 0)), "Dst set to click point")
_ck(pc._src_pos.is_equal_approx(Vector3.ZERO), "Src set to current pos")
_ck(is_equal_approx(pc._dst_rot, atan2(10.0, 0.0)), "_dst_rot faces the target")
# 2) __IsMovableGroundDistance:太近(< 1 m)不动
pc._is_going = false
var near_ok: bool = pc._goto(Vector3(0.5, 0, 0))
_ck(near_ok, "_goto(near) returns true (treated as done)")
_ck(not pc.is_going(), "within MOVABLE_GROUND_DISTANCE -> no movement")
# 3) 每帧推进:朝 Dst 走,抵达后 is_going 归零
pc._goto(Vector3(3, 0, 0))
for i in 240:
pc._process(0.05)
if not pc.is_going():
break
_ck(pc.player.position.distance_to(Vector3(3, 0, 0)) < 0.5, "advances to Dst, got %s" % pc.player.position)
_ck(not pc.is_going(), "arrival clears is_going")
# 4) 三门:frozen / lock -> _goto 被挡 -> 预约 + 0.1s 后重试
pc.player.position = Vector3.ZERO
pc._is_going = false
pc.frozen = true
var blocked: bool = pc._goto(Vector3(8, 0, 0))
_ck(not blocked, "_goto while frozen returns false (gated)")
_ck(not pc.is_going(), "frozen -> not going yet")
_ck(pc._reserved_ground != null, "frozen -> click ground reserved")
# 冻结中推进:不平移、不消预约
pc._process(0.05)
_ck(pc.player.position.is_equal_approx(Vector3.ZERO), "frozen -> no translation")
# 解冻:delay 递减到 0 后自动重试预约点
pc.frozen = false
for i in 10:
pc._process(0.02)
_ck(pc.is_going() or pc.player.position.x > 0.1,
"reserved ground fires after delay once unfrozen (going=%s x=%.2f)" % [pc.is_going(), pc.player.position.x])
# 5) moving_skill:只转向不平移
pc.player.position = Vector3.ZERO
pc._is_going = false
pc.moving_skill = true
pc._goto(Vector3(0, 0, 6))
_ck(not pc.is_going(), "_goto while moving_skill is gated (no translate)")
pc.moving_skill = false
# 清掉第 5 组留下的预约点,免得下面各组被它改向。
pc._reserved_ground = null
pc._reserved_delay_time = 0.0
# 6) Actor-Actor 碰撞(TestActorCollision / BlockMovement 近似)——正前方有远端 Actor
# 时走不过去,停在两 body 球相接前;is_going 归零(BlockMovement = 不滑移硬停)。
pc.player.position = Vector3.ZERO
pc.player.rotation.y = 0.0
pc._is_going = false
pc.skip_actor_collision = false
var blocker := Node3D.new()
get_root().add_child(blocker)
blocker.global_position = Vector3(2, 0, 0) # 正前方 2 m
pc.pickables.append(blocker)
pc._goto(Vector3(10, 0, 0)) # 想穿过 blocker
for i in 240:
pc._process(0.05)
if not pc.is_going():
break
_ck(pc.player.position.x > 0.3 and pc.player.position.x < 1.5,
"actor collision halts before overlap (x=%.2f)" % pc.player.position.x)
_ck(not pc.is_going(), "blocked advance clears is_going (BlockMovement)")
# 6b) 死亡的 Actor 不挡(rVictim.IsDead()
pc.player.position = Vector3.ZERO
pc._is_going = false
blocker.set_meta("dead", true)
pc._goto(Vector3(10, 0, 0))
for i in 400:
pc._process(0.05)
if not pc.is_going():
break
_ck(pc.player.position.distance_to(Vector3(10, 0, 0)) < 0.6,
"dead actor does not block (x=%.2f)" % pc.player.position.x)
blocker.set_meta("dead", false)
# 6c) CanSkipCollisionskip_actor_collision)为真 → 整段跳过,可穿过
pc.player.position = Vector3.ZERO
pc._is_going = false
pc.skip_actor_collision = true
pc._goto(Vector3(10, 0, 0))
for i in 400:
pc._process(0.05)
if not pc.is_going():
break
_ck(pc.player.position.distance_to(Vector3(10, 0, 0)) < 0.6,
"skip_actor_collision passes straight through (x=%.2f)" % pc.player.position.x)
pc.skip_actor_collision = false
pc.pickables.erase(blocker)
blocker.free()
# 7) 坐骑转向速度:MountHorse → c_fDefaultHorseRotationSpeed(300),逐帧收敛不瞬转
_ck(is_equal_approx(pc.rotation_speed_deg, pc.ROT_SPEED_DEFAULT_DEG),
"default rotation speed is c_fDefaultRotationSpeed 1200")
pc.rotation_speed_deg = pc.ROT_SPEED_HORSE_DEG
pc.player.position = Vector3.ZERO
pc.player.rotation.y = 0.0
pc._is_going = false
pc._goto(Vector3(0, 0, -6)) # 需要转到 yaw ≈ ±PI
pc._process(0.05)
_ck(absf(pc.player.rotation.y) <= deg_to_rad(pc.ROT_SPEED_HORSE_DEG) * 0.05 + 1e-3,
"mounted: turn clamped to 300 deg/s in one 50ms step (%.3f rad)" % pc.player.rotation.y)
_ck(pc.player.position.z < -0.05, "mounted: still translates toward Dst while turning")
pc.rotation_speed_deg = pc.ROT_SPEED_DEFAULT_DEG