Characters

This commit is contained in:
2025-10-05 18:21:16 +02:00
parent b52b3aa830
commit 174a399ee7
77 changed files with 14406 additions and 0 deletions

View File

@@ -0,0 +1,204 @@
using UnityEngine;
namespace MegaKoop.Game
{
public class ThirdPersonCamera : MonoBehaviour
{
[Header("Target")]
[SerializeField] private Transform target;
[SerializeField] private Vector3 focusOffset = new Vector3(0f, 1.6f, 0f);
[Header("Orbit")]
[SerializeField] private float mouseSensitivity = 180f;
[SerializeField] private float minPitch = -35f;
[SerializeField] private float maxPitch = 75f;
[SerializeField] private float rotationSmoothTime = 0.1f;
[Header("Distance")]
[SerializeField] private float distance = 5f;
[SerializeField] private float minDistance = 2f;
[SerializeField] private float maxDistance = 8f;
[SerializeField] private float zoomSpeed = 4f;
[SerializeField] private float distanceSmoothTime = 0.1f;
[Header("Collision")]
[SerializeField] private float obstructionRadius = 0.25f;
[SerializeField] private LayerMask obstructionMask = ~0;
[SerializeField] private float obstructionBuffer = 0.1f;
[Header("Cursor")]
[SerializeField] private bool lockCursor = true;
private Vector2 orbitAngles = new Vector2(20f, 0f);
private Vector2 currentOrbitAngles;
private float pitchVelocity;
private float yawVelocity;
private float desiredDistance;
private float distanceVelocity;
private static readonly RaycastHit[] ObstructionHits = new RaycastHit[8];
private void OnEnable()
{
desiredDistance = Mathf.Clamp(distance, minDistance, maxDistance);
distance = desiredDistance;
currentOrbitAngles = orbitAngles;
pitchVelocity = yawVelocity = 0f;
if (lockCursor)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
}
private void OnDisable()
{
if (lockCursor)
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
}
private void LateUpdate()
{
if (target == null)
{
return;
}
float deltaTime = Time.deltaTime;
ReadOrbitInput(deltaTime);
ReadZoomInput();
if (rotationSmoothTime <= 0f)
{
currentOrbitAngles = orbitAngles;
pitchVelocity = yawVelocity = 0f;
}
else
{
currentOrbitAngles.x = Mathf.SmoothDamp(currentOrbitAngles.x, orbitAngles.x, ref pitchVelocity, rotationSmoothTime, Mathf.Infinity, deltaTime);
currentOrbitAngles.y = Mathf.SmoothDamp(currentOrbitAngles.y, orbitAngles.y, ref yawVelocity, rotationSmoothTime, Mathf.Infinity, deltaTime);
}
Quaternion lookRotation = Quaternion.Euler(currentOrbitAngles.x, currentOrbitAngles.y, 0f);
Vector3 focusPoint = target.TransformPoint(focusOffset);
float smoothedDistance;
if (distanceSmoothTime <= 0f)
{
distanceVelocity = 0f;
smoothedDistance = desiredDistance;
}
else
{
smoothedDistance = Mathf.SmoothDamp(distance, desiredDistance, ref distanceVelocity, distanceSmoothTime, Mathf.Infinity, deltaTime);
}
float unobstructedDistance = smoothedDistance;
float adjustedDistance = ResolveObstructions(focusPoint, lookRotation, unobstructedDistance);
float finalDistance = Mathf.Min(unobstructedDistance, adjustedDistance);
Vector3 finalPosition = focusPoint - lookRotation * Vector3.forward * finalDistance;
transform.SetPositionAndRotation(finalPosition, lookRotation);
distance = finalDistance;
}
private void ReadOrbitInput(float deltaTime)
{
float lookX = Input.GetAxis("Mouse X");
float lookY = Input.GetAxis("Mouse Y");
if (Mathf.Abs(lookX) > 0.0001f || Mathf.Abs(lookY) > 0.0001f)
{
orbitAngles.y += lookX * mouseSensitivity * deltaTime;
orbitAngles.x -= lookY * mouseSensitivity * deltaTime;
orbitAngles.x = Mathf.Clamp(orbitAngles.x, minPitch, maxPitch);
}
}
private void ReadZoomInput()
{
float scroll = Input.GetAxis("Mouse ScrollWheel");
if (Mathf.Abs(scroll) > 0.0001f)
{
desiredDistance = Mathf.Clamp(desiredDistance - scroll * zoomSpeed, minDistance, maxDistance);
}
else
{
desiredDistance = Mathf.Clamp(desiredDistance, minDistance, maxDistance);
}
}
private float ResolveObstructions(Vector3 focusPoint, Quaternion lookRotation, float targetDistance)
{
if (targetDistance <= 0.001f)
{
return targetDistance;
}
Vector3 direction = lookRotation * Vector3.back;
int hitCount = Physics.SphereCastNonAlloc(focusPoint, obstructionRadius, direction, ObstructionHits, targetDistance, obstructionMask, QueryTriggerInteraction.Ignore);
if (hitCount == 0)
{
return targetDistance;
}
float closestDistance = targetDistance;
for (int i = 0; i < hitCount; i++)
{
RaycastHit hit = ObstructionHits[i];
if (hit.collider == null)
{
continue;
}
Transform hitTransform = hit.collider.transform;
if (target != null && (hitTransform == target || hitTransform.IsChildOf(target)))
{
continue;
}
if (hit.distance < closestDistance)
{
closestDistance = Mathf.Max(0f, hit.distance - obstructionBuffer);
}
}
return closestDistance;
}
public void SetTarget(Transform newTarget)
{
target = newTarget;
}
private void OnValidate()
{
minPitch = Mathf.Clamp(minPitch, -89f, 89f);
maxPitch = Mathf.Clamp(maxPitch, -89f, 89f);
if (maxPitch < minPitch)
{
float temp = maxPitch;
maxPitch = minPitch;
minPitch = temp;
}
mouseSensitivity = Mathf.Max(0f, mouseSensitivity);
zoomSpeed = Mathf.Max(0f, zoomSpeed);
obstructionRadius = Mathf.Max(0f, obstructionRadius);
obstructionBuffer = Mathf.Clamp(obstructionBuffer, 0f, 1f);
rotationSmoothTime = Mathf.Max(0f, rotationSmoothTime);
distanceSmoothTime = Mathf.Max(0f, distanceSmoothTime);
minDistance = Mathf.Max(0.1f, minDistance);
maxDistance = Mathf.Max(minDistance, maxDistance);
distance = Mathf.Clamp(distance, minDistance, maxDistance);
desiredDistance = Mathf.Clamp(distance, minDistance, maxDistance);
currentOrbitAngles = orbitAngles;
pitchVelocity = yawVelocity = 0f;
}
}
}