162 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			162 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | namespace Fusion.Addons.AnimationController | ||
|  | { | ||
|  | 	using UnityEngine; | ||
|  | 	using UnityEngine.Animations; | ||
|  | 	using UnityEngine.Playables; | ||
|  | 
 | ||
|  | 	/// <summary> | ||
|  | 	/// Animation state that plays multiple clips. Only one clip can be played at any given moment. | ||
|  | 	/// This is useful if you have clips with similar meaning, for example shooting with pistol/rifle/... | ||
|  | 	/// </summary> | ||
|  | 	public abstract partial class MultiClipState : AnimationState, IAnimationTimeProvider | ||
|  | 	{ | ||
|  | 		// PUBLIC MEMBERS | ||
|  | 
 | ||
|  | 		public float AnimationTime             => _animationTime; | ||
|  | 		public float InterpolatedAnimationTime => _interpolatedAnimationTime; | ||
|  | 
 | ||
|  | 		// PROTECTED MEMBERS | ||
|  | 
 | ||
|  | 		protected ClipNode[]             Nodes => _nodes; | ||
|  | 		protected AnimationMixerPlayable Mixer => _mixer; | ||
|  | 
 | ||
|  | 		// PRIVATE MEMBERS | ||
|  | 
 | ||
|  | 		[SerializeField] | ||
|  | 		private ClipNode[] _nodes; | ||
|  | 
 | ||
|  | 		private AnimationMixerPlayable _mixer; | ||
|  | 		private float                  _animationTime; | ||
|  | 		private float                  _interpolatedAnimationTime; | ||
|  | 
 | ||
|  | 		// PUBLIC METHODS | ||
|  | 
 | ||
|  | 		public void SetAnimationTime(float animationTime) | ||
|  | 		{ | ||
|  | 			_animationTime = animationTime; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		public bool IsFinished(float normalizedTime = 1.0f) | ||
|  | 		{ | ||
|  | 			if (_animationTime < normalizedTime) | ||
|  | 				return false; | ||
|  | 
 | ||
|  | 			return IsActive(); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// MultiClipState INTERFACE | ||
|  | 
 | ||
|  | 		protected abstract int GetClipID(); | ||
|  | 
 | ||
|  | 		protected virtual void OnClipRestarted() {} | ||
|  | 		protected virtual void OnClipFinished()  {} | ||
|  | 
 | ||
|  | 		// AnimationState INTERFACE | ||
|  | 
 | ||
|  | 		protected override void CreatePlayable() | ||
|  | 		{ | ||
|  | 			_mixer = AnimationMixerPlayable.Create(Controller.Graph, _nodes.Length); | ||
|  | 
 | ||
|  | 			for (int i = 0, count = _nodes.Length; i < count; ++i) | ||
|  | 			{ | ||
|  | 				ClipNode node = _nodes[i]; | ||
|  | 
 | ||
|  | 				node.CreatePlayable(Controller.Graph); | ||
|  | 
 | ||
|  | 				_mixer.ConnectInput(i, node.PlayableClip, 0); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			AddPlayable(_mixer, 0); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		protected override void OnDespawned() | ||
|  | 		{ | ||
|  | 			if (_mixer.IsValid() == true) | ||
|  | 			{ | ||
|  | 				_mixer.Destroy(); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			for (int i = 0, count = _nodes.Length; i < count; ++i) | ||
|  | 			{ | ||
|  | 				_nodes[i].DestroyPlayable(); | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		protected override void OnFixedUpdate() | ||
|  | 		{ | ||
|  | 			int clipID = GetClipID(); | ||
|  | 
 | ||
|  | 			for (int i = 0, count = _nodes.Length; i < count; ++i) | ||
|  | 			{ | ||
|  | 				_mixer.SetInputWeight(i, 0.0f); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			_mixer.SetInputWeight(clipID, 1.0f); | ||
|  | 
 | ||
|  | 			ClipNode node = _nodes[clipID]; | ||
|  | 
 | ||
|  | 			float oldAnimationTime = _animationTime; | ||
|  | 			float newAnimationTime = oldAnimationTime + Controller.DeltaTime * node.Speed / node.Length; | ||
|  | 			bool  clipRestarted    = false; | ||
|  | 
 | ||
|  | 			if (newAnimationTime >= 1.0f) | ||
|  | 			{ | ||
|  | 				if (node.IsLooping == true) | ||
|  | 				{ | ||
|  | 					newAnimationTime %= 1.0f; | ||
|  | 				} | ||
|  | 				else | ||
|  | 				{ | ||
|  | 					newAnimationTime = 1.0f; | ||
|  | 				} | ||
|  | 
 | ||
|  | 				if (oldAnimationTime < 1.0f) | ||
|  | 				{ | ||
|  | 					clipRestarted = true; | ||
|  | 				} | ||
|  | 			} | ||
|  | 
 | ||
|  | 			_animationTime = newAnimationTime; | ||
|  | 
 | ||
|  | 			node.PlayableClip.SetTime(newAnimationTime * node.Length); | ||
|  | 
 | ||
|  | 			if (clipRestarted == true) | ||
|  | 			{ | ||
|  | 				if (node.IsLooping == true) | ||
|  | 				{ | ||
|  | 					OnClipRestarted(); | ||
|  | 				} | ||
|  | 				else | ||
|  | 				{ | ||
|  | 					OnClipFinished(); | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		protected override void OnInterpolate() | ||
|  | 		{ | ||
|  | 			int clipID = GetClipID(); | ||
|  | 
 | ||
|  | 			for (int i = 0, count = _nodes.Length; i < count; ++i) | ||
|  | 			{ | ||
|  | 				_mixer.SetInputWeight(i, 0.0f); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			_mixer.SetInputWeight(clipID, 1.0f); | ||
|  | 
 | ||
|  | 			ClipNode node = _nodes[clipID]; | ||
|  | 			node.PlayableClip.SetTime(_interpolatedAnimationTime * node.Length); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		protected override void OnSetDefaults() | ||
|  | 		{ | ||
|  | 			_animationTime = 0.0f; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// IAnimationTimeProvider INTERFACE | ||
|  | 
 | ||
|  | 		float IAnimationTimeProvider.AnimationTime             { get { return _animationTime;             } set { _animationTime             = value; } } | ||
|  | 		float IAnimationTimeProvider.InterpolatedAnimationTime { get { return _interpolatedAnimationTime; } set { _interpolatedAnimationTime = value; } } | ||
|  | 	} | ||
|  | } |