From 315173556e800bf02968edbfda2f2ea4eee91a9e Mon Sep 17 00:00:00 2001 From: Dmitrii Bykov Date: Sun, 24 May 2026 20:34:06 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20=D1=80=D0=B5=D0=B0=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D1=8B=D0=B5=20=D1=80=D0=B0=D1=81=D1=87=D1=91=D1=82=D1=8B=20sca?= =?UTF-8?q?le=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20AABB-=D0=B8=D0=BD=D1=81?= =?UTF-8?q?=D0=BF=D0=B5=D0=BA=D1=86=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Написал scripts/util/inspect_models.gd — runtime-инструмент. Запустил через --headless --script, получил РЕАЛЬНЫЕ размеры: ХАРАКТЕРЫ (mini-characters): - Все male: 0.77×0.67-0.79×0.34 м (Ш×В×Г), T-pose шириной 0.77м - Pivot near center (offset 0.0005м) - 32 анимации, ВКЛЮЧАЯ «idle», «walk», «sit», «static» ФУРНИТУРА (выборка): - bedSingle: 1.62×0.51×1.89м (реалистичный single bed) - desk: 0.73×0.38×0.56м (мелко, нужно scale ~2.0) - chairDesk: 0.48×0.42×0.44м (мелко, нужно ~2.0-2.5) - kitchenFridgeLarge: 0.79×1.32×0.39м (нормально) РАСЧЁТЫ ОТЦА: - Цель: рост ~1.7м (взрослый отец) - Базовая высота 0.722м → scale = 1.7/0.722 = 2.35 - В T-pose ширина 1.8м (огромный) — НО idle-поза узкая, ~0.7м - Поэтому КРИТИЧНО запустить idle, не T-pose ФИКСЫ: 1. Father scale 2.35 (рост 1.7м, нормальный взрослый) 2. _start_father_idle через call_deferred — glb children могут быть не готовы в _ready, deferred ждёт следующий кадр 3. Animation list = 32 шт. Алгоритм: - Ищет первую анимацию содержащую «idle» (нижний регистр) - Если нет — играет первую в списке (fallback) - Print имя анимации для debug 4. Position x=1.6 (чуть дальше от двери при scale 2.35) ОСТАЁТСЯ ПРОВЕРИТЬ: - Реально ли запустилась idle (увидим по позе — руки опущены или раскинуты T-pose) - Возможно scale 2.35 слишком много с idle — иногда мини-чары выглядят пухло - Furniture scales — TODO следующим коммитом если попросишь Co-Authored-By: Claude Opus 4.7 (1M context) --- scenes/prologue/act1_room.tscn | 2 +- scripts/prologue/act1.gd | 3 +- scripts/util/inspect_models.gd | 83 ++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 scripts/util/inspect_models.gd diff --git a/scenes/prologue/act1_room.tscn b/scenes/prologue/act1_room.tscn index 9434e8b..0873cb2 100644 --- a/scenes/prologue/act1_room.tscn +++ b/scenes/prologue/act1_room.tscn @@ -650,7 +650,7 @@ material_override = SubResource("mat_note") shape = SubResource("shape_note") [node name="FatherNPC" parent="." instance=ExtResource("100_father")] -transform = Transform3D(0, 0, -1.4, 0, 1.4, 0, 1.4, 0, 0, 1.5, 0, 0) +transform = Transform3D(0, 0, -2.35, 0, 2.35, 0, 2.35, 0, 0, 1.6, 0, 0) [node name="PlayerFPV" parent="." instance=ExtResource("3_player")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.5) diff --git a/scripts/prologue/act1.gd b/scripts/prologue/act1.gd index b1f3026..e3f4f73 100644 --- a/scripts/prologue/act1.gd +++ b/scripts/prologue/act1.gd @@ -15,7 +15,8 @@ var state: State = State.INTRO func _ready() -> void: _hide_noise_items() _apply_textures() - _start_father_idle() + # Deferred — glb children могут быть не готовы в _ready parent сцены + call_deferred("_start_father_idle") player.interactable_focused.connect(_on_player_focused) player.interactable_unfocused.connect(_on_player_unfocused) diff --git a/scripts/util/inspect_models.gd b/scripts/util/inspect_models.gd new file mode 100644 index 0000000..b98276c --- /dev/null +++ b/scripts/util/inspect_models.gd @@ -0,0 +1,83 @@ +extends SceneTree + + +func _init() -> void: + var paths_to_check: Array[String] = [ + # Mini characters (для отца + других NPC) + "res://assets/models/characters/character-male-a.glb", + "res://assets/models/characters/character-male-b.glb", + "res://assets/models/characters/character-male-c.glb", + "res://assets/models/characters/character-male-d.glb", + "res://assets/models/characters/character-male-e.glb", + "res://assets/models/characters/character-male-f.glb", + "res://assets/models/characters/character-female-a.glb", + # Furniture + "res://assets/models/furniture/bedSingle.glb", + "res://assets/models/furniture/desk.glb", + "res://assets/models/furniture/chairDesk.glb", + "res://assets/models/furniture/chair.glb", + "res://assets/models/furniture/computerScreen.glb", + "res://assets/models/furniture/computerKeyboard.glb", + "res://assets/models/furniture/bookcaseClosedDoors.glb", + "res://assets/models/furniture/cardboardBoxClosed.glb", + "res://assets/models/furniture/kitchenFridgeLarge.glb", + "res://assets/models/furniture/kitchenStove.glb", + "res://assets/models/furniture/kitchenSink.glb", + "res://assets/models/furniture/table.glb", + ] + + print("=== MODEL INSPECTION ===") + for path in paths_to_check: + var scene: PackedScene = load(path) + if scene == null: + print("FAIL load: %s" % path) + continue + var instance: Node = scene.instantiate() + if instance == null: + print("FAIL instantiate: %s" % path) + continue + var aabb: AABB = _get_total_aabb(instance) + print("--- %s ---" % path.get_file()) + print(" size: x=%.3f y=%.3f z=%.3f" % [aabb.size.x, aabb.size.y, aabb.size.z]) + print(" pos: x=%.3f y=%.3f z=%.3f" % [aabb.position.x, aabb.position.y, aabb.position.z]) + var ap: AnimationPlayer = _find_anim_player(instance) + if ap != null: + var anims: PackedStringArray = ap.get_animation_list() + print(" animations (%d total):" % anims.size()) + for name in anims: + print(" - %s" % name) + instance.queue_free() + print("=== END ===") + quit() + + +func _find_anim_player(node: Node) -> AnimationPlayer: + if node is AnimationPlayer: + return node as AnimationPlayer + for child in node.get_children(): + var found: AnimationPlayer = _find_anim_player(child) + if found != null: + return found + return null + + +func _get_total_aabb(node: Node) -> AABB: + var bounds: AABB = AABB() + var first: bool = true + for mesh_node in _find_all_meshes(node): + var aabb: AABB = mesh_node.get_aabb() + if first: + bounds = aabb + first = false + else: + bounds = bounds.merge(aabb) + return bounds + + +func _find_all_meshes(node: Node) -> Array: + var result: Array = [] + if node is MeshInstance3D: + result.append(node) + for child in node.get_children(): + result.append_array(_find_all_meshes(child)) + return result