extends Node # Проходимость пропасти контейнеров на настоящей карте Parkour: прыжок у края, двойной прыжок на спуске, подруливание к цели. # Запуск: godot --headless --path . res://tools/test/parkour_gaps.tscn -- --client (ожидание: все зазоры «ДА») # Стартовые точки заданы в коде — после правки layout.py обнови их var level var p var f := 0 # (имя, x, z_старта(центр), z_края, ожидаемая посадка z-диапазон, высота пола) var cases := [ ["k0->k1 (18 м)", 4.0, -465.0, -475.0, 45.0], ["k2->k3 (22 м)", 2.0, -544.0, -549.0, 48.0] , ] func _ready() -> void: level = (load("res://maps/parkour/parkour.tscn") as PackedScene).instantiate() add_child(level) p = level.get_node("Player") p.set_physics_process(false) await get_tree().physics_frame for variant in ["dj", "dash+dj"]: # имя, x старта, пол старта, z старта, z края, пол цели, z цели ближний, дальний, x цели for c in [ ["exit->k1 18", 4.0, 44.0, -446.0, -457.7, 45.0, -476.0, -488.0, 5.0], ["k1->k2 16", 0.0, 45.0, -479.0, -487.7, 46.5, -504.0, -516.0, -4.0], ["k2->k3 22", -2.5, 46.5, -507.0, -515.7, 48.0, -538.0, -550.0, -2.5], ["k3->k4 24", 7.0, 48.0, -541.0, -549.7, 49.0, -574.0, -586.0, 7.5], ["k4->k5 20", 7.0, 49.0, -577.0, -585.7, 50.5, -606.0, -618.0, 2.0], ["k5->k6 22", 2.0, 50.5, -609.0, -617.7, 52.0, -640.0, -656.0, 0.0]]: await trial(c, variant) get_tree().quit() func key(a: String, down: bool) -> void: if down: Input.action_press(a) else: Input.action_release(a) func trial(c: Array, variant: String) -> void: p.set_physics_process(true) p.global_position = Vector3(c[1], c[2] + 1.18, c[3]) p.velocity = Vector3.ZERO p.is_dead = false await get_tree().physics_frame key("move_forward", true); key("sprint", true) var fr := 0; var jumped := false; var did := 0; var res := "промах" while fr < 360: await get_tree().physics_frame; fr += 1 if not jumped and p.is_on_floor() and p.global_position.z < c[4] + 1.0 and fr > 20: jumped = true; key("jump", true); did = 0 if jumped and not p.is_on_floor(): # подруливание к центру цели var dx: float = c[8] - p.global_position.x key("move_left", dx < -0.6); key("move_right", dx > 0.6) if jumped and did == 0 and not p.is_on_floor() and p.velocity.y < 0.0: did = fr if variant == "dj" or variant == "dj+dash": key("jump", false); await get_tree().physics_frame; key("jump", true) if variant == "dash+dj": var e := InputEventAction.new(); e.action = "dash"; e.pressed = true; Input.parse_input_event(e) if jumped and did > 0 and variant == "dj+dash" and fr == did + 8: var e2 := InputEventAction.new(); e2.action = "dash"; e2.pressed = true; Input.parse_input_event(e2) if jumped and did > 0 and variant == "dash+dj" and fr == did + 14: key("jump", false); await get_tree().physics_frame; key("jump", true) if jumped and fr > did + 25 and did > 0 and p.is_on_floor(): var z: float = p.global_position.z if z < c[6] + 0.5 and z > c[7] - 0.5 and absf(p.global_position.y - (c[5] + 1.16)) < 0.3: res = "ДА (z=%.1f)" % z else: res = "упал/на старте (z=%.1f y=%.1f)" % [z, p.global_position.y] break if p.global_position.y < c[2] - 25.0: res = "упал вниз"; break for a in ["move_forward","sprint","jump","move_left","move_right"]: key(a, false) print("%-8s %-10s %s" % [variant, c[0], res]) p.set_physics_process(false)