186 lines
6.9 KiB
C#
Executable File
186 lines
6.9 KiB
C#
Executable File
using System;
|
|
using System.Runtime.CompilerServices;
|
|
using KinematicCharacterController;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
using Logger = RebootKit.Engine.Foundation.Logger;
|
|
|
|
namespace RealityReboot.jelycho.Player {
|
|
public class PlayerFPPLocomotion : MonoBehaviour, ICharacterController {
|
|
static readonly Logger s_logger = new(nameof(PlayerFPPLocomotion));
|
|
|
|
[SerializeField] KinematicCharacterMotor m_Motor;
|
|
|
|
public float runSpeed = 10.0f;
|
|
public float sprintSpeed = 20.0f;
|
|
|
|
public float groundAcceleration = 10.0f;
|
|
public float groundFriction = 10.0f;
|
|
|
|
public float airFriction = 1.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;
|
|
bool m_IsSprinting;
|
|
bool m_IsJumpRequested;
|
|
float m_JumpRequestedTime;
|
|
float m_LastGroundedTime;
|
|
|
|
Vector3 m_LastVelocity;
|
|
|
|
public bool IsGrounded => m_Motor.GroundingStatus.IsStableOnGround;
|
|
|
|
void Awake() {
|
|
m_Motor.CharacterController = this;
|
|
}
|
|
|
|
void OnDrawGizmos() {
|
|
Gizmos.color = Color.blue;
|
|
Gizmos.DrawLine(transform.position,
|
|
transform.position + m_WishDir * 2.0f);
|
|
}
|
|
|
|
void OnGUI() {
|
|
GUI.Label(new Rect(0, 0, Screen.width, Screen.height),
|
|
$"Wish Direction: {m_WishDir}\n" +
|
|
$"Is Grounded: {m_Motor.GroundingStatus.IsStableOnGround}\n" +
|
|
$"Is Jump Requested: {m_IsJumpRequested}\n" +
|
|
$"Motor Velocity: {m_Motor.Velocity}, magnitude: {m_Motor.Velocity.magnitude}\n" +
|
|
$"Motor Base Velocity: {m_Motor.BaseVelocity}, magnitude: {m_Motor.BaseVelocity.magnitude}\n" +
|
|
$"Last Velocity: {m_LastVelocity}, magnitude: {math.length(m_LastVelocity)}\n");
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void SetWishDirection(Vector3 dir) {
|
|
m_WishDir = dir;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Jump() {
|
|
m_IsJumpRequested = true;
|
|
m_JumpRequestedTime = Time.time;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void SetSprint(bool isSprinting) {
|
|
m_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 = groundAcceleration * deltaTime * wishSpeed;
|
|
if (accelSpeed > addSpeed) {
|
|
accelSpeed = addSpeed;
|
|
}
|
|
|
|
currentVelocity += accelSpeed * control * m_WishDir;
|
|
}
|
|
|
|
void ApplyFriction(ref Vector3 currentVelocity, float friction, float deltaTime) {
|
|
float speed = currentVelocity.magnitude;
|
|
if (speed <= 0.0f) {
|
|
return;
|
|
}
|
|
|
|
float drop = speed * friction * deltaTime;
|
|
if (drop < speed) {
|
|
currentVelocity *= (speed - drop) / speed;
|
|
} else {
|
|
currentVelocity = Vector3.zero;
|
|
}
|
|
}
|
|
|
|
void GroundMovement(ref Vector3 currentVelocity, float deltaTime) {
|
|
float wishSpeed = m_IsSprinting ? sprintSpeed : runSpeed;
|
|
Accelerate(ref currentVelocity, wishSpeed, 1.0f, deltaTime);
|
|
ApplyFriction(ref currentVelocity, groundFriction, 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 {
|
|
Accelerate(ref currentVelocity, runSpeed, airControl, deltaTime);
|
|
ApplyFriction(ref currentVelocity, airFriction, 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) {
|
|
}
|
|
}
|
|
} |