Untitled
unknown
csharp
2 years ago
6.5 kB
7
Indexable
public class CharacterCamera : MonoBehaviour
{
[Header("Input")]
public bool handleInput = true;
[ShowIf(nameof(handleInput))]
public InputActionReference lookAction;
[ShowIf(nameof(handleInput))]
public InputActionReference zoomAction;
[Header("Framing")]
public Transform followTransform;
public Vector2 followPointFraming = new Vector2(0f, 0f);
public float followSharpness = 100f;
[Header("Distance")]
public float defaultDistance = 2f;
public float minDistance = 1f;
public float maxDistance = 4f;
public float distanceSpeed = 0.01f;
public float distanceSharpness = 10f;
[Header("Rotation")]
public bool invertX = false;
public bool invertY = false;
[Range(-90f, 90f)]
public float defaultVerticalAngle = 20f;
[Range(-90f, 90f)]
public float minVerticalAngle = -70f;
[Range(-90f, 90f)]
public float maxVerticalAngle = 90f;
public float xSensitivity = 30f;
public float ySensitivity = 20f;
public float rotationSharpness = 100f;
[Header("Collision")]
public float collisionRadius = 0.2f;
public LayerMask collisionLayers = -1;
public float collisionSharpness = 10000f;
public List<Collider> ignoredColliders = new List<Collider>();
private bool distanceIsObstructed;
private float currentDistance;
private float targetDistance;
private float targetVerticalAngle;
private int collisionCount;
private RaycastHit[] collisions = new RaycastHit[maxObstructions];
private Vector3 currentFollowPosition;
private Vector3 planarDirection;
private const int maxObstructions = 32;
public Vector3 InputRotation { get; set; }
public float ZoomInput { get; set; }
public void SetTarget(Transform target)
{
followTransform = target;
var coll = followTransform.GetComponentInParent<Collider>();
if (!ignoredColliders.Contains(coll))
ignoredColliders.Add(coll);
currentDistance = defaultDistance;
targetDistance = currentDistance;
targetVerticalAngle = 0f;
planarDirection = followTransform.forward;
currentFollowPosition = followTransform.position;
}
private void Update()
{
if (!handleInput)
return;
var lookInput = lookAction.action.ReadValue<Vector2>();
var scrollInput = zoomAction.action.ReadValue<float>();
InputRotation = lookInput;
ZoomInput = -scrollInput;
}
private void LateUpdate()
{
if (!followTransform)
return;
var targetRotation = HandleRotation();
transform.rotation = targetRotation;
HandleDistance();
HandleCollisions();
// Find the smoothed camera orbit position
var targetPosition = currentFollowPosition - ((targetRotation * Vector3.forward) * currentDistance);
// Handle framing
targetPosition += transform.right * followPointFraming.x;
targetPosition += transform.up * followPointFraming.y;
// Apply position
transform.position = targetPosition;
}
private Quaternion HandleRotation()
{
var inputX = InputRotation.x;
var inputY = InputRotation.y;
if (invertX) inputX *= -1f;
if (invertY) inputY *= -1f;
// Process rotation input
var rotationFromInput = Quaternion.Euler(followTransform.up * (inputX * xSensitivity * Time.deltaTime));
planarDirection = rotationFromInput * planarDirection;
planarDirection = Vector3.Cross(followTransform.up, Vector3.Cross(planarDirection, followTransform.up));
var planarRot = Quaternion.LookRotation(planarDirection, followTransform.up);
targetVerticalAngle -= (inputY * ySensitivity * Time.deltaTime);
targetVerticalAngle = Mathf.Clamp(targetVerticalAngle, minVerticalAngle, maxVerticalAngle);
var verticalRot = Quaternion.Euler(targetVerticalAngle, 0, 0);
var targetRotation = Quaternion.Slerp(transform.rotation,
planarRot * verticalRot, 1f - Mathf.Exp(-rotationSharpness * Time.deltaTime));
return targetRotation;
}
private void HandleDistance()
{
if (distanceIsObstructed && Mathf.Abs(ZoomInput) > 0f)
{
targetDistance = currentDistance;
}
targetDistance += ZoomInput * distanceSpeed;
targetDistance = Mathf.Clamp(targetDistance, minDistance, maxDistance);
// Find the smoothed follow position
currentFollowPosition = Vector3.Lerp(currentFollowPosition,
followTransform.position, 1f - Mathf.Exp(-followSharpness * Time.deltaTime));
}
private void HandleCollisions()
{
var closestHit = new RaycastHit();
closestHit.distance = Mathf.Infinity;
collisionCount = Physics.SphereCastNonAlloc(currentFollowPosition,
collisionRadius, -transform.forward, collisions, targetDistance, collisionLayers, QueryTriggerInteraction.Ignore);
for (int i = 0; i < collisionCount; i++)
{
bool isIgnored = false;
for (int j = 0; j < ignoredColliders.Count; j++)
{
if (ignoredColliders[j] == collisions[i].collider)
{
isIgnored = true;
break;
}
}
for (int j = 0; j < ignoredColliders.Count; j++)
{
if (ignoredColliders[j] == collisions[i].collider)
{
isIgnored = true;
break;
}
}
if (!isIgnored && collisions[i].distance < closestHit.distance && collisions[i].distance > 0)
closestHit = collisions[i];
}
// If obstructions detected
if (closestHit.distance < Mathf.Infinity)
{
distanceIsObstructed = true;
currentDistance = Mathf.Lerp(currentDistance, closestHit.distance,
1 - Mathf.Exp(-collisionSharpness * Time.deltaTime));
}
else
{
distanceIsObstructed = false;
currentDistance = Mathf.Lerp(currentDistance, targetDistance,
1 - Mathf.Exp(-distanceSharpness * Time.deltaTime));
}
}
}Editor is loading...
Leave a Comment