extends Node # Замеры мувсета ботом: дальность прыжка / двойного / рывка на спринте, бег по стене, прыжок от стены. # Запуск: godot --headless --path . res://tools/test/measure_movement.tscn -- --client (~1 мин, печатает таблицу) # Замеры мувсета: дальность прыжков, рывок, бег по стене, прыжок от стены var root3d: Node3D var p func world(with_floor: bool, wall: bool) -> void: if root3d: root3d.queue_free() await get_tree().physics_frame root3d = Node3D.new(); add_child(root3d) var sb := StaticBody3D.new(); root3d.add_child(sb) if with_floor: var cs := CollisionShape3D.new(); var b := BoxShape3D.new(); b.size = Vector3(400, 1, 800); cs.shape = b; cs.position = Vector3(0, -0.5, -300); sb.add_child(cs) if wall: var cs2 := CollisionShape3D.new(); var b2 := BoxShape3D.new(); b2.size = Vector3(1, 400, 800); cs2.shape = b2; cs2.position = Vector3(-4.5, 0, -300); sb.add_child(cs2) var cs3 := CollisionShape3D.new(); var b3 := BoxShape3D.new(); b3.size = Vector3(1, 400, 800); cs3.shape = b3; cs3.position = Vector3(4.5, 0, -300); sb.add_child(cs3) func spawn(pos: Vector3, vel := Vector3.ZERO) -> void: p = (load("res://player/player.tscn") as PackedScene).instantiate() root3d.add_child(p) p.global_position = pos p.velocity = vel func press(a: String) -> void: Input.action_press(a) func release(a: String) -> void: Input.action_release(a) func tap_dash() -> void: var e := InputEventAction.new(); e.action = "dash"; e.pressed = true Input.parse_input_event(e) func release_all() -> void: for a in ["move_forward","move_left","move_right","sprint","jump","crouch","dash"]: Input.action_release(a) func frames(n: int) -> void: for i in n: await get_tree().physics_frame # прыжок с разбега по ровному полу: variant: single / dj / dash / djdash / dashdj func jump_exp(variant: String) -> void: await world(true, false) spawn(Vector3(0, 1.17, 0)) await frames(5) press("move_forward"); press("sprint") await frames(60) var z0: float = p.global_position.z press("jump") var maxy: float = 0.0; var f := 0; var did2 := false; var did3 := false; var lz := 0.0 while f < 400: await get_tree().physics_frame; f += 1 maxy = maxf(maxy, p.global_position.y - 1.17) if not did2 and p.velocity.y <= 0.0 and not p.is_on_floor(): did2 = true if variant in ["dj", "djdash"]: release("jump"); await get_tree().physics_frame; press("jump") elif variant in ["dash", "dashdj"]: tap_dash() if did2 and not did3 and f > 40 and variant in ["djdash", "dashdj"]: did3 = true if variant == "djdash": tap_dash() else: release("jump"); await get_tree().physics_frame; press("jump") if f > 10 and p.is_on_floor(): lz = p.global_position.z; break release_all() print("прыжок %-7s: дальность %.1f м, высота %.2f м, время %.2f с" % [variant, z0 - lz, maxy, f / 60.0]) p.queue_free() # бег по стене: летим вдоль левой стены со скоростью v, стена слева func wall_exp(v: float, jump_after: float, then: String) -> void: await world(false, true) spawn(Vector3(-3.4, 100, 0), Vector3(0, 0, -v)) press("move_forward") var z0: float = p.global_position.z var f := 0; var run_f := 0; var started := false; var y_start := 0.0; var z_start := 0.0; var jumped := false; var x_max := -99.0; var z_j := 0.0; var y_j := 0.0 var landed_x := 0.0; var landed_z := 0.0; var t_j := 0 while f < 500: await get_tree().physics_frame; f += 1 if p.is_wallrunning: if not started: started = true; y_start = p.global_position.y; z_start = p.global_position.z run_f += 1 if started and not jumped and (run_f / 60.0) >= jump_after: jumped = true; z_j = p.global_position.z; y_j = p.global_position.y; t_j = f release("move_forward"); press("move_forward") press("jump"); await get_tree().physics_frame; release("jump") if then == "dash": await frames(15); tap_dash() if then == "dj": await frames(25); press("jump"); await get_tree().physics_frame; release("jump") if jumped: x_max = maxf(x_max, p.global_position.x) if p.global_position.y < y_j - 3.0: landed_x = p.global_position.x; landed_z = p.global_position.z; break if not jumped and started and not p.is_wallrunning and f > 30: break release_all() if jump_after < 0: pass print("стена v=%.0f: бежали %.2f с, %.1f м вдоль, провал по y %.2f м; прыжок от стены (после %.1fс, затем %s): отлёт от стены до x=%.1f (стена x=-4), вперёд %.1f м, за %.2f с" % [v, run_f / 60.0, (z_start - (z_j if jumped else p.global_position.z)), y_start - (y_j if jumped else p.global_position.y), jump_after, then, x_max, z_j - landed_z, (f - t_j) / 60.0]) p.queue_free() func _ready() -> void: for v in ["single", "dj", "dash", "djdash", "dashdj"]: await jump_exp(v) await wall_exp(13.0, 99.0, "none") await wall_exp(13.0, 0.5, "none") await wall_exp(13.0, 0.5, "dash") await wall_exp(13.0, 0.5, "dj") get_tree().quit()