176 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using Fusion.Addons.KCC;
 | |
| using UnityEngine;
 | |
| 
 | |
| namespace TPSBR
 | |
| {
 | |
| 	public sealed class JetpackKCCProcessor : KCCProcessor, IKCCProcessor, IPrepareData
 | |
| 	{
 | |
| 		// PRIVATE MEMBERS
 | |
| 
 | |
| 		[SerializeField]
 | |
| 		private float _moveForce = 8f;
 | |
| 		[SerializeField]
 | |
| 		private float _moveDownForce = 8f;
 | |
| 		[SerializeField]
 | |
| 		private float _thrustUpForce = 20f;
 | |
| 		[SerializeField]
 | |
| 		private float _fullThrustUpForce = 30f;
 | |
| 		[SerializeField]
 | |
| 		private float _lookThrustForce = 2f;
 | |
| 		[SerializeField]
 | |
| 		private float _groundThrustImpulse = 1f;
 | |
| 		[SerializeField]
 | |
| 		private float _upThrustOppositeVelocityMultiplier = 0.2f;
 | |
| 		[SerializeField]
 | |
| 		private float _moveThrustOppositeVelocityMultiplier = 0.05f;
 | |
| 		[SerializeField]
 | |
| 		private float _gravityMultiplier = 1.5f;
 | |
| 		[SerializeField]
 | |
| 		private float _airPhysicsFriction = 0.001f;
 | |
| 		[SerializeField]
 | |
| 		private float _groundPhysicsFriction = 0.25f;
 | |
| 		[SerializeField]
 | |
| 		private float _moveVelocityDecreaseSpeed = 5f;
 | |
| 
 | |
| 		private bool    _hasJetpack;
 | |
| 		private Jetpack _jetpack;
 | |
| 
 | |
| 		// KCCProcessor INTERFACE
 | |
| 
 | |
| 		public override float GetPriority(KCC kcc) => float.MaxValue;
 | |
| 
 | |
| 		public override void OnEnter(KCC kcc, KCCData data)
 | |
| 		{
 | |
| 			_jetpack = kcc.GetComponent<Jetpack>();
 | |
| 			_hasJetpack = _jetpack != null;
 | |
| 		}
 | |
| 
 | |
| 		public void Execute(PrepareData stage, KCC kcc, KCCData data)
 | |
| 		{
 | |
| 			data.Gravity = Physics.gravity * _gravityMultiplier;
 | |
| 
 | |
| 			// We explicitly need data from fixed update.
 | |
| 			KCCData fixedData      = kcc.FixedData;
 | |
| 			float   fixedDeltaTime = fixedData.DeltaTime;
 | |
| 
 | |
| 			if (kcc.IsInFixedUpdate == false)
 | |
| 			{
 | |
| 				// Reset to fixed update values. Instead of partial render predicted velocity we calculate velocity for next fixed update.
 | |
| 				data.KinematicVelocity    = fixedData.KinematicVelocity;
 | |
| 				data.ExternalVelocity     = fixedData.ExternalVelocity;
 | |
| 				data.ExternalAcceleration = fixedData.ExternalAcceleration;
 | |
| 				data.ExternalImpulse      = fixedData.ExternalImpulse;
 | |
| 				data.ExternalForce        = fixedData.ExternalForce;
 | |
| 				data.DynamicVelocity      = fixedData.DynamicVelocity;
 | |
| 			}
 | |
| 
 | |
| 			data.KinematicDirection = data.InputDirection;
 | |
| 			data.KinematicTangent   = default;
 | |
| 
 | |
| 			if (data.KinematicDirection != default)
 | |
| 			{
 | |
| 				data.KinematicTangent = data.KinematicDirection.normalized;
 | |
| 			}
 | |
| 
 | |
| 			if (data.KinematicTangent == default)
 | |
| 			{
 | |
| 				data.KinematicTangent = data.TransformDirection;
 | |
| 			}
 | |
| 
 | |
| 			// Move velocity is only decreasing (e.g. after jetpack activation)
 | |
| 			data.KinematicVelocity = Vector3.Lerp(data.KinematicVelocity, default, fixedDeltaTime * _moveVelocityDecreaseSpeed);
 | |
| 
 | |
| 			float thrustForce = 0f;
 | |
| 
 | |
| 			if (_jetpack.IsRunning == true)
 | |
| 			{
 | |
| 				thrustForce = _jetpack.FullThrust == true ? _fullThrustUpForce : _thrustUpForce;
 | |
| 			}
 | |
| 
 | |
| 			data.ExternalForce += Vector3.up * thrustForce;
 | |
| 
 | |
| 			if (thrustForce > 0f && _jetpack.FullThrust == true && fixedData.RealVelocity.y < 0f)
 | |
| 			{
 | |
| 				data.ExternalVelocity += new Vector3(0f, -data.DynamicVelocity.y * _upThrustOppositeVelocityMultiplier, 0f);
 | |
| 			}
 | |
| 
 | |
| 			if (fixedData.IsGrounded == true && _jetpack.FullThrust == true)
 | |
| 			{
 | |
| 				data.ExternalImpulse += Vector3.up * _groundThrustImpulse;
 | |
| 			}
 | |
| 
 | |
| 			if (fixedData.IsGrounded == true && fixedData.IsSnappingToGround == false && data.DynamicVelocity.y < 0.0f && data.DynamicVelocity.OnlyXZ().IsAlmostZero())
 | |
| 			{
 | |
| 				data.DynamicVelocity.y = 0f;
 | |
| 			}
 | |
| 
 | |
| 			if (_lookThrustForce > 0f)
 | |
| 			{
 | |
| 				var lookDirection = data.LookRotation * Vector3.forward;
 | |
| 				data.ExternalForce += lookDirection * _lookThrustForce;
 | |
| 			}
 | |
| 
 | |
| 			if (_moveDownForce > 0f && data.InputDirection != default)
 | |
| 			{
 | |
| 				// Player is able to fly down faster
 | |
| 				var rawInputDirection = Quaternion.Inverse(data.TransformRotation) * data.InputDirection;
 | |
| 				var desiredDirection = data.LookRotation * rawInputDirection;
 | |
| 
 | |
| 				if (desiredDirection.y < 0f)
 | |
| 				{
 | |
| 					data.ExternalForce += Vector3.down * -desiredDirection.normalized.y * _moveDownForce;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (_moveForce > 0f && data.KinematicDirection != default)
 | |
| 			{
 | |
| 				var velocityXZ = fixedData.RealVelocity.OnlyXZ();
 | |
| 				float oppositeDirectionDot = Vector3.Dot(-velocityXZ.normalized, data.KinematicTangent);
 | |
| 
 | |
| 				if (oppositeDirectionDot > 0f)
 | |
| 				{
 | |
| 					data.ExternalVelocity += -velocityXZ * oppositeDirectionDot * _moveThrustOppositeVelocityMultiplier;
 | |
| 				}
 | |
| 
 | |
| 				data.ExternalForce += data.KinematicTangent * _moveForce;
 | |
| 			}
 | |
| 
 | |
| 			data.DynamicVelocity += data.Gravity * fixedDeltaTime;
 | |
| 
 | |
| 			data.DynamicVelocity += data.ExternalVelocity;
 | |
| 			data.DynamicVelocity += data.ExternalAcceleration * fixedDeltaTime;
 | |
| 			data.DynamicVelocity += (data.ExternalImpulse / kcc.Rigidbody.mass);
 | |
| 			data.DynamicVelocity += (data.ExternalForce / kcc.Rigidbody.mass) * fixedDeltaTime;
 | |
| 
 | |
| 			Vector3 velocityDirection = data.KinematicTangent;
 | |
| 			float speed = data.DynamicVelocity.magnitude;
 | |
| 
 | |
| 			if (speed > 0f)
 | |
| 			{
 | |
| 				velocityDirection = data.DynamicVelocity / speed;
 | |
| 			}
 | |
| 
 | |
| 			data.DynamicVelocity += -0.5f * (fixedData.IsGrounded == true ? _groundPhysicsFriction : _airPhysicsFriction) * velocityDirection * speed * speed;
 | |
| 
 | |
| 			if (kcc.IsInFixedUpdate == true)
 | |
| 			{
 | |
| 				// Consume one-time effects only in fixed update.
 | |
| 				// For render prediction we need them to be applied on top of fixed data in all frames.
 | |
| 				data.JumpImpulse      = default;
 | |
| 				data.ExternalVelocity = default;
 | |
| 				data.ExternalImpulse  = default;
 | |
| 			}
 | |
| 
 | |
| 			// Forces applied over-time are reset always. These are set every tick/frame.
 | |
| 			data.ExternalAcceleration = default;
 | |
| 			data.ExternalForce        = default;
 | |
| 
 | |
| 			kcc.SuppressProcessorsExcept(this, true);
 | |
| 		}
 | |
| 
 | |
| 		// IKCCProcessor INTERFACE
 | |
| 
 | |
| 		bool IKCCProcessor.IsActive(KCC kcc) => _hasJetpack == true && _jetpack.IsActive == true;
 | |
| 	}
 | |
| }
 |