201 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| namespace TPSBR
 | |
| {
 | |
| 	using System;
 | |
| 	using UnityEngine;
 | |
| 	using UnityEngine.Animations;
 | |
| 	using UnityEngine.Playables;
 | |
| 	using Fusion.Addons.KCC;
 | |
| 	using Fusion.Addons.AnimationController;
 | |
| 
 | |
| 	using AnimationState = Fusion.Addons.AnimationController.AnimationState;
 | |
| 
 | |
| 	public sealed unsafe class TurnState : AnimationState
 | |
| 	{
 | |
| 		// PUBLIC MEMBERS
 | |
| 
 | |
| 		public float BlendSpeed => _blendSpeed;
 | |
| 		public float TurnSpeed  => _turnSpeed;
 | |
| 
 | |
| 		[NonSerialized][AnimationProperty(nameof(InterpolateAnimationTime))]
 | |
| 		public float AnimationTime;
 | |
| 		[NonSerialized][AnimationProperty(nameof(InterpolateRemainingTime))]
 | |
| 		public float RemainingTime;
 | |
| 		[NonSerialized]
 | |
| 		public float InterpolatedAnimationTime;
 | |
| 		[NonSerialized]
 | |
| 		public float InterpolatedRemainingTime;
 | |
| 
 | |
| 		// PRIVATE MEMBERS
 | |
| 
 | |
| 		[SerializeField]
 | |
| 		private ClipNode[] _nodes;
 | |
| 		[SerializeField]
 | |
| 		private float      _blendSpeed = 1.0f;
 | |
| 		[SerializeField]
 | |
| 		private float      _turnSpeed = 1.0f;
 | |
| 		[SerializeField]
 | |
| 		private float      _animationPower = 1.0f;
 | |
| 		[SerializeField]
 | |
| 		private float      _maxAnimationSpeed = 1.0f;
 | |
| 
 | |
| 		private KCC                    _kcc;
 | |
| 		private Agent                  _agent;
 | |
| 		private Weapons                _weapons;
 | |
| 		private AnimationMixerPlayable _mixer;
 | |
| 
 | |
| 		// PUBLIC METHODS
 | |
| 
 | |
| 		public void Refresh(float angle)
 | |
| 		{
 | |
| 			if (angle < 0.0f && RemainingTime <= 0.0f)
 | |
| 			{
 | |
| 				RemainingTime = Mathf.Clamp(RemainingTime + angle * _turnSpeed, -_maxAnimationSpeed, 0.0f);
 | |
| 			}
 | |
| 			if (angle > 0.0f && RemainingTime >= 0.0f)
 | |
| 			{
 | |
| 				RemainingTime = Mathf.Clamp(RemainingTime + angle * _turnSpeed, 0.0f, _maxAnimationSpeed);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// 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 OnInitialize()
 | |
| 		{
 | |
| 			base.OnInitialize();
 | |
| 
 | |
| 			_kcc     = Controller.GetComponentNoAlloc<KCC>();
 | |
| 			_agent   = Controller.GetComponentNoAlloc<Agent>();
 | |
| 			_weapons = Controller.GetComponentNoAlloc<Weapons>();
 | |
| 		}
 | |
| 
 | |
| 		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 idleClipID = GetClipID();
 | |
| 			int turnClipID;
 | |
| 
 | |
| 			float remainingTime = Mathf.Abs(RemainingTime);
 | |
| 
 | |
| 			float remainingDeltaTime = Controller.DeltaTime * Mathf.Max(0.5f, remainingTime);
 | |
| 			float animationDeltaTime = Controller.DeltaTime * remainingTime;
 | |
| 
 | |
| 			if (RemainingTime <= 0.0f)
 | |
| 			{
 | |
| 				turnClipID = idleClipID + 1;
 | |
| 				RemainingTime = Mathf.Clamp(RemainingTime + remainingDeltaTime * _blendSpeed, -_maxAnimationSpeed, 0.0f);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				turnClipID = idleClipID + 2;
 | |
| 				RemainingTime = Mathf.Clamp(RemainingTime - remainingDeltaTime * _blendSpeed, 0.0f, _maxAnimationSpeed);
 | |
| 			}
 | |
| 
 | |
| 			for (int i = 0, count = _nodes.Length; i < count; ++i)
 | |
| 			{
 | |
| 				_mixer.SetInputWeight(i, 0.0f);
 | |
| 			}
 | |
| 
 | |
| 			ClipNode idleNode = _nodes[idleClipID];
 | |
| 			ClipNode turnNode = _nodes[turnClipID];
 | |
| 
 | |
| 			float animationTime = AnimationTime + animationDeltaTime * turnNode.Speed / turnNode.Length;
 | |
| 			if (animationTime >= 1.0f)
 | |
| 			{
 | |
| 				animationTime %= 1.0f;
 | |
| 			}
 | |
| 
 | |
| 			AnimationTime = animationTime;
 | |
| 
 | |
| 			_mixer.SetInputWeight(idleClipID, 1.0f - _animationPower);
 | |
| 			_mixer.SetInputWeight(turnClipID, _animationPower);
 | |
| 
 | |
| 			idleNode.PlayableClip.SetTime(animationTime * idleNode.Length);
 | |
| 			turnNode.PlayableClip.SetTime(animationTime * turnNode.Length);
 | |
| 		}
 | |
| 
 | |
| 		protected override void OnInterpolate()
 | |
| 		{
 | |
| 			int idleClipID = GetClipID();
 | |
| 			int turnClipID = InterpolatedRemainingTime <= 0.0f ? (idleClipID + 1) : (idleClipID + 2);
 | |
| 
 | |
| 			for (int i = 0, count = _nodes.Length; i < count; ++i)
 | |
| 			{
 | |
| 				_mixer.SetInputWeight(i, 0.0f);
 | |
| 			}
 | |
| 
 | |
| 			_mixer.SetInputWeight(idleClipID, 1.0f - _animationPower);
 | |
| 			_mixer.SetInputWeight(turnClipID, _animationPower);
 | |
| 
 | |
| 			ClipNode idleNode = _nodes[idleClipID];
 | |
| 			idleNode.PlayableClip.SetTime(InterpolatedAnimationTime * idleNode.Length);
 | |
| 
 | |
| 			ClipNode turnNode = _nodes[turnClipID];
 | |
| 			turnNode.PlayableClip.SetTime(InterpolatedAnimationTime * turnNode.Length);
 | |
| 		}
 | |
| 
 | |
| 		protected override void OnDeactivate()
 | |
| 		{
 | |
| 			RemainingTime = 0.0f;
 | |
| 		}
 | |
| 
 | |
| 		protected override void OnSetDefaults()
 | |
| 		{
 | |
| 			AnimationTime = 0.0f;
 | |
| 		}
 | |
| 
 | |
| 		// PRIVATE METHODS
 | |
| 
 | |
| 		private int GetClipID()
 | |
| 		{
 | |
| 			int currentWeaponSlot = _weapons.CurrentWeaponSlot;
 | |
| 			if (currentWeaponSlot > 2)
 | |
| 			{
 | |
| 				currentWeaponSlot = 1; // For grenades we use pistol set
 | |
| 			}
 | |
| 
 | |
| 			if (currentWeaponSlot < 0)
 | |
| 				return 0;
 | |
| 
 | |
| 			return currentWeaponSlot * 3;
 | |
| 		}
 | |
| 
 | |
| 		private void InterpolateAnimationTime(AnimationInterpolationInfo interpolationInfo)
 | |
| 		{
 | |
| 			InterpolatedAnimationTime = AnimationUtility.InterpolateTime(interpolationInfo.FromBuffer.ReinterpretState<float>(interpolationInfo.Offset), interpolationInfo.ToBuffer.ReinterpretState<float>(interpolationInfo.Offset), 1.0f, interpolationInfo.Alpha);
 | |
| 		}
 | |
| 
 | |
| 		private void InterpolateRemainingTime(AnimationInterpolationInfo interpolationInfo)
 | |
| 		{
 | |
| 			InterpolatedRemainingTime = Mathf.LerpUnclamped(interpolationInfo.FromBuffer.ReinterpretState<float>(interpolationInfo.Offset), interpolationInfo.ToBuffer.ReinterpretState<float>(interpolationInfo.Offset), interpolationInfo.Alpha);
 | |
| 		}
 | |
| 	}
 | |
| }
 |