Skip to content

Instantly share code, notes, and snippets.

@pppoe252110
Last active June 28, 2023 05:20
Show Gist options
  • Save pppoe252110/b2f512b5efb4ac71c1de04c6305cc699 to your computer and use it in GitHub Desktop.
Save pppoe252110/b2f512b5efb4ac71c1de04c6305cc699 to your computer and use it in GitHub Desktop.
Third Person Camera Controller
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Serialization;
public class ThirdPersonCameraController : MonoBehaviour
{
[SerializeField, FormerlySerializedAs("Camera Target")] private Transform target;
[Header("View")]
[SerializeField, FormerlySerializedAs("View Sensitivity")] private float _viewSensitivity = 3f;
[SerializeField, FormerlySerializedAs("Scroll Sensitivity")] private float _scrollSensitivity = 3f;
[SerializeField, FormerlySerializedAs("Maximum Verical Angle")] private float _maxVericalAngle = 70f;
[SerializeField, FormerlySerializedAs("Minimum Verical Angle")] private float _minVericalAngle = -30f;
[SerializeField, FormerlySerializedAs("Maximum Distance")] private float _maxDistance = 5f;
[SerializeField, FormerlySerializedAs("Minimum Distance")] private float _minDistance = 3f;
[SerializeField, FormerlySerializedAs("Forward Offset")] private float _forwardOffset = 0.1f;
[SerializeField, FormerlySerializedAs("View Offset")] private Vector2 _viewOffset = new Vector2(0.5f, 0);
[Header("Rays")]
[SerializeField, FormerlySerializedAs("Rays Distance From Center")] private float _raysDistance = 0.2f;
[SerializeField, FormerlySerializedAs("Rays")] private Vector2[] _rays;
[SerializeField, FormerlySerializedAs("Ignore Layer")] private LayerMask _ignoreLayer;
private float currentDistance = 5f;
public void Reset()
{
_rays = new Vector2[9];
for (int i = 0; i < _rays.Length; i++)
{
_rays[i] = new Vector2(Mathf.Cos(i * 45f * Mathf.Deg2Rad), Mathf.Sin(i * 45f * Mathf.Deg2Rad));
}
_rays[8] = Vector2.zero;
}
private void Update()
{
currentDistance = Mathf.Clamp(currentDistance - Input.GetAxis("Mouse ScrollWheel") * _scrollSensitivity, _minDistance, _maxDistance);
transform.rotation = Quaternion.Euler(Mathf.Clamp(FixAngle(transform.rotation.eulerAngles.x - Input.GetAxis("Mouse Y") * _viewSensitivity), _minVericalAngle, _maxVericalAngle), transform.eulerAngles.y + Input.GetAxis("Mouse X") * _viewSensitivity, transform.eulerAngles.z);
}
private void LateUpdate()
{
List<RaycastHit> hits = new List<RaycastHit>();
Vector3 targetDir = GetTargetDirection();
for (int i = 0; i < _rays.Length; i++)
{
var rayPos = GetRayPos(i);
if (Physics.Raycast(rayPos, targetDir, out var hit, currentDistance, ~_ignoreLayer))
{
hits.Add(hit);
}
}
if (hits.Count > 0)
{
var closest = hits.Min(a => a.distance);
UpdateView(closest);
}
else
{
UpdateView(currentDistance);
}
}
public Vector3 GetRayPos(int i)
{
return target.position + transform.rotation * new Vector2(_rays[i].x * _raysDistance, _rays[i].y * _raysDistance);
}
public float FixAngle(float angle)
{
if (angle > 180)
return angle - 360f;
if (angle < -180)
return angle + 360f;
return angle;
}
public Vector3 GetTargetPosition()
{
return transform.rotation * new Vector3(_viewOffset.x, _viewOffset.y, -_maxDistance) + target.position;
}
public Vector3 GetTargetDirection()
{
var targetDir = GetTargetPosition() - target.position;
targetDir.Normalize();
return targetDir;
}
public void UpdateView(float distance)
{
Vector3 targetDir = GetTargetDirection();
transform.position = targetDir * distance + target.position + transform.forward * _forwardOffset;
}
#if UNITY_EDITOR
private void OnDrawGizmos()
{
for (int i = 0; i < _rays.Length; i++)
{
var rayPos = GetRayPos(i);
Gizmos.DrawRay(rayPos, transform.rotation * new Vector3(_viewOffset.x, _viewOffset.y, -currentDistance));
}
}
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment