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;
|
|
}
|
|
}
|