fix: animation debug + F1 third-person camera
SkinnedPlayerModel: - Added _print_tree debug to see GLB scene structure at runtime - Auto-play Idle animation on load - Added periodic debug output for animation state - Only change animation when target differs from current Third-person camera: - F1 toggles between FPS and third-person view - Third-person camera positioned behind/above player - Smooth follow with lerp - Camera tracks player position each frame
This commit is contained in:
@@ -8,7 +8,7 @@ class_name SkinnedPlayerModel
|
|||||||
|
|
||||||
var skeleton: Skeleton3D
|
var skeleton: Skeleton3D
|
||||||
var animation_player: AnimationPlayer
|
var animation_player: AnimationPlayer
|
||||||
var animation_tree: AnimationTree
|
var _anim_debug_timer: float = 0.0
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
if model_path != "":
|
if model_path != "":
|
||||||
@@ -31,18 +31,39 @@ func load_model(path: String) -> void:
|
|||||||
|
|
||||||
add_child(scene)
|
add_child(scene)
|
||||||
|
|
||||||
# Find skeleton and animation player
|
# Debug: print the full scene tree
|
||||||
skeleton = find_skeleton(scene)
|
print("SkinnedPlayerModel: scene tree after instantiation:")
|
||||||
animation_player = find_animation_player(scene)
|
_print_tree(scene, 0)
|
||||||
|
|
||||||
|
# Find animation player — search entire tree including the scene root itself
|
||||||
|
animation_player = find_animation_player(self)
|
||||||
|
if not animation_player:
|
||||||
|
animation_player = find_animation_player(scene)
|
||||||
|
|
||||||
|
skeleton = find_skeleton(self)
|
||||||
|
if not skeleton:
|
||||||
|
skeleton = find_skeleton(scene)
|
||||||
|
|
||||||
if animation_player:
|
if animation_player:
|
||||||
print("SkinnedPlayerModel: loaded '%s' with %d animations" % [
|
var anim_list = animation_player.get_animation_list()
|
||||||
path, animation_player.get_animation_list().size()
|
print("SkinnedPlayerModel: found AnimationPlayer with %d animations:" % anim_list.size())
|
||||||
])
|
for anim in anim_list:
|
||||||
for anim in animation_player.get_animation_list():
|
print(" - %s (length: %.2f)" % [anim, animation_player.get_animation(anim).length])
|
||||||
print(" - %s" % anim)
|
# Auto-play idle
|
||||||
|
if animation_player.has_animation("Idle"):
|
||||||
|
animation_player.play("Idle")
|
||||||
|
print("SkinnedPlayerModel: playing 'Idle'")
|
||||||
|
elif anim_list.size() > 0:
|
||||||
|
animation_player.play(anim_list[0])
|
||||||
|
print("SkinnedPlayerModel: playing first anim: %s" % anim_list[0])
|
||||||
else:
|
else:
|
||||||
print("SkinnedPlayerModel: no animation player found")
|
print("SkinnedPlayerModel: WARNING - no AnimationPlayer found in scene tree")
|
||||||
|
|
||||||
|
func _print_tree(node: Node, depth: int) -> void:
|
||||||
|
var indent = " " * depth
|
||||||
|
print("%s%s (%s)" % [indent, node.name, node.get_class()])
|
||||||
|
for child in node.get_children():
|
||||||
|
_print_tree(child, depth + 1)
|
||||||
|
|
||||||
func find_skeleton(node: Node) -> Skeleton3D:
|
func find_skeleton(node: Node) -> Skeleton3D:
|
||||||
if node is Skeleton3D:
|
if node is Skeleton3D:
|
||||||
@@ -72,6 +93,15 @@ func _process(delta: float) -> void:
|
|||||||
if not animation_player:
|
if not animation_player:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Debug: print animation state occasionally
|
||||||
|
_anim_debug_timer += delta
|
||||||
|
if _anim_debug_timer > 2.0:
|
||||||
|
_anim_debug_timer = 0.0
|
||||||
|
if animation_player.is_playing():
|
||||||
|
print("SkinnedPlayerModel: playing '%s' (pos: %.2f)" % [animation_player.current_animation, animation_player.current_animation_position])
|
||||||
|
else:
|
||||||
|
print("SkinnedPlayerModel: NOT playing any animation")
|
||||||
|
|
||||||
# Get movement state from the state machine
|
# Get movement state from the state machine
|
||||||
var sm = get_parent().get_node_or_null("MovementStateMachine")
|
var sm = get_parent().get_node_or_null("MovementStateMachine")
|
||||||
if not sm:
|
if not sm:
|
||||||
@@ -84,25 +114,16 @@ func _process(delta: float) -> void:
|
|||||||
var vel = sm.player.velocity
|
var vel = sm.player.velocity
|
||||||
speed = Vector2(vel.x, vel.z).length()
|
speed = Vector2(vel.x, vel.z).length()
|
||||||
|
|
||||||
|
# Only change animation if it's different from current
|
||||||
|
var target_anim = "Idle"
|
||||||
match state:
|
match state:
|
||||||
"ground", "idle":
|
"ground", "idle":
|
||||||
if speed > 1.0:
|
if speed > 1.0:
|
||||||
play_animation("Run")
|
target_anim = "Run"
|
||||||
else:
|
"slide", "wall_run", "grapple", "dash":
|
||||||
play_animation("Idle")
|
target_anim = "Run"
|
||||||
"air":
|
|
||||||
play_animation("Idle")
|
|
||||||
"crouch":
|
|
||||||
play_animation("Idle")
|
|
||||||
"slide":
|
|
||||||
play_animation("Run")
|
|
||||||
"wall_run":
|
|
||||||
play_animation("Run")
|
|
||||||
"wall_cling":
|
|
||||||
play_animation("Idle")
|
|
||||||
"grapple":
|
|
||||||
play_animation("Run")
|
|
||||||
"dash":
|
|
||||||
play_animation("Run")
|
|
||||||
_:
|
_:
|
||||||
play_animation("Idle")
|
target_anim = "Idle"
|
||||||
|
|
||||||
|
if animation_player.current_animation != target_anim or not animation_player.is_playing():
|
||||||
|
play_animation(target_anim)
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ var _fps_label: Label
|
|||||||
var _standalone_speed_label: Label
|
var _standalone_speed_label: Label
|
||||||
var _player: CharacterBody3D
|
var _player: CharacterBody3D
|
||||||
var _debug_ui_panel: PanelContainer
|
var _debug_ui_panel: PanelContainer
|
||||||
|
var _third_person: bool = false
|
||||||
|
var _third_person_camera: Camera3D
|
||||||
|
var _fps_camera: Camera3D
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||||
@@ -45,6 +47,61 @@ func _ready() -> void:
|
|||||||
p.queue_free()
|
p.queue_free()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
|
if event is InputEventKey and event.pressed and not event.echo:
|
||||||
|
if event.keycode == KEY_F1:
|
||||||
|
_toggle_third_person()
|
||||||
|
|
||||||
|
func _toggle_third_person() -> void:
|
||||||
|
_third_person = not _third_person
|
||||||
|
|
||||||
|
# Find cameras
|
||||||
|
if not _fps_camera:
|
||||||
|
_fps_camera = _find_camera_in_player()
|
||||||
|
if not _third_person_camera:
|
||||||
|
_setup_third_person_camera()
|
||||||
|
|
||||||
|
if _third_person:
|
||||||
|
# Switch to third person
|
||||||
|
if _fps_camera:
|
||||||
|
_fps_camera.current = false
|
||||||
|
if _third_person_camera:
|
||||||
|
_third_person_camera.current = true
|
||||||
|
print("Third person: ON")
|
||||||
|
else:
|
||||||
|
# Switch to first person
|
||||||
|
if _third_person_camera:
|
||||||
|
_third_person_camera.current = false
|
||||||
|
if _fps_camera:
|
||||||
|
_fps_camera.current = true
|
||||||
|
print("Third person: OFF")
|
||||||
|
|
||||||
|
func _find_camera_in_player() -> Camera3D:
|
||||||
|
if not _player:
|
||||||
|
return null
|
||||||
|
# Search for Camera3D in player's children
|
||||||
|
for child in _player.get_children():
|
||||||
|
if child is Camera3D:
|
||||||
|
return child
|
||||||
|
for grandchild in child.get_children():
|
||||||
|
if grandchild is Camera3D:
|
||||||
|
return grandchild
|
||||||
|
return null
|
||||||
|
|
||||||
|
func _setup_third_person_camera() -> void:
|
||||||
|
if not _player:
|
||||||
|
return
|
||||||
|
_third_person_camera = Camera3D.new()
|
||||||
|
_third_person_camera.name = "ThirdPersonCamera"
|
||||||
|
_third_person_camera.fov = 75.0
|
||||||
|
_third_person_camera.near = 0.1
|
||||||
|
_third_person_camera.far = 200.0
|
||||||
|
# Position behind and above the player
|
||||||
|
_third_person_camera.position = Vector3(0, 2.0, -4.0)
|
||||||
|
_third_person_camera.look_at(Vector3(0, 1.0, 0))
|
||||||
|
_player.add_child(_third_person_camera)
|
||||||
|
_third_person_camera.current = false
|
||||||
|
|
||||||
|
|
||||||
func _build_materials() -> void:
|
func _build_materials() -> void:
|
||||||
pass
|
pass
|
||||||
@@ -690,6 +747,12 @@ func _process(_delta: float) -> void:
|
|||||||
if not _player or not is_instance_valid(_player):
|
if not _player or not is_instance_valid(_player):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Third person camera follow
|
||||||
|
if _third_person and _third_person_camera and _third_person_camera.current:
|
||||||
|
var target_pos = _player.global_position + Vector3(0, 2.0, -4.0)
|
||||||
|
_third_person_camera.global_position = _third_person_camera.global_position.lerp(target_pos, 0.1)
|
||||||
|
_third_person_camera.look_at(_player.global_position + Vector3(0, 1.0, 0))
|
||||||
|
|
||||||
if _debug_ui_panel:
|
if _debug_ui_panel:
|
||||||
_debug_ui_panel.visible = SettingsManager.show_debug_ui
|
_debug_ui_panel.visible = SettingsManager.show_debug_ui
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user