Files
jelito/Assets/jelycho/Code/Player/PlayerFPPLocomotion.cs

265 lines
9.2 KiB
C#
Executable File

using System.Runtime.CompilerServices;
using RebootKit.Engine.Extensions;
using RebootKit.Engine.Foundation;
using RebootReality.jelycho.KinematicCharacterController.Core;
using Unity.Mathematics;
using UnityEngine;
using Logger = RebootKit.Engine.Foundation.Logger;
namespace RebootReality.jelycho.Player {
public class PlayerFPPLocomotion : MonoBehaviour, ICharacterController {
static readonly Logger s_Logger = new Logger(nameof(PlayerFPPLocomotion));
[ConfigVar("fpp.show_debug", 1)]
static ConfigVar s_showDebug;
[SerializeField] KinematicCharacterMotor m_Motor;
public float runSpeed = 10.0f;
public float sprintSpeed = 20.0f;
public float acceleration = 8.0f;
public float groundFriction = 10.0f;
public float jumpHeight = 2.0f;
public float jumpInputDuration = 0.2f;
public float coyoteDuration = 0.2f;
[Range(0.0f, 1.0f)] public float airControl = 0.5f;
public float gravity = 9.8f;
public float YawRotation { get; set; }
Vector3 m_WishDir;
public bool IsSprinting {
[MethodImpl(MethodImplOptions.AggressiveInlining)] get;
[MethodImpl(MethodImplOptions.AggressiveInlining)] private set;
}
bool m_IsJumpRequested;
float m_JumpRequestedTime;
float m_LastGroundedTime;
Vector3 m_LastVelocity;
public bool IsGrounded {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get {
return m_Motor.GroundingStatus.IsStableOnGround;
}
}
public float SpeedXZ {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get {
return m_Motor.Velocity.With(y: 0.0f).magnitude;
}
}
public Vector3 LocalVelocity {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get {
return transform.InverseTransformDirection(m_LastVelocity);
}
}
public Vector3 Velocity {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get {
return m_LastVelocity;
}
}
void Awake() {
m_Motor.CharacterController = this;
}
void OnDrawGizmos() {
Gizmos.color = Color.blue;
Gizmos.DrawLine(transform.position,
transform.position + m_WishDir * 2.0f);
}
static GUIStyle s_debugLabelStyle;
void OnGUI() {
if (s_showDebug.IndexValue == 0) {
return;
}
if (s_debugLabelStyle == null) {
s_debugLabelStyle = new GUIStyle(GUI.skin.label) {
fontSize = 20,
normal = { textColor = Color.white },
alignment = TextAnchor.LowerLeft
};
}
GUI.Label(new Rect(0, 0, Screen.width, Screen.height),
$"Is Grounded: {m_Motor.GroundingStatus.IsStableOnGround.ToString()}\n" +
$"Motor Velocity: {m_Motor.Velocity}, magnitude: {m_Motor.Velocity.magnitude}\n" +
$"XZ Motor Velocity: {m_Motor.Velocity.With(y: 0.0f).magnitude}",
s_debugLabelStyle);
}
public void WarpTo(float3 position) {
m_Motor.SetPosition(position);
m_LastGroundedTime = 0.0f;
m_IsJumpRequested = false;
m_JumpRequestedTime = 0.0f;
m_WishDir = Vector3.zero;
m_LastVelocity = Vector3.zero;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetWishDirection(Vector3 dir) {
m_WishDir = dir.normalized;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Jump() {
m_IsJumpRequested = true;
m_JumpRequestedTime = Time.time;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetSprint(bool isSprinting) {
IsSprinting = isSprinting;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static float CalculateJumpVelocity(float jumpHeight, float gravity) {
return math.sqrt(2.0f * gravity * jumpHeight);
}
public void UpdateRotation(ref Quaternion currentRotation, float deltaTime) {
currentRotation = Quaternion.AngleAxis(YawRotation, Vector3.up);
}
void Accelerate(ref Vector3 currentVelocity,
float wishSpeed,
float control,
float deltaTime) {
float currentSpeed = Vector3.Dot(currentVelocity, m_WishDir);
float addSpeed = wishSpeed - currentSpeed;
if (addSpeed <= 0.0f) {
return;
}
float accelSpeed = acceleration * deltaTime * wishSpeed;
if (accelSpeed > addSpeed) {
accelSpeed = addSpeed;
}
currentVelocity += accelSpeed * control * m_WishDir;
}
void AirAccelerate(ref Vector3 currentVelocity,
float deltaTime) {
float wishSpeed = currentVelocity.magnitude;
if (wishSpeed >= runSpeed) {
wishSpeed = runSpeed;
}
float currentSpeed = Vector3.Dot(currentVelocity, m_WishDir);
float addSpeed = wishSpeed - currentSpeed;
if (addSpeed <= 0.0f) {
return;
}
float accelSpeed = deltaTime * wishSpeed;
if (accelSpeed > addSpeed) {
accelSpeed = addSpeed;
}
currentVelocity += accelSpeed * m_WishDir;
}
void ApplyFriction(ref Vector3 currentVelocity, float friction, float deltaTime) {
float speed = currentVelocity.With(y: 0.0f).magnitude;
if (speed <= 0.0f) {
return;
}
float stopSpeed = 12.0f;
float control = speed < stopSpeed ? stopSpeed : speed;
float newSpeed = speed - friction * control * deltaTime;
if (newSpeed <= 0.0f) {
newSpeed = 0.0f;
}
newSpeed /= speed;
currentVelocity.x *= newSpeed;
currentVelocity.z *= newSpeed;
}
void GroundMovement(ref Vector3 currentVelocity, float deltaTime) {
float wishSpeed = IsSprinting ? sprintSpeed : runSpeed;
ApplyFriction(ref currentVelocity, groundFriction, deltaTime);
Accelerate(ref currentVelocity, wishSpeed, 1.0f, deltaTime);
}
void ApplyGravity(ref Vector3 currentVelocity, float deltaTime) {
currentVelocity.y -= gravity * deltaTime;
}
public void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime) {
if (Time.time > m_JumpRequestedTime + jumpInputDuration) {
m_IsJumpRequested = false;
}
if (m_Motor.GroundingStatus.IsStableOnGround) {
m_LastGroundedTime = Time.time;
}
bool canJump = m_Motor.GroundingStatus.IsStableOnGround ||
Time.time < m_LastGroundedTime + coyoteDuration;
if (m_IsJumpRequested && canJump) {
currentVelocity.y = CalculateJumpVelocity(jumpHeight, gravity);
m_Motor.ForceUnground();
m_IsJumpRequested = false;
m_LastGroundedTime = 0.0f;
}
if (m_Motor.GroundingStatus.IsStableOnGround) {
GroundMovement(ref currentVelocity, deltaTime);
} else {
AirAccelerate(ref currentVelocity, deltaTime);
ApplyGravity(ref currentVelocity, deltaTime);
}
m_LastVelocity = currentVelocity;
}
public void BeforeCharacterUpdate(float deltaTime) {
}
public void PostGroundingUpdate(float deltaTime) {
}
public void AfterCharacterUpdate(float deltaTime) {
}
public bool IsColliderValidForCollisions(Collider coll) {
return true;
}
public void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) {
}
public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) {
}
public void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport) {
}
public void OnDiscreteCollisionDetected(Collider hitCollider) {
}
}
}