using UnityEngine; using UnityEngine.InputSystem; [RequireComponent(typeof(CharacterController))] public class BlobController : MonoBehaviour { private Transform playerCamera; [Header("Movement Speeds")] [SerializeField] private float walkSpeed = 5f; [SerializeField] private float sprintSpeed = 9f; [SerializeField] private float acceleration = 10f; [SerializeField] private float deceleration = 15f; [Header("Jump & Gravity")] [SerializeField] private float jumpHeight = 1.5f; [SerializeField] private float gravity = -20f; [SerializeField] private float groundedGravity = -2f; [Header("Camera Settings (3rd Person)")] [SerializeField] private float cameraDistance = 5f; [SerializeField] private float cameraHeightOffset = 1.5f; [SerializeField] private float cameraSmoothSpeed = 15f; [SerializeField] private float lookSensitivity = 0.2f; [SerializeField] private float minPitch = -20f; [SerializeField] private float maxPitch = 60f; [Header("Input Actions")] [SerializeField] private InputActionReference moveAction; [SerializeField] private InputActionReference sprintAction; [SerializeField] private InputActionReference jumpAction; [SerializeField] private InputActionReference lookAction; [Header("Shader / Material")] [Tooltip("Laissez vide pour chercher automatiquement le Renderer sur ce GameObject ou ses enfants.")] [SerializeField] private Renderer blobRenderer; [Tooltip("Vitesse d'interpolation des paramètres _Moving et _Jumping.")] [SerializeField] private float shaderTransitionSpeed = 5f; private Material blobMaterial; private readonly int movingPropertyID = Shader.PropertyToID("_Moving"); private readonly int jumpingPropertyID = Shader.PropertyToID("_Jumping"); private CharacterController controller; private Vector3 currentVelocity; private float verticalVelocity; private bool isGrounded; // Valeurs pour le shader private float currentMovingValue = 0f; private float currentJumpingValue = 0f; // Variables de contrôle de la caméra private float yaw = 0f; private float pitch = 15f; private Vector3 smoothedTargetFocusPoint; private bool isCameraInitialized = false; private void Awake() { controller = GetComponent(); if (Camera.main != null) { playerCamera = Camera.main.transform; } else { Debug.LogWarning("Aucune 'Main Camera' n'a été trouvée dans la scène !"); } if (blobRenderer == null) { blobRenderer = GetComponentInChildren(); } if (blobRenderer != null) { blobMaterial = blobRenderer.material; } // Verrouillage et masquage du curseur de la souris au démarrage Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } private void OnEnable() { if (moveAction != null) moveAction.action.Enable(); if (sprintAction != null) sprintAction.action.Enable(); if (jumpAction != null) jumpAction.action.Enable(); if (lookAction != null) lookAction.action.Enable(); } private void OnDisable() { if (moveAction != null) moveAction.action.Disable(); if (sprintAction != null) sprintAction.action.Disable(); if (jumpAction != null) jumpAction.action.Disable(); if (lookAction != null) lookAction.action.Disable(); } private void Update() { HandleGroundCheck(); HandleGravity(); HandleMovement(); UpdateShaderParameters(); } private void LateUpdate() { HandleCamera(); } private void HandleGroundCheck() { isGrounded = controller.isGrounded; if (isGrounded && verticalVelocity < 0.0f) { verticalVelocity = groundedGravity; } } private void HandleGravity() { if (isGrounded && jumpAction != null && jumpAction.action.triggered) { verticalVelocity = Mathf.Sqrt(jumpHeight * -2f * gravity); } verticalVelocity += gravity * Time.deltaTime; } private void HandleMovement() { Vector2 inputVector = moveAction != null ? moveAction.action.ReadValue() : Vector2.zero; if (playerCamera == null && Camera.main != null) { playerCamera = Camera.main.transform; } Vector3 forward = playerCamera ? playerCamera.forward : Vector3.forward; Vector3 right = playerCamera ? playerCamera.right : Vector3.right; forward.y = 0f; right.y = 0f; forward.Normalize(); right.Normalize(); Vector3 targetDirection = (forward * inputVector.y + right * inputVector.x).normalized; bool isSprinting = sprintAction != null && sprintAction.action.IsPressed(); float targetSpeed = isSprinting ? sprintSpeed : walkSpeed; if (inputVector.sqrMagnitude == 0f) { targetSpeed = 0f; } float currentAccel = (inputVector.sqrMagnitude > 0f) ? acceleration : deceleration; Vector3 targetVelocity3D = targetDirection * targetSpeed; currentVelocity.x = Mathf.MoveTowards(currentVelocity.x, targetVelocity3D.x, currentAccel * Time.deltaTime); currentVelocity.z = Mathf.MoveTowards(currentVelocity.z, targetVelocity3D.z, currentAccel * Time.deltaTime); Vector3 finalMovement = new Vector3(currentVelocity.x, verticalVelocity, currentVelocity.z); controller.Move(finalMovement * Time.deltaTime); if (targetDirection != Vector3.zero) { Quaternion targetRotation = Quaternion.LookRotation(targetDirection); transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, 15f * Time.deltaTime); } } private void HandleCamera() { if (playerCamera == null) return; Vector2 lookInput = lookAction != null ? lookAction.action.ReadValue() : Vector2.zero; yaw += lookInput.x * lookSensitivity; pitch -= lookInput.y * lookSensitivity; pitch = Mathf.Clamp(pitch, minPitch, maxPitch); Vector3 rawTargetFocusPoint = transform.position + Vector3.up * cameraHeightOffset; if (!isCameraInitialized) { smoothedTargetFocusPoint = rawTargetFocusPoint; isCameraInitialized = true; } else { smoothedTargetFocusPoint = Vector3.Lerp(smoothedTargetFocusPoint, rawTargetFocusPoint, cameraSmoothSpeed * Time.deltaTime); } Quaternion rotation = Quaternion.Euler(pitch, yaw, 0f); Vector3 finalCameraPosition = smoothedTargetFocusPoint - (rotation * Vector3.forward * cameraDistance); playerCamera.position = finalCameraPosition; playerCamera.rotation = rotation; } private void UpdateShaderParameters() { if (blobMaterial == null) return; Vector3 horizontalVelocity = new Vector3(currentVelocity.x, 0f, currentVelocity.z); float currentSpeed = horizontalVelocity.magnitude; float targetMovingValue = walkSpeed > 0.001f ? currentSpeed / walkSpeed : 0f; currentMovingValue = Mathf.MoveTowards(currentMovingValue, targetMovingValue, shaderTransitionSpeed * Time.deltaTime); blobMaterial.SetFloat(movingPropertyID, currentMovingValue); float targetJumpingValue = isGrounded ? 0f : 1f; currentJumpingValue = Mathf.MoveTowards(currentJumpingValue, targetJumpingValue, shaderTransitionSpeed * Time.deltaTime); blobMaterial.SetFloat(jumpingPropertyID, currentJumpingValue); } }