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
3 changed files with 23 additions and 15 deletions
Showing only changes of commit 43b870465b - Show all commits
+19 -14
View File
@@ -5,9 +5,13 @@ class_name SkinnedPlayerModel
## Replaces the procedural HumanoidModel for characters with custom skins.
@export var model_path: String = ""
## Scale factor applied to the loaded scene. For the Miku GLB, 1.0 is correct (~1.6m).
## Scale factor applied to the loaded scene. The current Miku GLB is ~1.2m tall;
## set to 1.25 to reach ~1.5m (fits inside the 1.8m player capsule).
## For models exported in centimeters (Mixamo/Blender default), set to 0.01.
@export var scale_factor: float = 1.0
@export var scale_factor: float = 1.25
## Vertical offset to align the model's visual feet with the player origin.
## The Miku GLB has feet at Y=0.2 in rest pose; negative offset lowers them.
@export var position_y_offset: float = -0.2
@export var first_person_mode: bool = false # Hide head/torso for FPS view
## Bones per second for locomotion animations created at runtime.
@@ -56,10 +60,11 @@ func load_model(path: String) -> void:
add_child(scene)
print("SkinnedPlayerModel: scene added: %s" % scene.name)
# Apply model scale (the Miku GLB is already in meters, ~1.6m tall)
# Apply model scale (the Miku GLB is ~1.2m; scale_factor adjusts to target height)
# For models exported in centimeters (common from Mixamo/Blender), set scale_factor to 0.01.
scene.scale = Vector3(scale_factor, scale_factor, scale_factor)
print("SkinnedPlayerModel: applied scale %.4f" % scale_factor)
scene.position = Vector3(0, position_y_offset * scale_factor, 0)
print("SkinnedPlayerModel: applied scale %.4f, y_offset %.4f" % [scale_factor, position_y_offset])
# Find mesh instance for first-person mode
_mesh_instance = scene.find_child("Tda Miku for fbx_mesh", true, false)
@@ -122,6 +127,10 @@ func load_model(path: String) -> void:
# Ensure fallback animations exist for states the movement system needs
_ensure_locomotion_animations(animation_player)
# Force initial skin update so the first rendered frame shows the
# correct animated pose instead of T-pose.
_update_skin()
else:
print("SkinnedPlayerModel: WARNING - no AnimationPlayer found")
@@ -303,16 +312,12 @@ func _add_animation_to_player(ap: AnimationPlayer, anim_name: String, anim: Anim
print("SkinnedPlayerModel: added '%s' (%d tracks)" % [anim_name, anim.get_track_count()])
func _update_skin() -> void:
## Force skeleton skin update by re-applying current bone poses.
## GLTF runtime loaded models sometimes need this because the AnimationPlayer's
## internal bone pose updates don't always trigger the visual pipeline.
# Re-apply current bone poses to ensure dirty flags are set.
# This triggers NOTIFICATION_UPDATE_SKELETON on the Skeleton3D.
for i in range(skeleton.get_bone_count()):
skeleton.set_bone_pose(i, skeleton.get_bone_pose(i))
# Also notify the MeshInstance that its skeleton changed
if _mesh_instance:
_mesh_instance.skeleton = _mesh_instance.skeleton
## Force skeleton skin update by notifying Skeleton3D that poses changed.
## GLTF runtime loaded models need this because AnimationPlayer's internal
## bone pose updates don't always trigger the visual pipeline's dirty flags.
## NOTIFICATION_UPDATE_SKELETON causes the Skeleton3D to recompute its
## bone transforms and notify attached MeshInstances to update vertex buffers.
skeleton.notification(NOTIFICATION_UPDATE_SKELETON)
func _setup_first_person() -> void:
# In first person, hide the head and upper body so only arms/hands/legs show
+2 -1
View File
@@ -433,7 +433,8 @@ func _spawn_player(pid: int) -> CharacterBody3D:
var skinned = load("res://characters/skinned_player_model.gd").new()
skinned.name = "SkinnedModel"
skinned.model_path = "res://assets/characters/skins/miku_rigged_animated.glb"
skinned.scale_factor = 1.0 # Already scaled to 1.8m in Blender
skinned.scale_factor = 1.25 # GLB is ~1.2m, scale to ~1.5m for player capsule
skinned.position_y_offset = -0.2 # Align feet with player origin
skinned.position = Vector3.ZERO # Model origin = player origin
player.add_child(skinned)
print("TestLevelBuilder: added SkinnedModel for player 1")
+2
View File
@@ -148,6 +148,8 @@ func _spawn_player(pid: int) -> CharacterBody3D:
var skinned = load("res://characters/skinned_player_model.gd").new()
skinned.name = "SkinnedModel"
skinned.model_path = "res://assets/characters/skins/miku_rigged_animated.glb"
skinned.scale_factor = 1.25
skinned.position_y_offset = -0.2
skinned.position = Vector3(0, 0.0, 0)
skinned.first_person_mode = true
player.add_child(skinned)