Characters
This commit is contained in:
196
Game/Scripts/ThirdPersonCharacterController.cs
Normal file
196
Game/Scripts/ThirdPersonCharacterController.cs
Normal file
@@ -0,0 +1,196 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace MegaKoop.Game
|
||||
{
|
||||
[RequireComponent(typeof(UnityEngine.CharacterController))]
|
||||
public class ThirdPersonCharacterController : MonoBehaviour
|
||||
{
|
||||
[Header("Movement")]
|
||||
[SerializeField] private float moveSpeed = 5f;
|
||||
[SerializeField] private float rotationSharpness = 12f;
|
||||
|
||||
[Header("Air Control")]
|
||||
[SerializeField] private float airControlResponsiveness = 50f;
|
||||
|
||||
[Header("Jump")]
|
||||
[SerializeField] private float jumpHeight = 1.6f;
|
||||
[SerializeField] private float gravity = -20f;
|
||||
[SerializeField] private float groundedGravity = -5f;
|
||||
|
||||
[Header("Camera Reference")]
|
||||
[SerializeField] private Transform cameraTransform;
|
||||
|
||||
private UnityEngine.CharacterController characterController;
|
||||
private Vector3 planarVelocity;
|
||||
private float verticalVelocity;
|
||||
private bool isGrounded;
|
||||
private MegaKoop.Game.Networking.ICharacterInputSource inputSource;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
characterController = GetComponent<UnityEngine.CharacterController>();
|
||||
|
||||
if (cameraTransform == null)
|
||||
{
|
||||
Camera mainCamera = Camera.main;
|
||||
if (mainCamera != null)
|
||||
{
|
||||
cameraTransform = mainCamera.transform;
|
||||
}
|
||||
}
|
||||
|
||||
isGrounded = characterController.isGrounded;
|
||||
if (isGrounded)
|
||||
{
|
||||
verticalVelocity = groundedGravity;
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
Vector2 moveInput = ReadMovementInput();
|
||||
Vector3 desiredMove = CalculateDesiredMove(moveInput);
|
||||
bool hasMoveInput = desiredMove.sqrMagnitude > 0f;
|
||||
|
||||
UpdatePlanarVelocity(desiredMove, hasMoveInput);
|
||||
TryRotateTowardsMovement(desiredMove, hasMoveInput);
|
||||
|
||||
UpdateGroundedStateBeforeGravity();
|
||||
HandleJumpInput();
|
||||
ApplyGravity();
|
||||
|
||||
Vector3 velocity = planarVelocity;
|
||||
velocity.y = verticalVelocity;
|
||||
|
||||
CollisionFlags collisionFlags = characterController.Move(velocity * Time.deltaTime);
|
||||
isGrounded = (collisionFlags & CollisionFlags.Below) != 0;
|
||||
|
||||
if (isGrounded && verticalVelocity < 0f)
|
||||
{
|
||||
verticalVelocity = groundedGravity;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetInputSource(MegaKoop.Game.Networking.ICharacterInputSource source)
|
||||
{
|
||||
inputSource = source;
|
||||
}
|
||||
|
||||
private Vector2 ReadMovementInput()
|
||||
{
|
||||
if (inputSource != null)
|
||||
{
|
||||
Vector2 sourceInput = inputSource.MoveInput;
|
||||
return Vector2.ClampMagnitude(sourceInput, 1f);
|
||||
}
|
||||
|
||||
float horizontal = Input.GetAxisRaw("Horizontal");
|
||||
float vertical = Input.GetAxisRaw("Vertical");
|
||||
Vector2 input = new Vector2(horizontal, vertical);
|
||||
input = Vector2.ClampMagnitude(input, 1f);
|
||||
return input;
|
||||
}
|
||||
|
||||
private Vector3 CalculateDesiredMove(Vector2 input)
|
||||
{
|
||||
Vector3 forward = Vector3.forward;
|
||||
Vector3 right = Vector3.right;
|
||||
|
||||
if (cameraTransform != null)
|
||||
{
|
||||
forward = cameraTransform.forward;
|
||||
right = cameraTransform.right;
|
||||
}
|
||||
|
||||
forward.y = 0f;
|
||||
right.y = 0f;
|
||||
|
||||
forward.Normalize();
|
||||
right.Normalize();
|
||||
|
||||
Vector3 desiredMove = forward * input.y + right * input.x;
|
||||
if (desiredMove.sqrMagnitude > 1f)
|
||||
{
|
||||
desiredMove.Normalize();
|
||||
}
|
||||
|
||||
return desiredMove;
|
||||
}
|
||||
|
||||
private void UpdatePlanarVelocity(Vector3 desiredMove, bool hasMoveInput)
|
||||
{
|
||||
if (isGrounded)
|
||||
{
|
||||
planarVelocity = hasMoveInput ? desiredMove * moveSpeed : Vector3.zero;
|
||||
return;
|
||||
}
|
||||
|
||||
if (airControlResponsiveness <= 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 targetVelocity = hasMoveInput ? desiredMove * moveSpeed : Vector3.zero;
|
||||
float maxDelta = airControlResponsiveness * Time.deltaTime;
|
||||
planarVelocity = Vector3.MoveTowards(planarVelocity, targetVelocity, maxDelta);
|
||||
}
|
||||
|
||||
private void TryRotateTowardsMovement(Vector3 desiredMove, bool hasMoveInput)
|
||||
{
|
||||
if (!hasMoveInput)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Quaternion targetRotation = Quaternion.LookRotation(desiredMove, Vector3.up);
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSharpness * Time.deltaTime);
|
||||
}
|
||||
|
||||
private void UpdateGroundedStateBeforeGravity()
|
||||
{
|
||||
if (isGrounded && verticalVelocity < 0f)
|
||||
{
|
||||
verticalVelocity = groundedGravity;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleJumpInput()
|
||||
{
|
||||
if (!isGrounded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShouldJumpThisFrame())
|
||||
{
|
||||
verticalVelocity = Mathf.Sqrt(jumpHeight * -2f * gravity);
|
||||
isGrounded = false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldJumpThisFrame()
|
||||
{
|
||||
if (inputSource != null)
|
||||
{
|
||||
return inputSource.JumpPressed;
|
||||
}
|
||||
|
||||
return Input.GetButtonDown("Jump");
|
||||
}
|
||||
|
||||
private void ApplyGravity()
|
||||
{
|
||||
verticalVelocity += gravity * Time.deltaTime;
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
moveSpeed = Mathf.Max(0f, moveSpeed);
|
||||
rotationSharpness = Mathf.Max(0f, rotationSharpness);
|
||||
jumpHeight = Mathf.Max(0f, jumpHeight);
|
||||
airControlResponsiveness = Mathf.Max(0f, airControlResponsiveness);
|
||||
gravity = Mathf.Min(-0.01f, gravity);
|
||||
groundedGravity = Mathf.Clamp(groundedGravity, gravity, 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user