extends Node # Подтягивание на уступы: тонкая полка и сплошной блок, коллизия «коробка» и «меш», ходьба и спринт, высоты 1,2–2,7 м. # Запуск: godot --headless --path . res://tools/test/mantle_test.tscn -- --client (ожидание: везде «ДА») var root3d: Node3D var p # kind: "thin" (полка 0.6 м, под ней пусто) или "block" (сплошной блок от пола); shape: "box" или "mesh" func build(kind: String, shape: String, h: float) -> 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) var fl := CollisionShape3D.new(); var fb := BoxShape3D.new(); fb.size = Vector3(60, 1, 60); fl.shape = fb; fl.position = Vector3(0, -0.5, 0); sb.add_child(fl) var size := Vector3(10, 0.6, 12) if kind == "thin" else Vector3(10, h, 12) var cy := h - 0.3 if kind == "thin" else h * 0.5 var cs := CollisionShape3D.new() if shape == "box": var b := BoxShape3D.new(); b.size = size; cs.shape = b else: var m := BoxMesh.new(); m.size = size; cs.shape = m.create_trimesh_shape() cs.position = Vector3(0, cy, -8 - size.z * 0.5) # передняя грань на z=-8 sb.add_child(cs) func trial(kind: String, shape: String, h: float, sprint: bool) -> String: await build(kind, shape, h) p = (load("res://player/player.tscn") as PackedScene).instantiate() root3d.add_child(p) p.global_position = Vector3(0, 1.17, 0) await get_tree().physics_frame Input.action_press("move_forward") if sprint: Input.action_press("sprint") var f := 0; var jumped := false; var ok := false while f < 420: await get_tree().physics_frame; f += 1 var dz: float = p.global_position.z + 8.0 # до грани if not jumped and dz < (-1.0 if not sprint else 0.0) + 2.4 and p.is_on_floor() and f > 30: jumped = true; Input.action_press("jump") if jumped and p.is_on_floor() and p.global_position.z < -8.2 and absf(p.global_position.y - (h + 1.16)) < 0.35: ok = true; break for a in ["move_forward","sprint","jump"]: Input.action_release(a) var res := "ДА " if ok else "нет" p.queue_free() return res func _ready() -> void: print("высота уступа: 1.2 1.6 2.0 2.4 2.7") for kind in ["thin", "block"]: for shape in ["box", "mesh"]: for sprint in [false, true]: var row := "%-5s %-4s %-6s " % [kind, shape, "спринт" if sprint else "ходьба"] for h in [1.2, 1.6, 2.0, 2.4, 2.7]: row += await trial(kind, shape, h, sprint) + " " print(row) get_tree().quit()