113 lines
5.2 KiB
C#
113 lines
5.2 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.
|
|
#pragma warning disable UNT0028 // Use non-allocating physics APIs.
|
|
|
|
using Animancer.Units;
|
|
using UnityEngine;
|
|
|
|
namespace Animancer.Samples.AnimatorControllers.GameKit
|
|
{
|
|
/// <summary>A <see cref="CharacterState"/> which plays a "getting hit" animation.</summary>
|
|
///
|
|
/// <remarks>
|
|
/// <strong>Sample:</strong>
|
|
/// <see href="https://kybernetik.com.au/animancer/docs/samples/animator-controllers/3d-game-kit/flinch">
|
|
/// 3D Game Kit/Flinch</see>
|
|
/// </remarks>
|
|
///
|
|
/// https://kybernetik.com.au/animancer/api/Animancer.Samples.AnimatorControllers.GameKit/FlinchState
|
|
///
|
|
[AddComponentMenu(Strings.SamplesMenuPrefix + "Game Kit - Flinch State")]
|
|
[AnimancerHelpUrl(typeof(FlinchState))]
|
|
public class FlinchState : CharacterState
|
|
{
|
|
/************************************************************************************************************************/
|
|
#if UNITY_PHYSICS_3D
|
|
/************************************************************************************************************************/
|
|
|
|
[SerializeField] private MixerTransition2D _Animation;
|
|
[SerializeField] private LayerMask _EnemyLayers;
|
|
[SerializeField, Meters] private float _EnemyCheckRadius = 1;
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
protected virtual void Awake()
|
|
{
|
|
_Animation.Events.OnEnd = Character.StateMachine.ForceSetDefaultState;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
public void OnDamageReceived() => Character.StateMachine.ForceSetState(this);
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
protected virtual void OnEnable()
|
|
{
|
|
Character.Parameters.ForwardSpeed = 0;
|
|
Character.Animancer.Play(_Animation);
|
|
|
|
Vector3 direction = DetermineHitDirection();
|
|
|
|
// Once we know which direction the hit came from, we need to convert it to be relative to the model.
|
|
// The Parameter X represents left/right so we project the direction onto the right vector.
|
|
// The Parameter Y represents forward/back so we project the direction onto the forward vector.
|
|
_Animation.State.Parameter = new(
|
|
Vector3.Dot(Character.Animancer.transform.right, direction),
|
|
Vector3.Dot(Character.Animancer.transform.forward, direction));
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>
|
|
/// Since Animancer does not actually depend on the 3D Game Kit (except for this sample), we cannot reference
|
|
/// any of its scripts from here so we cannot use their <c>IMessageReceiver</c> system which informs the
|
|
/// defending character where the incoming hit came from.
|
|
/// <para></para>
|
|
/// So instead we just find the closest enemy and use that as the direction.
|
|
/// </summary>
|
|
private Vector3 DetermineHitDirection()
|
|
{
|
|
Vector3 position = Character.transform.position;
|
|
float closestEnemySquaredDistance = float.PositiveInfinity;
|
|
Vector3 closestEnemyDirection = Vector3.zero;
|
|
|
|
Collider[] enemies = Physics.OverlapSphere(position, _EnemyCheckRadius, _EnemyLayers);
|
|
for (int i = 0; i < enemies.Length; i++)
|
|
{
|
|
Vector3 direction = enemies[i].transform.position - position;
|
|
float squaredDistance = direction.magnitude;
|
|
if (closestEnemySquaredDistance > squaredDistance)
|
|
{
|
|
closestEnemySquaredDistance = squaredDistance;
|
|
closestEnemyDirection = direction;
|
|
}
|
|
}
|
|
|
|
return closestEnemyDirection.normalized;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
public override bool FullMovementControl => false;
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
public override bool CanExitState => false;
|
|
|
|
/************************************************************************************************************************/
|
|
#else
|
|
/************************************************************************************************************************/
|
|
|
|
protected virtual void Awake()
|
|
{
|
|
SampleReadMe.LogMissingPhysics3DModuleError(this);
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
#endif
|
|
/************************************************************************************************************************/
|
|
}
|
|
}
|