// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik // #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value. using Animancer.Units; using UnityEngine; namespace Animancer.Samples.AnimatorControllers.GameKit { /// A which plays an "airborne" animation. /// /// /// Sample: /// /// 3D Game Kit/Airborne /// /// /// https://kybernetik.com.au/animancer/api/Animancer.Samples.AnimatorControllers.GameKit/AirborneState /// [AddComponentMenu(Strings.SamplesMenuPrefix + "Game Kit - Airborne State")] [AnimancerHelpUrl(typeof(AirborneState))] public class AirborneState : CharacterState { /************************************************************************************************************************/ [SerializeField] private LinearMixerTransition _Animations; [SerializeField, MetersPerSecond] private float _JumpSpeed = 10; [SerializeField, MetersPerSecond] private float _JumpAbortSpeed = 10; [SerializeField, Multiplier] private float _TurnSpeedProportion = 5.4f; [SerializeField] private LandingState _LandingState; [SerializeField] private UnityEvent _PlayAudio;// See the Read Me. private bool _IsJumping; /************************************************************************************************************************/ protected virtual void OnEnable() { _IsJumping = false; Character.Animancer.Play(_Animations); } /************************************************************************************************************************/ public override bool StickToGround => false; /************************************************************************************************************************/ /// /// The airborne animations do not have root motion, so we just let the brain determine which way to go. /// public override Vector3 RootMotion => Character.Parameters.MovementDirection * (Character.Parameters.ForwardSpeed * Time.deltaTime); /************************************************************************************************************************/ protected virtual void FixedUpdate() { // When you jump, do not start checking if you have landed until you stop going up. if (_IsJumping) { if (Character.Parameters.VerticalSpeed <= 0) _IsJumping = false; } else { // If we have a landing state, try to enter it. if (_LandingState != null) { if (Character.StateMachine.TrySetState(_LandingState)) return; } else// Otherwise check the default transitions to Idle or Locomotion. { if (Character.CheckMotionState()) return; } // If the jump was cancelled but we are still going up, apply some extra downwards acceleration in // addition to the regular graivty applied in Character.OnAnimatorMove. if (Character.Parameters.VerticalSpeed > 0) Character.Parameters.VerticalSpeed -= _JumpAbortSpeed * Time.deltaTime; } _Animations.State.Parameter = Character.Parameters.VerticalSpeed; Character.Movement.UpdateSpeedControl(); Vector3 movement = Character.Parameters.MovementDirection; // Since we do not have quick turn animations like the LocomotionState, we just increase the turn speed // when the direction we want to go is further away from the direction we are currently facing. float turnSpeed = Vector3.Angle(Character.transform.forward, movement) * (1f / 180) * _TurnSpeedProportion * Character.Movement.CurrentTurnSpeed; Character.Movement.TurnTowards(movement, turnSpeed); } /************************************************************************************************************************/ public bool TryJump() { // We did not override CanEnterState to check if the Character is grounded because this state is also used // if you walk off a ledge, so instead we check that condition here when specifically attempting to jump. if (Character.Movement.IsGrounded && Character.StateMachine.TryResetState(this)) { // Entering this state would have called OnEnable. _IsJumping = true; Character.Parameters.VerticalSpeed = _JumpSpeed; // In the 3D Game Kit the jump sound is actually triggered whenever you have a positive VerticalSpeed // when you become airborne, which could happen if you go up a ramp for example. _PlayAudio.Invoke(); return true; } return false; } /************************************************************************************************************************/ public void CancelJump() => _IsJumping = false; /************************************************************************************************************************/ } }