169 lines
7.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace CustomUse {
public class MyCustomExampleCharacterCamera: 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;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Χ<EFBFBD>Ƶı
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;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD>
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));
// Ӧ<><D3A6><EFBFBD><EFBFBD>ת
Transform.rotation = targetRotation;
//<2F><><EFBFBD>վ<EFBFBD><D5BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (_distanceIsObstructed && Mathf.Abs(zoomInput) > 0f)
{
TargetDistance = _currentDistance;
}
TargetDistance += zoomInput * DistanceMovementSpeed;
TargetDistance = Mathf.Clamp(TargetDistance, MinDistance, MaxDistance);
// <20>ҵ<EFBFBD>ƽ<EFBFBD><C6BD><EFBFBD>ĸ<EFBFBD><C4B8><EFBFBD>λ<EFBFBD><CEBB>
_currentFollowPosition = Vector3.Lerp(_currentFollowPosition, FollowTransform.position, 1f - Mathf.Exp(-FollowingSharpness * deltaTime));
// <20><><EFBFBD><EFBFBD><EFBFBD>ϰ<EFBFBD>
{
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];
}
}
// <20><><EFBFBD><EFBFBD><EFBFBD>ϰ<EFBFBD><CFB0><EFBFBD>̽<EFBFBD><CCBD><EFBFBD><EFBFBD>
if (closestHit.distance < Mathf.Infinity)
{
_distanceIsObstructed = true;
_currentDistance = Mathf.Lerp(_currentDistance, closestHit.distance, 1 - Mathf.Exp(-ObstructionSharpness * deltaTime));
}
// <20><><EFBFBD><EFBFBD>û<EFBFBD><C3BB><EFBFBD>
else
{
_distanceIsObstructed = false;
_currentDistance = Mathf.Lerp(_currentDistance, TargetDistance, 1 - Mathf.Exp(-DistanceMovementSharpness * deltaTime));
}
}
// <20><>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>
Vector3 targetPosition = _currentFollowPosition - ((targetRotation * Vector3.forward) * _currentDistance);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
targetPosition += Transform.right * FollowPointFraming.x;
targetPosition += Transform.up * FollowPointFraming.y;
// Ӧ<>ò<EFBFBD><C3B2><EFBFBD>
Transform.position = targetPosition;
}
}
}
}