Files
Deroc_Virtual_3D/Assets/StarterAssets/FirstPersonController/Scripts/FirstPersonController.cs
T
Alex38Lyon d4b7efa424 update
2025-06-03 09:56:26 +02:00

373 lines
10 KiB
C#

using UnityEngine;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
#endif
namespace StarterAssets
{
[RequireComponent(typeof(CharacterController))]
#if ENABLE_INPUT_SYSTEM
[RequireComponent(typeof(PlayerInput))]
#endif
public class FirstPersonController : MonoBehaviour
{
[Header("Player")]
public float StandingSpeed = 4.0f;
private float MoveSpeed = 4.0f;
public float SprintSpeed = 6.0f;
public float RotationSpeed = 1.0f;
public float SpeedChangeRate = 10.0f;
[Space(10)]
public float JumpHeight = 1.2f;
public float Gravity = -15.0f;
[Space(10)]
public float JumpTimeout = 0.1f;
public float FallTimeout = 0.15f;
[Header("Posture Heights")]
[Tooltip("Height when standing")]
public float StandingHeight = 1.8f;
[Tooltip("Height when crouching")]
public float CrouchHeight = 1.2f;
[Tooltip("Height when crawling")]
public float CrawlHeight = 0.8f;
[Header("Player Grounded")]
public bool Grounded = true;
public float GroundedOffset = -0.14f;
public float GroundedRadius = 0.5f;
public LayerMask GroundLayers;
[Header("Cinemachine")]
public GameObject CinemachineCameraTarget;
public float TopClamp = 90.0f;
public float BottomClamp = -90.0f;
private float _cinemachineTargetPitch;
private float _speed;
private float _rotationVelocity;
private float _verticalVelocity;
private float _terminalVelocity = 53.0f;
private float _jumpTimeoutDelta;
private float _fallTimeoutDelta;
#if ENABLE_INPUT_SYSTEM
private PlayerInput _playerInput;
#endif
private CharacterController _controller;
private StarterAssetsInputs _input;
private GameObject _mainCamera;
private const float _threshold = 0.01f;
// Posture state
private enum PlayerPosture { Standing, Crouching, Crawling }
private PlayerPosture _currentPosture = PlayerPosture.Standing;
private PlayerPosture _OldPosture = PlayerPosture.Standing;
private bool IsCurrentDeviceMouse
{
get
{
#if ENABLE_INPUT_SYSTEM
return _playerInput.currentControlScheme == "KeyboardMouse";
#else
return false;
#endif
}
}
private void Awake()
{
if (_mainCamera == null)
{
_mainCamera = GameObject.FindGameObjectWithTag("MainCamera");
}
}
private void Start()
{
MoveSpeed = StandingSpeed;
_controller = GetComponent<CharacterController>();
_input = GetComponent<StarterAssetsInputs>();
#if ENABLE_INPUT_SYSTEM
_playerInput = GetComponent<PlayerInput>();
#else
Debug.LogError("Starter Assets package is missing dependencies.");
#endif
_jumpTimeoutDelta = JumpTimeout;
_fallTimeoutDelta = FallTimeout;
// Initialise posture
SetPosture(PlayerPosture.Standing);
}
private void Update()
{
JumpAndGravity();
GroundedCheck();
HandlePosture();
Move();
}
private void LateUpdate()
{
CameraRotation();
}
private void GroundedCheck()
{
Vector3 spherePosition = new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z);
Grounded = Physics.CheckSphere(spherePosition, GroundedRadius, GroundLayers, QueryTriggerInteraction.Ignore);
}
private void CameraRotation()
{
if (_input.look.sqrMagnitude >= _threshold)
{
float deltaTimeMultiplier = IsCurrentDeviceMouse ? 1.0f : Time.deltaTime;
_cinemachineTargetPitch += _input.look.y * RotationSpeed * deltaTimeMultiplier;
_rotationVelocity = _input.look.x * RotationSpeed * deltaTimeMultiplier;
_cinemachineTargetPitch = ClampAngle(_cinemachineTargetPitch, BottomClamp, TopClamp);
CinemachineCameraTarget.transform.localRotation = Quaternion.Euler(_cinemachineTargetPitch, 0.0f, 0.0f);
transform.Rotate(Vector3.up * _rotationVelocity);
}
}
private void Move()
{
float targetSpeed = _input.sprint ? SprintSpeed : MoveSpeed;
if (_input.move == Vector2.zero) targetSpeed = 0.0f;
float currentHorizontalSpeed = new Vector3(_controller.velocity.x, 0.0f, _controller.velocity.z).magnitude;
float speedOffset = 0.1f;
float inputMagnitude = _input.analogMovement ? _input.move.magnitude : 1f;
if (currentHorizontalSpeed < targetSpeed - speedOffset || currentHorizontalSpeed > targetSpeed + speedOffset)
{
_speed = Mathf.Lerp(currentHorizontalSpeed, targetSpeed * inputMagnitude, Time.deltaTime * SpeedChangeRate);
_speed = Mathf.Round(_speed * 1000f) / 1000f;
}
else
{
_speed = targetSpeed;
}
Vector3 inputDirection = new Vector3(_input.move.x, 0.0f, _input.move.y).normalized;
if (_input.move != Vector2.zero)
{
inputDirection = transform.right * _input.move.x + transform.forward * _input.move.y;
}
_controller.Move(inputDirection.normalized * (_speed * Time.deltaTime) + new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);
}
private void JumpAndGravity()
{
if (Grounded)
{
_fallTimeoutDelta = FallTimeout;
if (_verticalVelocity < 0.0f)
{
_verticalVelocity = -2f;
}
if (_input.jump && _jumpTimeoutDelta <= 0.0f)
{
_verticalVelocity = Mathf.Sqrt(JumpHeight * -2f * Gravity);
}
if (_jumpTimeoutDelta >= 0.0f)
{
_jumpTimeoutDelta -= Time.deltaTime;
}
}
else
{
_jumpTimeoutDelta = JumpTimeout;
if (_fallTimeoutDelta >= 0.0f)
{
_fallTimeoutDelta -= Time.deltaTime;
}
_input.jump = false;
}
if (_verticalVelocity < _terminalVelocity)
{
_verticalVelocity += Gravity * Time.deltaTime;
}
}
private void HandlePosture()
{
// Appui sur 'C' : Passage entre Crouch et Standing
if (_input.crouch)
{
// Debug.Log("_input.crouch : " + _input.crouch);
_input.crouch = false;
if (_currentPosture == PlayerPosture.Crouching)
{
// Vérification de la hauteur du plafond avant de se redresser
if (CheckCeilingHeight() >= StandingHeight)
{
SetPosture(PlayerPosture.Standing);
}
else
{
Debug.Log("Pas assez de hauteur pour se lever.");
}
}
else if (_currentPosture == PlayerPosture.Standing || _currentPosture == PlayerPosture.Crawling )
{
if (CheckCeilingHeight() >= CrouchHeight)
{
SetPosture(PlayerPosture.Crouching);
}
else
{
Debug.Log("Pas assez de hauteur pour se baisser.");
}
}
}
// Appui sur 'V' : Passage entre Crawl et Standing
if (_input.crawl)
{
// Debug.Log("_input.crawl : " + _input.crawl);
_input.crawl = false;
if (_currentPosture == PlayerPosture.Crawling)
{
// Vérification de la hauteur du plafond avant de se redresser
if (CheckCeilingHeight() >= StandingHeight)
{
SetPosture(PlayerPosture.Standing);
}
else
{
Debug.Log("Pas assez de hauteur pour se lever.");
if (CheckCeilingHeight() >= CrouchHeight)
{
SetPosture(PlayerPosture.Crouching);
}
else
{
Debug.Log("Pas assez de hauteur pour se baisser.");
}
}
}
else if (_currentPosture == PlayerPosture.Standing)
{
SetPosture(PlayerPosture.Crawling);
}
else if (_currentPosture == PlayerPosture.Crouching)
{
SetPosture(PlayerPosture.Crawling);
}
}
}
private float CheckCeilingHeight()
{
// Calculer la position de la tête, qui est à la hauteur maximale de la capsule
Vector3 headPosition = transform.position + Vector3.up * (_controller.height / 2);
// Effectuer un rayon vers le haut à partir de la position de la tête
RaycastHit hit;
if (Physics.Raycast(headPosition, Vector3.up, out hit, 2f))
{
// Si le rayon touche un objet, on retourne la distance entre la tête et le plafond
Debug.Log ("hit.distance : " + hit.distance + ", headPosition : " + headPosition);
return 10.0f;
// return hit.distance;
}
return 10.0f;
// return Mathf.Infinity; // Si rien n'est touché, on considère qu'il n'y a pas de plafond
}
private void SetPosture(PlayerPosture posture)
{
float h=0.0f;
_OldPosture = _currentPosture;
_currentPosture = posture;
if ( _OldPosture == PlayerPosture.Standing) h = StandingHeight;
else if ( _OldPosture == PlayerPosture.Crouching) h = CrouchHeight;
else if ( _OldPosture == PlayerPosture.Crawling) h = CrawlHeight;
Debug.Log ("_OldPosture : " + _OldPosture + ", _currentPosture : " + _currentPosture);
switch (posture)
{
case PlayerPosture.Standing:
_controller.height = StandingHeight;
_controller.center = new Vector3(0.0f, StandingHeight / 2.0f, 0.0f);
MoveSpeed = StandingSpeed;
CinemachineCameraTarget.transform.position = new Vector3(
CinemachineCameraTarget.transform.position.x,
CinemachineCameraTarget.transform.position.y + StandingHeight - h,
CinemachineCameraTarget.transform.position.z
);
break;
case PlayerPosture.Crouching:
_controller.height = CrouchHeight;
_controller.center = new Vector3(0.0f, CrouchHeight / 2.0f, 0.0f);
MoveSpeed = StandingSpeed*0.6f;
CinemachineCameraTarget.transform.position = new Vector3(
CinemachineCameraTarget.transform.position.x,
CinemachineCameraTarget.transform.position.y + CrouchHeight - h,
CinemachineCameraTarget.transform.position.z
);
break;
case PlayerPosture.Crawling:
_controller.height = CrawlHeight;
_controller.center = new Vector3(0.0f, CrawlHeight / 2.0f, 0.0f);
MoveSpeed = StandingSpeed*0.4f;
CinemachineCameraTarget.transform.position = new Vector3(
CinemachineCameraTarget.transform.position.x,
CinemachineCameraTarget.transform.position.y + CrawlHeight - h,
CinemachineCameraTarget.transform.position.z
);
break;
}
}
private static float ClampAngle(float lfAngle, float lfMin, float lfMax)
{
if (lfAngle < -360f) lfAngle += 360f;
if (lfAngle > 360f) lfAngle -= 360f;
return Mathf.Clamp(lfAngle, lfMin, lfMax);
}
private void OnDrawGizmosSelected()
{
Color transparentGreen = new Color(0.0f, 1.0f, 0.0f, 0.35f);
Color transparentRed = new Color(1.0f, 0.0f, 0.0f, 0.35f);
Gizmos.color = Grounded ? transparentGreen : transparentRed;
Gizmos.DrawSphere(new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z), GroundedRadius);
}
}
}