This page is part of the 3D Game Kit example.
When the player gets hit too many times, they die and Respawn at the last checkpoint they passed:
Mecanim
Dying works basically the same as Flinching except that it's triggered by the Damageable.OnDeath
event:
The PlayerController.OnReceiveMessage
method explained on the Flinch page includes a case for death messages:
// PlayerController.cs:
public void OnReceiveMessage(MessageType type, object sender, object data)
{
switch (type)
{
case MessageType.DAMAGED:
{
Damageable.DamageMessage damageData = (Damageable.DamageMessage)data;
Damaged(damageData);
}
break;
case MessageType.DEAD:
{
Damageable.DamageMessage damageData = (Damageable.DamageMessage)data;
Die(damageData);
}
break;
}
}
readonly int m_HashDeath = Animator.StringToHash("Death");
public void Die(Damageable.DamageMessage damageMessage)
{
m_Animator.SetTrigger(m_HashDeath);
m_ForwardSpeed = 0f;
m_VerticalSpeed = 0f;
m_Respawning = true;
m_Damageable.isInvulnerable = true;
}
- The transition from
Any State
toEllenDeath
occurs after the"Death"
trigger parameter is set. - When that animation finishes it transitions into the
BeginRespawn
state. - That state has a
EllenRespawnEffect
script attached to it. - That script's
OnStateEnter
method callsPlayerController.Respawn
. Respawn
callsStartCoroutine(RespawnRoutine())
.RespawnRoutine
does several things:
readonly int m_HashRespawn = Animator.StringToHash("Respawn");
protected IEnumerator RespawnRoutine()
{
// Wait for the animator to be transitioning from the EllenDeath state.
while (m_CurrentStateInfo.shortNameHash != m_HashEllenDeath || !m_IsAnimatorTransitioning)
{
yield return null;
}
// Wait for the screen to fade out.
yield return StartCoroutine(ScreenFader.FadeSceneOut());
while (ScreenFader.IsFading)
{
yield return null;
}
// Enable spawning.
EllenSpawn spawn = GetComponentInChildren<EllenSpawn>();
spawn.enabled = true;
// If there is a checkpoint, move Ellen to it.
if (m_CurrentCheckpoint != null)
{
transform.position = m_CurrentCheckpoint.transform.position;
transform.rotation = m_CurrentCheckpoint.transform.rotation;
}
else
{
Debug.LogError("There is no Checkpoint set, there should always be a checkpoint set. Did you add acheckpoint at the spawn?");
}
// Set the Respawn parameter of the animator.
m_Animator.SetTrigger(m_HashRespawn);
// Start the respawn graphic effects.
spawn.StartEffect();
// Wait for the screen to fade in.
// Currently it is not important to yield here but should some changes occur that require waiting until arespawn has finished this will be required.
yield return StartCoroutine(ScreenFader.FadeSceneIn());
m_Damageable.ResetDamage();
}
- The
"Respawn"
trigger causes the Animator Controller to transition to theRespawn
state which plays the actual animation on the character (while the screen is fading back in).
Animancer
The DieState
script handles most of the same behaviour as the Mecanim character:
using Animancer;
using Animancer.FSM;
using UnityEngine;
using UnityEngine.Events;
public sealed class DieState : CharacterState
{
[SerializeField] private ClipTransition _Animation;
[SerializeField] private UnityEvent _OnEnterState;
[SerializeField] private UnityEvent _OnExitState;
private void Awake()
{
_Animation.Events.OnEnd = Character.Respawn.ForceEnterState;
}
public void OnDeath()
{
Character.StateMachine.ForceSetState(this);
}
private void OnEnable()
{
Character.Animancer.Play(_Animation);
Character.Parameters.ForwardSpeed = 0;
_OnEnterState.Invoke();
}
private void OnDisable()
{
_OnExitState.Invoke();
}
public override bool FullMovementControl => false;
public override bool CanExitState => false;
}
Unfortunately, the Script Referencing issue prevents it from using the ScreenFader
script because its methods are static
so Unity Events can't call them. UltEvents could call them, but we don't want this example to require another plugin.
It has a public
OnDeath
method for the Damageable
to call just like the Flinch state as well as _OnEnterState
and _OnExitState
events which make the player invulnerable just like the Respawn state.
Those events could have been set up as Animancer Events at the start and end of the _Animation
Transition, but it's possible that something could interrupt this state (such as forcibly restarting the level) and we wouldn't want to leave the player invulnerable if that happens.