using UnityEngine;
using UnityEngine.InputSystem;
[RequireComponent(typeof(CharacterController))]
[RequireComponent(typeof(Animator))]
public class ThirdPersonController : MonoBehaviour
{
[Header("Movement Settings")]
public float walkSpeed = 2f;
public float runSpeed = 4f;
public float sprintSpeed = 6f;
public float turnSmoothTime = 0.15f;
[Header("Animation Settings")]
public float speedSmoothTime = 0.1f;
[Header("Jump & Gravity")]
public float jumpHeight = 1.2f;
public float gravity = -9.81f;
private CharacterController controller;
private Animator animator;
private Transform cameraTransform;
private float turnSmoothVelocity;
private float speedSmoothVelocity;
private float currentSpeed;
private Vector3 velocity;
private bool isGrounded;
private InputAction moveAction;
private InputAction jumpAction;
private InputAction sprintAction;
void Awake() {
moveAction = new InputAction("Move", binding: "<Gamepad>/leftStick");
moveAction.AddCompositeBinding("Dpad")
.With("Up", "<Keyboard>/w")
.With("Down", "<Keyboard>/s")
.With("Left", "<Keyboard>/a")
.With("Right", "<Keyboard>/d");
jumpAction = new InputAction("Jump", binding: "<Keyboard>/space");
jumpAction.AddBinding("<Gamepad>/buttonSouth");
sprintAction = new InputAction("Sprint", binding: "<Keyboard>/leftShift");
sprintAction.AddBinding("<Gamepad>leftTrigger");
}
void OnEnable()
{
moveAction.Enable();
jumpAction.Enable();
sprintAction.Enable();
}
void OnDisable()
{
moveAction.Disable();
jumpAction.Disable();
sprintAction.Disable();
}
void Start()
{
controller = GetComponent<CharacterController>();
animator = GetComponent<Animator>();
cameraTransform = Camera.main.transform;
}
void Update()
{
isGrounded = controller.isGrounded;
if(isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
Vector2 input = moveAction.ReadValue<Vector2>();
Vector3 direction = new Vector3(input.x, 0f, input.y).normalized;
float targetSpeed = 0f;
if(direction.magnitude >= 0.1f)
{
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + cameraTransform.eulerAngles.y;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
transform.rotation = Quaternion.Euler(0f, angle, 0f);
bool isSprinting = sprintAction.IsPressed();
targetSpeed = isSprinting ? sprintSpeed : runSpeed;
if(direction.magnitude < 0.5f) targetSpeed = walkSpeed;
}
currentSpeed = Mathf.SmoothDamp(currentSpeed, targetSpeed, ref speedSmoothVelocity, speedSmoothTime);
controller.Move(transform.forward * currentSpeed * Time.deltaTime);
if(jumpAction.triggered && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
animator.SetTrigger("Jump");
}
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
animator.SetFloat("Speed", currentSpeed);
animator.SetBool("isGrounded", isGrounded);
}
}