Part of these game systems:
3D Player Controller
First/third person character controller with smooth movement, jumping, and slope handling using CharacterController.
How to Use
1
Attach to your player GameObject
2
Add a CharacterController component
3
Create an empty child at the feet for Ground Check
4
Set Ground Mask to your terrain layer
5
Sprint with Left Shift
Source Code
C#
using UnityEngine;
[RequireComponent(typeof(CharacterController))]
public class PlayerController3D : MonoBehaviour
{
[Header("Movement")]
[SerializeField] private float walkSpeed = 6f;
[SerializeField] private float sprintSpeed = 10f;
[SerializeField] private float rotationSpeed = 10f;
[Header("Jumping")]
[SerializeField] private float jumpHeight = 1.5f;
[SerializeField] private float gravity = -20f;
[Header("Ground Check")]
[SerializeField] private Transform groundCheck;
[SerializeField] private float groundDistance = 0.3f;
[SerializeField] private LayerMask groundMask;
[Header("Camera")]
[SerializeField] private Transform cameraTransform;
private CharacterController controller;
private Vector3 velocity;
private bool isGrounded;
private void Awake()
{
controller = GetComponent<CharacterController>();
if (cameraTransform == null)
cameraTransform = Camera.main.transform;
}
private void Update()
{
// Ground check
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if (isGrounded && velocity.y < 0f)
velocity.y = -2f;
// Input
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
Vector3 inputDir = new Vector3(h, 0f, v).normalized;
// Movement relative to camera
if (inputDir.magnitude >= 0.1f)
{
float targetAngle = Mathf.Atan2(inputDir.x, inputDir.z) * Mathf.Rad2Deg + cameraTransform.eulerAngles.y;
float angle = Mathf.LerpAngle(transform.eulerAngles.y, targetAngle, rotationSpeed * Time.deltaTime);
transform.rotation = Quaternion.Euler(0f, angle, 0f);
Vector3 moveDir = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
float speed = Input.GetKey(KeyCode.LeftShift) ? sprintSpeed : walkSpeed;
controller.Move(moveDir.normalized * speed * Time.deltaTime);
}
// Jump
if (Input.GetButtonDown("Jump") && isGrounded)
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
// Apply gravity
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
private void OnDrawGizmosSelected()
{
if (groundCheck != null)
{
Gizmos.color = isGrounded ? Color.green : Color.red;
Gizmos.DrawWireSphere(groundCheck.position, groundDistance);
}
}
}