Feat/14 movement overhaul #20

Merged
Dotts merged 86 commits from feat/14-movement-overhaul into main 2026-07-17 10:44:23 -07:00
2 changed files with 113 additions and 29 deletions
Showing only changes of commit b1aec93fd5 - Show all commits
+49 -28
View File
@@ -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)
+64 -1
View File
@@ -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