mirror of
https://github.com/nothke/quality-control.git
synced 2024-11-10 12:53:43 +00:00
179 lines
7.2 KiB
C#
179 lines
7.2 KiB
C#
|
using System;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEngine;
|
|||
|
|
|||
|
namespace KinematicCharacterController.Examples
|
|||
|
{
|
|||
|
public class ExampleCharacterCamera : MonoBehaviour
|
|||
|
{
|
|||
|
[Header("Framing")]
|
|||
|
public Camera Camera;
|
|||
|
public Vector2 FollowPointFraming = new Vector2(0f, 0f);
|
|||
|
public float FollowingSharpness = 10000f;
|
|||
|
|
|||
|
[Header("Distance")]
|
|||
|
public float DefaultDistance = 6f;
|
|||
|
public float MinDistance = 0f;
|
|||
|
public float MaxDistance = 10f;
|
|||
|
public float DistanceMovementSpeed = 5f;
|
|||
|
public float DistanceMovementSharpness = 10f;
|
|||
|
|
|||
|
[Header("Rotation")]
|
|||
|
public bool InvertX = false;
|
|||
|
public bool InvertY = false;
|
|||
|
[Range(-90f, 90f)]
|
|||
|
public float DefaultVerticalAngle = 20f;
|
|||
|
[Range(-90f, 90f)]
|
|||
|
public float MinVerticalAngle = -90f;
|
|||
|
[Range(-90f, 90f)]
|
|||
|
public float MaxVerticalAngle = 90f;
|
|||
|
public float RotationSpeed = 1f;
|
|||
|
public float RotationSharpness = 10000f;
|
|||
|
public bool RotateWithPhysicsMover = false;
|
|||
|
|
|||
|
[Header("Obstruction")]
|
|||
|
public float ObstructionCheckRadius = 0.2f;
|
|||
|
public LayerMask ObstructionLayers = -1;
|
|||
|
public float ObstructionSharpness = 10000f;
|
|||
|
public List<Collider> IgnoredColliders = new List<Collider>();
|
|||
|
|
|||
|
public Transform Transform { get; private set; }
|
|||
|
public Transform FollowTransform { get; private set; }
|
|||
|
|
|||
|
public Vector3 PlanarDirection { get; set; }
|
|||
|
public float TargetDistance { get; set; }
|
|||
|
|
|||
|
private bool _distanceIsObstructed;
|
|||
|
private float _currentDistance;
|
|||
|
private float _targetVerticalAngle;
|
|||
|
private RaycastHit _obstructionHit;
|
|||
|
private int _obstructionCount;
|
|||
|
private RaycastHit[] _obstructions = new RaycastHit[MaxObstructions];
|
|||
|
private float _obstructionTime;
|
|||
|
private Vector3 _currentFollowPosition;
|
|||
|
|
|||
|
private const int MaxObstructions = 32;
|
|||
|
|
|||
|
void OnValidate()
|
|||
|
{
|
|||
|
DefaultDistance = Mathf.Clamp(DefaultDistance, MinDistance, MaxDistance);
|
|||
|
DefaultVerticalAngle = Mathf.Clamp(DefaultVerticalAngle, MinVerticalAngle, MaxVerticalAngle);
|
|||
|
}
|
|||
|
|
|||
|
void Awake()
|
|||
|
{
|
|||
|
Transform = this.transform;
|
|||
|
|
|||
|
_currentDistance = DefaultDistance;
|
|||
|
TargetDistance = _currentDistance;
|
|||
|
|
|||
|
_targetVerticalAngle = 0f;
|
|||
|
|
|||
|
PlanarDirection = Vector3.forward;
|
|||
|
}
|
|||
|
|
|||
|
// Set the transform that the camera will orbit around
|
|||
|
public void SetFollowTransform(Transform t)
|
|||
|
{
|
|||
|
FollowTransform = t;
|
|||
|
PlanarDirection = FollowTransform.forward;
|
|||
|
_currentFollowPosition = FollowTransform.position;
|
|||
|
}
|
|||
|
|
|||
|
public void UpdateWithInput(float deltaTime, float zoomInput, Vector3 rotationInput)
|
|||
|
{
|
|||
|
if (FollowTransform)
|
|||
|
{
|
|||
|
if (InvertX)
|
|||
|
{
|
|||
|
rotationInput.x *= -1f;
|
|||
|
}
|
|||
|
if (InvertY)
|
|||
|
{
|
|||
|
rotationInput.y *= -1f;
|
|||
|
}
|
|||
|
|
|||
|
// Process rotation input
|
|||
|
Quaternion rotationFromInput = Quaternion.Euler(FollowTransform.up * (rotationInput.x * RotationSpeed));
|
|||
|
PlanarDirection = rotationFromInput * PlanarDirection;
|
|||
|
PlanarDirection = Vector3.Cross(FollowTransform.up, Vector3.Cross(PlanarDirection, FollowTransform.up));
|
|||
|
Quaternion planarRot = Quaternion.LookRotation(PlanarDirection, FollowTransform.up);
|
|||
|
|
|||
|
_targetVerticalAngle -= (rotationInput.y * RotationSpeed);
|
|||
|
_targetVerticalAngle = Mathf.Clamp(_targetVerticalAngle, MinVerticalAngle, MaxVerticalAngle);
|
|||
|
Quaternion verticalRot = Quaternion.Euler(_targetVerticalAngle, 0, 0);
|
|||
|
Quaternion targetRotation = Quaternion.Slerp(Transform.rotation, planarRot * verticalRot, 1f - Mathf.Exp(-RotationSharpness * deltaTime));
|
|||
|
|
|||
|
// Apply rotation
|
|||
|
Transform.rotation = targetRotation;
|
|||
|
|
|||
|
// Process distance input
|
|||
|
if (_distanceIsObstructed && Mathf.Abs(zoomInput) > 0f)
|
|||
|
{
|
|||
|
TargetDistance = _currentDistance;
|
|||
|
}
|
|||
|
TargetDistance += zoomInput * DistanceMovementSpeed;
|
|||
|
TargetDistance = Mathf.Clamp(TargetDistance, MinDistance, MaxDistance);
|
|||
|
|
|||
|
// Find the smoothed follow position
|
|||
|
_currentFollowPosition = Vector3.Lerp(_currentFollowPosition, FollowTransform.position, 1f - Mathf.Exp(-FollowingSharpness * deltaTime));
|
|||
|
|
|||
|
// Handle obstructions
|
|||
|
{
|
|||
|
RaycastHit closestHit = new RaycastHit();
|
|||
|
closestHit.distance = Mathf.Infinity;
|
|||
|
_obstructionCount = Physics.SphereCastNonAlloc(_currentFollowPosition, ObstructionCheckRadius, -Transform.forward, _obstructions, TargetDistance, ObstructionLayers, QueryTriggerInteraction.Ignore);
|
|||
|
for (int i = 0; i < _obstructionCount; i++)
|
|||
|
{
|
|||
|
bool isIgnored = false;
|
|||
|
for (int j = 0; j < IgnoredColliders.Count; j++)
|
|||
|
{
|
|||
|
if (IgnoredColliders[j] == _obstructions[i].collider)
|
|||
|
{
|
|||
|
isIgnored = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
for (int j = 0; j < IgnoredColliders.Count; j++)
|
|||
|
{
|
|||
|
if (IgnoredColliders[j] == _obstructions[i].collider)
|
|||
|
{
|
|||
|
isIgnored = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!isIgnored && _obstructions[i].distance < closestHit.distance && _obstructions[i].distance > 0)
|
|||
|
{
|
|||
|
closestHit = _obstructions[i];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// If obstructions detecter
|
|||
|
if (closestHit.distance < Mathf.Infinity)
|
|||
|
{
|
|||
|
_distanceIsObstructed = true;
|
|||
|
_currentDistance = Mathf.Lerp(_currentDistance, closestHit.distance, 1 - Mathf.Exp(-ObstructionSharpness * deltaTime));
|
|||
|
}
|
|||
|
// If no obstruction
|
|||
|
else
|
|||
|
{
|
|||
|
_distanceIsObstructed = false;
|
|||
|
_currentDistance = Mathf.Lerp(_currentDistance, TargetDistance, 1 - Mathf.Exp(-DistanceMovementSharpness * deltaTime));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Find the smoothed camera orbit position
|
|||
|
Vector3 targetPosition = _currentFollowPosition - ((targetRotation * Vector3.forward) * _currentDistance);
|
|||
|
|
|||
|
// Handle framing
|
|||
|
targetPosition += Transform.right * FollowPointFraming.x;
|
|||
|
targetPosition += Transform.up * FollowPointFraming.y;
|
|||
|
|
|||
|
// Apply position
|
|||
|
Transform.position = targetPosition;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|