// 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 { /// A which plays a "getting hit" animation. /// /// /// Sample: /// /// 3D Game Kit/Flinch /// /// /// 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)); } /************************************************************************************************************************/ /// /// 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 IMessageReceiver system which informs the /// defending character where the incoming hit came from. /// /// So instead we just find the closest enemy and use that as the direction. /// 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 /************************************************************************************************************************/ } }