您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
109 行
4.1 KiB
109 行
4.1 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Animations;
|
|
using UnityEngine.Playables;
|
|
|
|
[Serializable]
|
|
public struct ActionAnimationDefinition
|
|
{
|
|
public CharacterPredictedState.StateData.Action action;
|
|
public AnimationClip animation;
|
|
public float restartTimeOffset;
|
|
}
|
|
|
|
public class ActionAnimationHandler
|
|
{
|
|
public struct ActionAnimation
|
|
{
|
|
public int port;
|
|
public AnimationClipPlayable animation;
|
|
public float restartTimeOffset;
|
|
}
|
|
|
|
public ActionAnimationHandler(AnimationLayerMixerPlayable mixer, ActionAnimationDefinition[] actionAnimationDefs)
|
|
{
|
|
if (actionAnimationDefs == null)
|
|
return;
|
|
|
|
m_mixer = mixer;
|
|
foreach (var def in actionAnimationDefs)
|
|
{
|
|
if (def.animation == null)
|
|
continue;
|
|
|
|
if (m_actionAnimations.ContainsKey(def.action))
|
|
continue;
|
|
|
|
ActionAnimation actionAnim = new ActionAnimation();
|
|
actionAnim.animation = AnimationClipPlayable.Create(mixer.GetGraph(), def.animation);
|
|
actionAnim.animation.SetApplyFootIK(false);
|
|
actionAnim.animation.SetDuration(def.animation.length);
|
|
actionAnim.port = mixer.AddInput(actionAnim.animation, 0);
|
|
actionAnim.restartTimeOffset = def.restartTimeOffset;
|
|
mixer.SetLayerAdditive((uint)actionAnim.port, true);
|
|
m_actionAnimations.Add(def.action, actionAnim);
|
|
}
|
|
}
|
|
|
|
public void UpdateAction(CharacterPredictedState.StateData.Action newAction, float actionTime)
|
|
{
|
|
// Handle action change. This does not happen when action changes to None
|
|
if (newAction != m_currentAction && newAction != CharacterPredictedState.StateData.Action.None && m_actionAnimations.ContainsKey(newAction))
|
|
{
|
|
// Stop current action
|
|
if (m_currentAction != CharacterPredictedState.StateData.Action.None)
|
|
{
|
|
m_actionAnimations[m_currentAction].animation.Pause();
|
|
m_mixer.SetInputWeight(m_actionAnimations[m_currentAction].port, 0);
|
|
}
|
|
|
|
m_currentAction = newAction;
|
|
|
|
// Start new action animation
|
|
m_actionAnimations[m_currentAction].animation.Play();
|
|
m_mixer.SetInputWeight(m_actionAnimations[m_currentAction].port, 1);
|
|
}
|
|
|
|
if (m_currentAction == CharacterPredictedState.StateData.Action.None)
|
|
return;
|
|
|
|
|
|
// We syncronize time when presentation state is in same action. If presentation state has None action the animation will continue playing normally
|
|
if (newAction == m_currentAction)
|
|
{
|
|
if (actionTime < m_lastActionTime)
|
|
m_actionRestarted = true;
|
|
m_lastActionTime = actionTime;
|
|
|
|
float time = m_actionRestarted ? actionTime + m_actionAnimations[m_currentAction].restartTimeOffset : actionTime;
|
|
m_actionAnimations[m_currentAction].animation.SetTime(time);
|
|
}
|
|
|
|
|
|
|
|
// Stop animation when it is done
|
|
bool animDone = m_actionAnimations[m_currentAction].animation.GetTime() >= m_actionAnimations[m_currentAction].animation.GetDuration();
|
|
if (animDone)
|
|
{
|
|
m_actionAnimations[m_currentAction].animation.Pause();
|
|
m_mixer.SetInputWeight(m_actionAnimations[m_currentAction].port, 0);
|
|
m_currentAction = CharacterPredictedState.StateData.Action.None;
|
|
m_actionRestarted = false;
|
|
m_lastActionTime = 0;
|
|
}
|
|
}
|
|
|
|
public ActionAnimation GetActionAnimation(CharacterPredictedState.StateData.Action action)
|
|
{
|
|
ActionAnimation actionAnimation;
|
|
m_actionAnimations.TryGetValue(action, out actionAnimation);
|
|
return actionAnimation;
|
|
}
|
|
|
|
AnimationLayerMixerPlayable m_mixer;
|
|
Dictionary<CharacterPredictedState.StateData.Action, ActionAnimation> m_actionAnimations = new Dictionary<CharacterPredictedState.StateData.Action, ActionAnimation>();
|
|
CharacterPredictedState.StateData.Action m_currentAction;
|
|
float m_lastActionTime;
|
|
bool m_actionRestarted;
|
|
}
|