511 lines
12 KiB
C#
511 lines
12 KiB
C#
|
using System;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.ComponentModel;
|
|||
|
using UnityEngine;
|
|||
|
using UnityEngine.Playables;
|
|||
|
|
|||
|
[RequireComponent(typeof(Animator))]
|
|||
|
public class SimpleAnimation: MonoBehaviour
|
|||
|
{
|
|||
|
public interface State
|
|||
|
{
|
|||
|
bool enabled { get; set; }
|
|||
|
bool isValid { get; }
|
|||
|
float time { get; set; }
|
|||
|
float normalizedTime { get; set; }
|
|||
|
float speed { get; set; }
|
|||
|
string name { get; set; }
|
|||
|
float weight { get; set; }
|
|||
|
float length { get; }
|
|||
|
AnimationClip clip { get; }
|
|||
|
WrapMode wrapMode { get; set; }
|
|||
|
}
|
|||
|
public Animator animator
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (m_Animator == null)
|
|||
|
{
|
|||
|
m_Animator = GetComponent<Animator>();
|
|||
|
}
|
|||
|
return m_Animator;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public bool animatePhysics
|
|||
|
{
|
|||
|
get { return m_AnimatePhysics; }
|
|||
|
set { m_AnimatePhysics = value; animator.updateMode = m_AnimatePhysics ? AnimatorUpdateMode.AnimatePhysics : AnimatorUpdateMode.Normal; }
|
|||
|
}
|
|||
|
|
|||
|
public AnimatorCullingMode cullingMode
|
|||
|
{
|
|||
|
get { return animator.cullingMode; }
|
|||
|
set { m_CullingMode = value; animator.cullingMode = m_CullingMode; }
|
|||
|
}
|
|||
|
|
|||
|
public bool isPlaying { get { return m_Playable.IsPlaying(); } }
|
|||
|
|
|||
|
public bool playAutomatically
|
|||
|
{
|
|||
|
get { return m_PlayAutomatically; }
|
|||
|
set { m_PlayAutomatically = value; }
|
|||
|
}
|
|||
|
|
|||
|
public AnimationClip clip
|
|||
|
{
|
|||
|
get { return m_Clip; }
|
|||
|
set
|
|||
|
{
|
|||
|
m_Clip = value;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public WrapMode wrapMode
|
|||
|
{
|
|||
|
get { return m_WrapMode; }
|
|||
|
set { m_WrapMode = value; }
|
|||
|
}
|
|||
|
|
|||
|
public void AddClip(AnimationClip clip, string newName)
|
|||
|
{
|
|||
|
AddState(clip, newName);
|
|||
|
}
|
|||
|
|
|||
|
public void Blend(string stateName, float targetWeight, float fadeLength)
|
|||
|
{
|
|||
|
m_Animator.enabled = true;
|
|||
|
Kick();
|
|||
|
m_Playable.Blend(stateName, targetWeight, fadeLength);
|
|||
|
}
|
|||
|
|
|||
|
public void CrossFade(string stateName, float fadeLength)
|
|||
|
{
|
|||
|
m_Animator.enabled = true;
|
|||
|
Kick();
|
|||
|
m_Playable.Crossfade(stateName, fadeLength);
|
|||
|
}
|
|||
|
|
|||
|
public void CrossFadeQueued(string stateName, float fadeLength, QueueMode queueMode)
|
|||
|
{
|
|||
|
m_Animator.enabled = true;
|
|||
|
Kick();
|
|||
|
m_Playable.CrossfadeQueued(stateName, fadeLength, queueMode);
|
|||
|
}
|
|||
|
|
|||
|
public int GetClipCount()
|
|||
|
{
|
|||
|
return m_Playable.GetClipCount();
|
|||
|
}
|
|||
|
|
|||
|
public bool IsPlaying(string stateName)
|
|||
|
{
|
|||
|
return m_Playable.IsPlaying(stateName);
|
|||
|
}
|
|||
|
|
|||
|
public void Stop()
|
|||
|
{
|
|||
|
m_Playable.StopAll();
|
|||
|
}
|
|||
|
|
|||
|
public void Stop(string stateName)
|
|||
|
{
|
|||
|
m_Playable.Stop(stateName);
|
|||
|
}
|
|||
|
|
|||
|
public void Sample()
|
|||
|
{
|
|||
|
m_Graph.Evaluate();
|
|||
|
}
|
|||
|
|
|||
|
public bool Play()
|
|||
|
{
|
|||
|
m_Animator.enabled = true;
|
|||
|
Kick();
|
|||
|
if (m_Clip != null && m_PlayAutomatically)
|
|||
|
{
|
|||
|
m_Playable.Play(kDefaultStateName);
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
public void AddState(AnimationClip clip, string name)
|
|||
|
{
|
|||
|
Kick();
|
|||
|
if (m_Playable.AddClip(clip, name))
|
|||
|
{
|
|||
|
RebuildStates();
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
public void RemoveState(string name)
|
|||
|
{
|
|||
|
if (m_Playable.RemoveClip(name))
|
|||
|
{
|
|||
|
RebuildStates();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public bool Play(string stateName)
|
|||
|
{
|
|||
|
//Debug.Log("playing " + stateName);
|
|||
|
m_Animator.enabled = true;
|
|||
|
Kick();
|
|||
|
return m_Playable.Play(stateName);
|
|||
|
}
|
|||
|
|
|||
|
public void PlayQueued(string stateName, QueueMode queueMode)
|
|||
|
{
|
|||
|
m_Animator.enabled = true;
|
|||
|
Kick();
|
|||
|
m_Playable.PlayQueued(stateName, queueMode);
|
|||
|
}
|
|||
|
|
|||
|
public void RemoveClip(AnimationClip clip)
|
|||
|
{
|
|||
|
if (clip == null)
|
|||
|
throw new System.NullReferenceException("clip");
|
|||
|
|
|||
|
if ( m_Playable.RemoveClip(clip) )
|
|||
|
{
|
|||
|
RebuildStates();
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
public void Unwind()
|
|||
|
{
|
|||
|
Kick();
|
|||
|
m_Playable.Unwind();
|
|||
|
}
|
|||
|
|
|||
|
public void Rewind()
|
|||
|
{
|
|||
|
Kick();
|
|||
|
m_Playable.Rewind();
|
|||
|
}
|
|||
|
|
|||
|
public void Rewind(string stateName)
|
|||
|
{
|
|||
|
Kick();
|
|||
|
m_Playable.Rewind(stateName);
|
|||
|
}
|
|||
|
|
|||
|
public State GetState(string stateName)
|
|||
|
{
|
|||
|
SimpleAnimationPlayable.IState state = m_Playable.GetState(stateName);
|
|||
|
if (state == null)
|
|||
|
return null;
|
|||
|
|
|||
|
return new StateImpl(state, this);
|
|||
|
}
|
|||
|
|
|||
|
public IEnumerable<State> GetStates()
|
|||
|
{
|
|||
|
return new StateEnumerable(this);
|
|||
|
}
|
|||
|
|
|||
|
public State this[string name]
|
|||
|
{
|
|||
|
get { return GetState(name); }
|
|||
|
}
|
|||
|
|
|||
|
const string kDefaultStateName = "Default";
|
|||
|
private class StateEnumerable : IEnumerable<State>
|
|||
|
{
|
|||
|
private SimpleAnimation m_Owner;
|
|||
|
public StateEnumerable(SimpleAnimation owner)
|
|||
|
{
|
|||
|
m_Owner = owner;
|
|||
|
}
|
|||
|
|
|||
|
public IEnumerator<State> GetEnumerator()
|
|||
|
{
|
|||
|
return new StateEnumerator(m_Owner);
|
|||
|
}
|
|||
|
|
|||
|
IEnumerator IEnumerable.GetEnumerator()
|
|||
|
{
|
|||
|
return new StateEnumerator(m_Owner);
|
|||
|
}
|
|||
|
|
|||
|
class StateEnumerator : IEnumerator<State>
|
|||
|
{
|
|||
|
private SimpleAnimation m_Owner;
|
|||
|
private IEnumerator<SimpleAnimationPlayable.IState> m_Impl;
|
|||
|
public StateEnumerator(SimpleAnimation owner)
|
|||
|
{
|
|||
|
m_Owner = owner;
|
|||
|
m_Impl = m_Owner.m_Playable.GetStates().GetEnumerator();
|
|||
|
Reset();
|
|||
|
}
|
|||
|
|
|||
|
State GetCurrent()
|
|||
|
{
|
|||
|
return new StateImpl(m_Impl.Current, m_Owner);
|
|||
|
}
|
|||
|
|
|||
|
object IEnumerator.Current { get { return GetCurrent(); } }
|
|||
|
|
|||
|
State IEnumerator<State>.Current { get { return GetCurrent(); } }
|
|||
|
|
|||
|
public void Dispose() { }
|
|||
|
|
|||
|
public bool MoveNext()
|
|||
|
{
|
|||
|
return m_Impl.MoveNext();
|
|||
|
}
|
|||
|
|
|||
|
public void Reset()
|
|||
|
{
|
|||
|
m_Impl.Reset();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
private class StateImpl : State
|
|||
|
{
|
|||
|
public StateImpl(SimpleAnimationPlayable.IState handle, SimpleAnimation component)
|
|||
|
{
|
|||
|
m_StateHandle = handle;
|
|||
|
m_Component = component;
|
|||
|
}
|
|||
|
|
|||
|
private SimpleAnimationPlayable.IState m_StateHandle;
|
|||
|
private SimpleAnimation m_Component;
|
|||
|
|
|||
|
bool State.enabled
|
|||
|
{
|
|||
|
get { return m_StateHandle.enabled; }
|
|||
|
set
|
|||
|
{
|
|||
|
m_StateHandle.enabled = value;
|
|||
|
if (value)
|
|||
|
{
|
|||
|
m_Component.Kick();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
bool State.isValid
|
|||
|
{
|
|||
|
get { return m_StateHandle.IsValid(); }
|
|||
|
}
|
|||
|
float State.time
|
|||
|
{
|
|||
|
get { return m_StateHandle.time; }
|
|||
|
set
|
|||
|
{
|
|||
|
m_StateHandle.time = value;
|
|||
|
m_Component.Kick();
|
|||
|
}
|
|||
|
}
|
|||
|
float State.normalizedTime
|
|||
|
{
|
|||
|
get { return m_StateHandle.normalizedTime; }
|
|||
|
set
|
|||
|
{
|
|||
|
m_StateHandle.normalizedTime = value;
|
|||
|
m_Component.Kick();
|
|||
|
}
|
|||
|
}
|
|||
|
float State.speed
|
|||
|
{
|
|||
|
get { return m_StateHandle.speed; }
|
|||
|
set
|
|||
|
{
|
|||
|
m_StateHandle.speed = value;
|
|||
|
m_Component.Kick();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
string State.name
|
|||
|
{
|
|||
|
get { return m_StateHandle.name; }
|
|||
|
set { m_StateHandle.name = value; }
|
|||
|
}
|
|||
|
float State.weight
|
|||
|
{
|
|||
|
get { return m_StateHandle.weight; }
|
|||
|
set
|
|||
|
{
|
|||
|
m_StateHandle.weight = value;
|
|||
|
m_Component.Kick();
|
|||
|
}
|
|||
|
}
|
|||
|
float State.length
|
|||
|
{
|
|||
|
get { return m_StateHandle.length; }
|
|||
|
}
|
|||
|
|
|||
|
AnimationClip State.clip
|
|||
|
{
|
|||
|
get { return m_StateHandle.clip; }
|
|||
|
}
|
|||
|
|
|||
|
WrapMode State.wrapMode
|
|||
|
{
|
|||
|
get { return m_StateHandle.wrapMode; }
|
|||
|
set { Debug.LogError("Not Implemented"); }
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[System.Serializable]
|
|||
|
public class EditorState
|
|||
|
{
|
|||
|
public AnimationClip clip;
|
|||
|
public string name;
|
|||
|
public bool defaultState;
|
|||
|
}
|
|||
|
|
|||
|
protected void Kick()
|
|||
|
{
|
|||
|
if (!m_IsPlaying)
|
|||
|
{
|
|||
|
m_Graph.Play();
|
|||
|
m_IsPlaying = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected PlayableGraph m_Graph;
|
|||
|
protected PlayableHandle m_LayerMixer;
|
|||
|
protected PlayableHandle m_TransitionMixer;
|
|||
|
protected Animator m_Animator;
|
|||
|
protected bool m_Initialized;
|
|||
|
protected bool m_IsPlaying;
|
|||
|
|
|||
|
protected SimpleAnimationPlayable m_Playable;
|
|||
|
|
|||
|
[SerializeField]
|
|||
|
protected bool m_PlayAutomatically = true;
|
|||
|
|
|||
|
[SerializeField]
|
|||
|
protected bool m_AnimatePhysics = false;
|
|||
|
|
|||
|
[SerializeField]
|
|||
|
protected AnimatorCullingMode m_CullingMode = AnimatorCullingMode.CullUpdateTransforms;
|
|||
|
|
|||
|
[SerializeField]
|
|||
|
protected WrapMode m_WrapMode;
|
|||
|
|
|||
|
[SerializeField]
|
|||
|
protected AnimationClip m_Clip;
|
|||
|
|
|||
|
[SerializeField]
|
|||
|
private EditorState[] m_States;
|
|||
|
|
|||
|
protected virtual void OnEnable()
|
|||
|
{
|
|||
|
Initialize();
|
|||
|
m_Graph.Play();
|
|||
|
if (m_PlayAutomatically)
|
|||
|
{
|
|||
|
Stop();
|
|||
|
Play();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected virtual void OnDisable()
|
|||
|
{
|
|||
|
if (m_Initialized)
|
|||
|
{
|
|||
|
Stop();
|
|||
|
m_Graph.Stop();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void Reset()
|
|||
|
{
|
|||
|
if (m_Graph.IsValid())
|
|||
|
m_Graph.Destroy();
|
|||
|
|
|||
|
m_Initialized = false;
|
|||
|
}
|
|||
|
|
|||
|
private void Initialize()
|
|||
|
{
|
|||
|
if (m_Initialized)
|
|||
|
return;
|
|||
|
|
|||
|
m_Animator = GetComponent<Animator>();
|
|||
|
m_Animator.updateMode = m_AnimatePhysics ? AnimatorUpdateMode.AnimatePhysics : AnimatorUpdateMode.Normal;
|
|||
|
m_Animator.cullingMode = m_CullingMode;
|
|||
|
m_Graph = PlayableGraph.Create();
|
|||
|
m_Graph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
|
|||
|
SimpleAnimationPlayable template = new SimpleAnimationPlayable();
|
|||
|
|
|||
|
var playable = ScriptPlayable<SimpleAnimationPlayable>.Create(m_Graph, template, 1);
|
|||
|
m_Playable = playable.GetBehaviour();
|
|||
|
m_Playable.onDone += OnPlayableDone;
|
|||
|
if (m_States == null)
|
|||
|
{
|
|||
|
m_States = new EditorState[1];
|
|||
|
m_States[0] = new EditorState();
|
|||
|
m_States[0].defaultState = true;
|
|||
|
m_States[0].name = "Default";
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (m_States != null)
|
|||
|
{
|
|||
|
foreach (var state in m_States)
|
|||
|
{
|
|||
|
if (state.clip)
|
|||
|
{
|
|||
|
m_Playable.AddClip(state.clip, state.name);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
EnsureDefaultStateExists();
|
|||
|
|
|||
|
AnimationPlayableUtilities.Play(m_Animator, m_Playable.playable, m_Graph);
|
|||
|
Play();
|
|||
|
Kick();
|
|||
|
m_Initialized = true;
|
|||
|
}
|
|||
|
|
|||
|
private void EnsureDefaultStateExists()
|
|||
|
{
|
|||
|
if (m_Playable != null && m_Clip != null && m_Playable.GetState(kDefaultStateName) == null)
|
|||
|
{
|
|||
|
m_Playable.AddClip(m_Clip, kDefaultStateName);
|
|||
|
Kick();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected virtual void Awake()
|
|||
|
{
|
|||
|
Initialize();
|
|||
|
}
|
|||
|
|
|||
|
protected void OnDestroy()
|
|||
|
{
|
|||
|
if (m_Graph.IsValid())
|
|||
|
{
|
|||
|
m_Graph.Destroy();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void OnPlayableDone()
|
|||
|
{
|
|||
|
m_Graph.Stop();
|
|||
|
m_IsPlaying = false;
|
|||
|
}
|
|||
|
|
|||
|
private void RebuildStates()
|
|||
|
{
|
|||
|
var playableStates = GetStates();
|
|||
|
var list = new List<EditorState>();
|
|||
|
foreach (var state in playableStates)
|
|||
|
{
|
|||
|
var newState = new EditorState();
|
|||
|
newState.clip = state.clip;
|
|||
|
newState.name = state.name;
|
|||
|
list.Add(newState);
|
|||
|
}
|
|||
|
m_States = list.ToArray();
|
|||
|
}
|
|||
|
}
|