LieutenantChampignon/Projet Unity/Lieutenant Champignon/Assets/BUT Project/Scripts/[starter]/Movement/PlayerMovement.cs

235 lines
7.9 KiB
C#
Executable File

using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
namespace BUT
{
[RequireComponent(typeof(CharacterController))]
public class PlayerMovement : MonoBehaviour
{
[SerializeField]
Movement m_Movement;
[SerializeField]
private bool altCameraManagement;
float m_CurrentSpeed;
public float CurrentSpeed
{
set
{
if (m_CurrentSpeed == value) return;
m_CurrentSpeed = value;
OnSpeedChange?.Invoke(m_CurrentSpeed);
}
get => m_CurrentSpeed;
}
bool m_IsSprinting;
public bool IsSprinting { set => m_IsSprinting = value; get => m_IsSprinting; }
private bool m_IsMoving;
public bool IsMoving
{
set
{
if (m_IsMoving == value) return;
m_IsMoving = value;
OnMovingChange?.Invoke(m_IsMoving);
}
get => m_IsMoving;
}
private Vector3 m_Direction;
public Vector3 Direction { set => m_Direction = value; get => m_Direction; }
public Vector3 FullDirection => (GroundRotationOffset * Direction * CurrentSpeed + Vector3.up * GravityVelocity);
private Quaternion m_GroundRotationOffset;
public Quaternion GroundRotationOffset { set => m_GroundRotationOffset = value; get => m_GroundRotationOffset; }
public const float GRAVITY = -9.31f;
private float m_GravityVelocity;
public float GravityVelocity { set => m_GravityVelocity = value; get => m_GravityVelocity; }
private int m_JumpNumber;
public int JumpNumber { set => m_JumpNumber = value; get => m_JumpNumber; }
[SerializeField]
float m_RayLenght;
[SerializeField]
LayerMask m_RayMask;
RaycastHit m_Hit;
private bool m_IsGrounded;
public bool IsGrounded
{
set
{
if (IsGrounded == value) return;
m_IsGrounded = value;
OnGroundedChange?.Invoke(m_IsGrounded);
}
get => m_IsGrounded;
}
private CharacterController m_CharacterController;
private Vector2 m_MovementInput;
private Vector3 m_MovementDirection;
public UnityEvent<float> OnSpeedChange;
public UnityEvent<bool> OnMovingChange;
public UnityEvent<bool> OnGroundedChange;
private void Awake()
{
m_CharacterController = GetComponent<CharacterController>();
}
public void MovingChanged(bool _moving)
{
OnMovingChange?.Invoke(_moving);
}
public void SpeedChanged(float _speed)
{
OnSpeedChange?.Invoke(_speed);
}
public void GroundedChanged(bool _grounded)
{
OnGroundedChange?.Invoke(_grounded);
}
private void OnDisable()
{
IsMoving = false;
}
private void OnEnable()
{
StartCoroutine(Moving());
}
IEnumerator Moving()
{
while (enabled)
{
if (m_MovementInput.magnitude > 0.1f)
{
if (!IsMoving)
{
IsMoving = true;
}
// clamp input magnitude
m_MovementInput = Vector3.ClampMagnitude(m_MovementInput, 1);
}
else if (IsMoving)
{
IsMoving = false;
}
ManageDirection();
ManageGravity();
if (IsMoving) ApplyRotation();
ApplyMovement();
yield return new WaitForFixedUpdate();
}
}
public void SetInputMove(InputAction.CallbackContext _context)
{
m_MovementInput = _context.ReadValue<Vector2>();
}
public void SetInputJump(InputAction.CallbackContext _context)
{
if (!_context.started || (!m_CharacterController.isGrounded && JumpNumber >= m_Movement.MaxJumpNumber)) return;
if (JumpNumber == 0) StartCoroutine(WaitForLanding());
JumpNumber++;
if (m_Movement.MinimazeJumpPower) GravityVelocity += m_Movement.JumpPower / JumpNumber;
else GravityVelocity += m_Movement.JumpPower;
}
IEnumerator WaitForLanding()
{
yield return new WaitUntil(() => !m_CharacterController.isGrounded);
yield return new WaitUntil(() => m_CharacterController.isGrounded);
JumpNumber = 0;
}
public void SetInputSprint(InputAction.CallbackContext _context)
{
IsSprinting = _context.started || _context.performed;
}
private void ManageDirection()
{
// set direction
m_MovementDirection = new Vector3(m_MovementInput.x, 0, m_MovementInput.y);
// modify direction according to camera view
m_MovementDirection = Camera.main.transform.TransformDirection(m_MovementDirection);
m_MovementDirection.y = transform.forward.y;
Debug.DrawRay(transform.position, -transform.up * m_RayLenght, Color.red);
if (Physics.Raycast(transform.position, -transform.up, out m_Hit, m_RayLenght, m_RayMask))
{
IsGrounded = true;
float angleOffset = Vector3.SignedAngle(transform.up, m_Hit.normal, transform.right);
GroundRotationOffset = Quaternion.AngleAxis(angleOffset, transform.right);
Debug.DrawRay(transform.position, GroundRotationOffset * m_MovementDirection, Color.green);
//m_MovementDirection = Quaternion.LookRotation(m_Hit.normal) * m_MovementDirection;
}
else
{
IsGrounded = m_CharacterController.isGrounded;
GroundRotationOffset = Quaternion.identity;
}
m_MovementDirection.Normalize();
Direction = m_MovementDirection;
Debug.DrawRay(transform.position, Direction, Color.red);
// calculate speed according to input force
CurrentSpeed = ((IsSprinting) ? m_Movement.SprintFactor : 1) * m_Movement.MaxSpeed * m_Movement.SpeedFactor.Evaluate(m_MovementInput.magnitude);
}
public void ApplyRotation()
{
if (!IsMoving) return;
// calculate target rotation
Quaternion targetRotation = Quaternion.LookRotation(Direction, transform.up);
// lerp toward the target rotation
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation,
m_Movement.MaxAngularSpeed * Mathf.Deg2Rad * m_Movement.AngularSpeedFactor.Evaluate(Direction.magnitude) * Time.deltaTime);
}
public void ApplyMovement()
{
Debug.DrawRay(transform.position, FullDirection, Color.yellow);
// move toward the direction with the current speed
m_CharacterController.Move(FullDirection * Time.deltaTime);
if (altCameraManagement) Camera.main.transform.position += Direction * CurrentSpeed * Time.deltaTime;
}
private void ManageGravity()
{
if (m_CharacterController.isGrounded && GravityVelocity < 0.0f)
{
// if grounded set back gravity velocity to a normal number
GravityVelocity = -1;
}
else
{
// if not grounded add gravity
GravityVelocity += GRAVITY * m_Movement.GravityMultiplier * Time.deltaTime;
}
}
}
}