131 lines
5.7 KiB
C#
131 lines
5.7 KiB
C#
// 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
|
|
{
|
|
/// <summary>A <see cref="CharacterState"/> which plays an "airborne" animation.</summary>
|
|
///
|
|
/// <remarks>
|
|
/// <strong>Sample:</strong>
|
|
/// <see href="https://kybernetik.com.au/animancer/docs/samples/animator-controllers/3d-game-kit/airborne">
|
|
/// 3D Game Kit/Airborne</see>
|
|
/// </remarks>
|
|
///
|
|
/// 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;
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>
|
|
/// The airborne animations do not have root motion, so we just let the brain determine which way to go.
|
|
/// </summary>
|
|
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;
|
|
|
|
/************************************************************************************************************************/
|
|
}
|
|
}
|