You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
5.8 KiB
149 lines
5.8 KiB
public partial class AnimationController : Node3D |
|
{ |
|
[Export] public Skeleton3D Skeleton { get; set; } |
|
[Export] public BoneAttachment3D RootBone { get; set; } |
|
|
|
// Contains all the bones in the skeleton, keyed by name (e.g. "LowerArm_L"). |
|
Dictionary<string, BoneAttachment3D> _bones = []; |
|
|
|
// Whether the player's body is currently turning to match up with the camera rotation. |
|
bool _isTurning = false; |
|
|
|
// Current amount the body is turned due to walking sideways. |
|
float _bodyYaw = 0.0f; |
|
|
|
CharacterBody3D _player; |
|
MovementController _movementController; |
|
CameraController _cameraController; |
|
Camera3D _camera; |
|
Transform3D _cameraDefaultTransform; |
|
|
|
AnimationTree _animTree; |
|
Animation _walkForwardAnim; |
|
Animation _walkBackwardAnim; |
|
|
|
public override void _Ready() |
|
{ |
|
_player = GetParent<CharacterBody3D>(); |
|
_movementController = _player.GetNode<MovementController>("MovementController"); |
|
_cameraController = _player.GetNode<CameraController>("CameraController"); |
|
_camera = _cameraController.Camera; |
|
_cameraDefaultTransform = _camera.Transform; |
|
|
|
_animTree = GetNode<AnimationTree>("AnimationTree"); |
|
_walkForwardAnim = _animTree.GetAnimation("walk_forward"); |
|
_walkBackwardAnim = _animTree.GetAnimation("walk_backward"); |
|
|
|
void AddBone(BoneAttachment3D bone) |
|
{ bone.OverridePose = true; _bones[bone.Name] = bone; } |
|
AddBone(RootBone); |
|
foreach (var child in RootBone.FindChildren("*", "BoneAttachment3D")) |
|
AddBone((BoneAttachment3D)child); |
|
} |
|
|
|
public override void _Process(double delta) |
|
{ |
|
ResetTransforms(); |
|
HandleTurning(delta); |
|
HandleLookingAnimation(delta); |
|
HandleWalkingAnimation(delta); |
|
} |
|
|
|
void ResetTransforms() |
|
{ |
|
foreach (var bone in _bones.Values) |
|
bone.Transform = Skeleton.GetBonePose(bone.BoneIdx); |
|
_camera.Transform = _cameraDefaultTransform; |
|
} |
|
|
|
void HandleTurning(double delta) |
|
{ |
|
const float TurnBegin = 60.0f; // Start turning when camera is rotated this much. |
|
const float TurnEnd = 5.0f; // Stop turning when body is this close to camera rotation. |
|
const float TurnSpeed = 6.0f; |
|
|
|
var yaw = _cameraController.CurrentYaw; // Camera yaw relative to player yaw. |
|
var isMoving = _movementController.RealMoveSpeed > 0.01f; |
|
_isTurning = isMoving || (Abs(yaw) > DegToRad(TurnBegin)); |
|
|
|
if (_isTurning) { |
|
var yawDelta = Sign(yaw) * Min(Abs(yaw), Abs(yaw) * TurnSpeed * (float)delta); |
|
_cameraController.CurrentYaw -= (float)yawDelta; |
|
_player.RotateY(yawDelta); |
|
|
|
if (Abs(_cameraController.CurrentYaw) < DegToRad(TurnEnd)) |
|
_isTurning = false; |
|
} |
|
} |
|
|
|
void HandleLookingAnimation(double delta) |
|
{ |
|
const float PitchFactorLowerBody = 0.05f; |
|
const float PitchFactorUpperBody = 0.20f; |
|
const float PitchFactorNeck = 0.25f; |
|
const float PitchFactorHead = 0.35f; |
|
|
|
var pitch = _cameraController.CurrentPitch; |
|
_bones["LowerBody"].RotateX(pitch * PitchFactorLowerBody); |
|
_bones["UpperBody"].RotateX(-pitch * PitchFactorUpperBody); |
|
_bones["Neck"].RotateX(-pitch * PitchFactorNeck); |
|
_bones["Head"].RotateX(-pitch * PitchFactorHead); |
|
_bones["UpperArm_L"].RotateX(pitch * (PitchFactorLowerBody + PitchFactorUpperBody) / 2); |
|
_bones["UpperArm_R"].RotateX(pitch * (PitchFactorLowerBody + PitchFactorUpperBody) / 2); |
|
_camera.RotateX(pitch * (1 - PitchFactorLowerBody - PitchFactorUpperBody - PitchFactorNeck - PitchFactorHead)); |
|
|
|
const float YawFactorLowerBody = 0.06f; |
|
const float YawFactorUpperBody = 0.18f; |
|
const float YawFactorNeck = 0.2f; |
|
const float YawFactorHead = 0.3f; |
|
|
|
var yaw = _cameraController.CurrentYaw; |
|
_bones["LowerBody"].GlobalRotate(Vector3.Up, yaw * YawFactorLowerBody); |
|
_bones["UpperBody"].GlobalRotate(Vector3.Up, yaw * YawFactorUpperBody); |
|
_bones["Neck"].GlobalRotate(Vector3.Up, yaw * YawFactorNeck); |
|
_bones["Head"].GlobalRotate(Vector3.Up, yaw * YawFactorHead); |
|
_camera.GlobalRotate(Vector3.Up, yaw * (1 - YawFactorLowerBody - YawFactorUpperBody - YawFactorNeck - YawFactorHead)); |
|
|
|
// How much of the "ideal" camera rotation (rather than animation rotation) should be applied. |
|
const float CameraFactorIdealPitch = 0.7f; |
|
const float CameraFactorIdealYaw = 0.8f; |
|
const float CameraFactorIdealRoll = 0.9f; |
|
|
|
var global_yaw = _player.Rotation.Y + yaw; |
|
var cameraRotation = _camera.GlobalRotation; |
|
cameraRotation.X = LerpAngle(cameraRotation.X, pitch, CameraFactorIdealPitch); |
|
cameraRotation.Y = LerpAngle(cameraRotation.Y, global_yaw, CameraFactorIdealYaw); |
|
cameraRotation.Z = LerpAngle(cameraRotation.Z, 0, CameraFactorIdealRoll); |
|
_camera.GlobalRotation = cameraRotation; |
|
} |
|
|
|
void HandleWalkingAnimation(double delta) |
|
{ |
|
var input = Input.GetVector("move_strafe_left", "move_strafe_right", "move_forward", "move_back"); |
|
var isOnFloor = _movementController.TimeSinceOnFloor < 0.25f; |
|
var isMoving = _movementController.RealMoveSpeed > 0.01f; |
|
var isMovingForward = input.Y <= 0; |
|
|
|
var walkState = (isOnFloor && isMoving) ? "move" : "idle"; |
|
var walkDirection = isMovingForward ? "forward" : "backward"; |
|
var walkSpeed = _movementController.RealMoveSpeed / _movementController.MaxSpeed; |
|
var targetBodyYaw = -(isMovingForward ? Vector2.Up : Vector2.Down).AngleTo(input); |
|
|
|
_animTree.Set("parameters/walk_state/transition_request", walkState); |
|
_animTree.Set("parameters/walk_direction/transition_request", walkDirection); |
|
|
|
var prevWalkSpeed = (float)_animTree.Get("parameters/walk_speed/blend_amount"); |
|
_animTree.Set("parameters/walk_speed/blend_amount", Lerp(prevWalkSpeed, walkSpeed, 10 * (float)delta)); |
|
|
|
const float YAW_FACTOR_LOWER_BODY = 0.25f; |
|
const float YAW_FACTOR_UPPER_BODY = 0.25f; |
|
const float YAW_FACTOR_NECK = 0.50f; |
|
|
|
_bodyYaw += (targetBodyYaw - _bodyYaw) * (float)delta * 6; |
|
|
|
_bones["Root"].GlobalRotate(Vector3.Up, _bodyYaw); |
|
_bones["LowerBody"].GlobalRotate(Vector3.Up, -_bodyYaw * YAW_FACTOR_LOWER_BODY); |
|
_bones["UpperBody"].GlobalRotate(Vector3.Up, -_bodyYaw * YAW_FACTOR_UPPER_BODY); |
|
_bones["Neck"].GlobalRotate(Vector3.Up, -_bodyYaw * YAW_FACTOR_NECK); |
|
} |
|
}
|
|
|