using System; using System.Threading.Tasks; using Godot; namespace KarrotStarterTemplate.Common.StateMachines.Custom.PlayerStateMachines; public enum ERootMotionAnimationDirection { Character, Camera, Input, } public partial class RootMotionBasePlayerState : BasePlayerState { [Export] public ERootMotionAnimationDirection animationDirectionType { get; set; } = ERootMotionAnimationDirection.Input; [Export] public bool updateDirectionOnProcess { get; set; } [Export] public ERootMotionAnimationDirection noInputDirectionTypeFallback { get; set; } = ERootMotionAnimationDirection.Camera; private Vector2 _blendPosition; private Vector3 _velocity = Vector3.Zero; private Vector3 _animationDirection = Vector3.Zero; protected override Task OnEnter() { _animationDirection = GetRootMotionDirection(); return base.OnEnter(); } protected override void OnStateProcess(double delta) { var (x, y, z) = animationTree.GetRootMotionPosition() / 2f; _velocity += new Vector3(-x, y, -z); base.OnStateProcess(delta); } protected override void OnStatePhysicsProcess(double delta) { if (updateDirectionOnProcess) { _animationDirection = GetRootMotionDirection(); } if (_animationDirection != Vector3.Zero) { characterBody.GlobalRotation = new Vector3(0, Mathf.LerpAngle(characterBody.GlobalRotation.Y, -Mathf.Atan2(_animationDirection.X, -_animationDirection.Z), 10 * (float)delta), 0); } Quaternion rotationQuaternion = characterBody.Transform.Basis.GetRotationQuaternion(); characterBody.Velocity = rotationQuaternion.Normalized() * _velocity / (float)delta; characterBody.MoveAndSlide(); _velocity = Vector3.Zero; } private Vector3 GetRootMotionDirection() { ERootMotionAnimationDirection temp = animationDirectionType; if (temp == ERootMotionAnimationDirection.Input && package.GetVector3("move_direction").IsZeroApprox()) { temp = noInputDirectionTypeFallback; } switch (temp) { case ERootMotionAnimationDirection.Character: return Vector3.Zero; case ERootMotionAnimationDirection.Camera: return (-cameraController.camera.GlobalBasis.Z); case ERootMotionAnimationDirection.Input: return (cameraController.camera.GlobalBasis.Z * package.GetVector3("move_direction").Y) + cameraController.camera.GlobalBasis.X * package.GetVector3("move_direction").X; default: throw new ArgumentOutOfRangeException(); } } }