using UnityEngine; /// /// Third-person controller for the T-Rex player character. /// Handles movement, rotation, camera follow, and basic animations. /// public class TrexController : MonoBehaviour { [Header("Movement")] [Tooltip("Walking speed in units per second")] public float walkSpeed = 5f; [Tooltip("Running speed when holding Shift")] public float runSpeed = 8f; [Tooltip("Rotation speed when turning")] public float rotationSpeed = 10f; [Tooltip("How much gravity affects the T-Rex")] public float gravity = -9.81f; [Header("Jumping")] [Tooltip("Jump velocity in units per second")] public float jumpHeight = 2f; [Tooltip("Ground check distance from feet")] public float groundCheckDistance = 0.4f; [Tooltip("Layer mask for what counts as ground")] public LayerMask groundLayer; [Header("Camera")] [Tooltip("Offset of camera behind and above T-Rex")] public Vector3 cameraOffset = new Vector3(0, 3f, -6f); [Tooltip("How smoothly camera follows")] public float cameraSmoothTime = 0.1f; [Tooltip("Enable mouse look for camera rotation")] public bool enableMouseLook = true; [Tooltip("Mouse sensitivity for looking around")] public float mouseSensitivity = 2f; [Header("References")] [Tooltip("Transform representing the T-Rex's feet position")] public Transform groundCheck; [Tooltip("The camera that follows the T-Rex")] public Camera mainCamera; [Tooltip("Animator component for playing animations")] public Animator animator; // Private variables private Vector3 velocity; private bool isGrounded; private float horizontalLook; private float verticalLook; private float currentHorizontalLook; private float currentVerticalLook; private CharacterController controller; private Vector3 cameraVelocity = Vector3.zero; void Start() { // Get or add CharacterController controller = GetComponent(); if (controller == null) { Debug.LogWarning("No CharacterController found! Adding one.", gameObject); controller = gameObject.AddComponent(); controller.height = 3f; controller.radius = 0.8f; } // Setup ground check if not assigned if (groundCheck == null) { groundCheck = new GameObject("GroundCheck").transform; groundCheck.SetParent(transform); groundCheck.localPosition = new Vector3(0, -controller.height / 2f + 0.1f, 0); } // Setup animator parameters if assigned if (animator != null) { animator.SetFloat("Speed", 0f); animator.SetBool("IsGrounded", true); } // Lock cursor on start Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; Debug.Log("🦖 T-Rex Controller initialized!"); } void Update() { HandleGroundCheck(); HandleMovement(); HandleCamera(); UpdateAnimator(); } void HandleGroundCheck() { isGrounded = Physics.CheckSphere(groundCheck.position, groundCheckDistance, groundLayer); if (isGrounded && velocity.y < 0) { velocity.y = -2f; // Small downward push to keep grounded } } void HandleMovement() { // Get input float horizontal = Input.GetAxis("Horizontal"); float vertical = Input.GetAxis("Vertical"); bool isRunning = Input.GetKey(KeyCode.LeftShift); bool wantsToJump = Input.GetButtonDown("Jump"); // Calculate movement direction relative to camera Vector3 moveDirection = CameraRelativeDirection(horizontal, vertical); // Apply speed float currentSpeed = isRunning ? runSpeed : walkSpeed; Vector3 movement = moveDirection * currentSpeed; // Handle jumping if (isGrounded && wantsToJump) { velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity); } // Apply gravity if (!isGrounded) { velocity.y += gravity * Time.deltaTime; movement.y = velocity.y; } else { movement.y = velocity.y; } // Move the character controller.Move(movement * Time.deltaTime); // Rotate T-Rex to face movement direction if (moveDirection.magnitude > 0.1f) { Quaternion targetRotation = Quaternion.LookRotation(moveDirection); transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime); } } Vector3 CameraRelativeDirection(float horizontal, float vertical) { if (mainCamera == null) { mainCamera = Camera.main; } Vector3 forward = mainCamera.transform.forward; Vector3 right = mainCamera.transform.right; // Remove vertical component forward.y = 0f; right.y = 0f; forward.Normalize(); right.Normalize(); return (forward * vertical + right * horizontal).normalized; } void HandleCamera() { if (mainCamera == null || !enableMouseLook) return; // Mouse look if (Input.GetMouseButton(1) || Cursor.lockState == CursorLockMode.Locked) { horizontalLook += Input.GetAxis("Mouse X") * mouseSensitivity; verticalLook -= Input.GetAxis("Mouse Y") * mouseSensitivity; // Clamp vertical look verticalLook = Mathf.Clamp(verticalLook, -60f, 60f); } // Smooth camera rotation currentHorizontalLook = Mathf.Lerp(currentHorizontalLook, horizontalLook, cameraSmoothTime * 10f); currentVerticalLook = Mathf.Lerp(currentVerticalLook, verticalLook, cameraSmoothTime * 10f); // Calculate target camera position Quaternion rotation = Quaternion.Euler(currentVerticalLook, currentHorizontalLook, 0f); Vector3 targetPosition = transform.position + transform.up * cameraOffset.y - rotation * Vector3.forward * cameraOffset.z; targetPosition += rotation * Vector3.right * cameraOffset.x; // Smooth camera movement mainCamera.transform.position = Vector3.SmoothDamp( mainCamera.transform.position, targetPosition, ref cameraVelocity, cameraSmoothTime ); // Camera always looks at T-Rex mainCamera.transform.LookAt(transform.position + Vector3.up * 2f); } void UpdateAnimator() { if (animator == null) return; float speed = Mathf.Abs(Input.GetAxis("Horizontal")) + Mathf.Abs(Input.GetAxis("Vertical")); animator.SetFloat("Speed", speed); animator.SetBool("IsGrounded", isGrounded); } // Debug visualization void OnDrawGizmosSelected() { // Draw ground check sphere if (groundCheck != null) { Gizmos.color = Color.green; Gizmos.DrawWireSphere(groundCheck.position, groundCheckDistance); } } }