196 lines
6.8 KiB
C#
196 lines
6.8 KiB
C#
using Sirenix.OdinInspector;
|
|
using UnityEngine;
|
|
using VOID.Generic.Player.Input;
|
|
|
|
namespace VOID.Generic.Player
|
|
{
|
|
/// <summary>
|
|
/// Manager with full control of camera with movement by player.
|
|
/// </summary>
|
|
[DefaultExecutionOrder(-1)]
|
|
public class CameraManager : MonoBehaviour
|
|
{
|
|
public static CameraManager current {get; private set;}
|
|
|
|
// Camera Movement Settings
|
|
[Title("Camera Horizontal Movement")]
|
|
[SerializeField, MinValue(1f), MaxValue(10f), SuffixLabel("m/s")]
|
|
private float moveSpeed = 5f;
|
|
[SerializeField, MinValue(1f), MaxValue(5f)]
|
|
private float moveSpeedFastMultiplier = 2.5f;
|
|
|
|
// Camera's target elevating
|
|
[Title("Camera Vertical Movement")]
|
|
[SerializeField, MinValue(1f), MaxValue(20f), SuffixLabel("m/s")]
|
|
private float elevateSpeed = 1f;
|
|
|
|
// Camera Rotate and Tilt Settings
|
|
[Title("Camera Rotate and Tilt")]
|
|
[SerializeField, MinValue(0.01f), MaxValue(1f)]
|
|
private float rotateSensitivity = 0.1f;
|
|
[SerializeField, MinValue(0.01f), MaxValue(1f)]
|
|
private float tiltSensitivity = 0.06f;
|
|
[SerializeField, MinMaxSlider(10f, 90f, true)]
|
|
private Vector2 tiltLimit = new(20f, 85f);
|
|
|
|
// Camera Zoom Settings
|
|
[Title("Camera Zoom")]
|
|
[SerializeField, MinValue(0.05f), MaxValue(1f)]
|
|
private float zoomSensitivity = 0.3f;
|
|
[SerializeField, MinMaxSlider(1f, 30f, true)]
|
|
private Vector2 zoomLimit = new(2f, 15f);
|
|
[SerializeField]
|
|
private float zoomCurrent = 8f;
|
|
|
|
// Camera Offset
|
|
[Title("Camera Offset")]
|
|
[SerializeField, MinValue(0f), MaxValue(3f)]
|
|
private float targetVerticalOffset = 1.0f;
|
|
[SerializeField]
|
|
private Vector3 cameraOffset = new(0f, 0f, -1f);
|
|
|
|
// Camera and Target
|
|
private Camera _camera;
|
|
private GameObject _target;
|
|
|
|
// Stick properties
|
|
[Title("Sticking to transform")]
|
|
public Transform stickTo;
|
|
|
|
// Aditional Components
|
|
private CameraInputManager _cameraInputManager;
|
|
|
|
private void Awake()
|
|
{
|
|
current = this;
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
_cameraInputManager = CameraInputManager.current;
|
|
|
|
_camera = Camera.main;
|
|
_target = CameraTarget.InstantiateNew().gameObject;
|
|
}
|
|
|
|
private void FixedUpdate()
|
|
{
|
|
MoveHorizontally();
|
|
MoveVertically();
|
|
RotateAndTilt();
|
|
Zoom();
|
|
Offset();
|
|
CameraLookAtTarget();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Moves camera's target to given position.
|
|
/// </summary>
|
|
public void MoveTo(Vector3 position)
|
|
{
|
|
_target.transform.position = position;
|
|
stickTo = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Moving camera's target horizontally.
|
|
/// </summary>
|
|
private void MoveHorizontally()
|
|
{
|
|
// No camera movement from player, but it can be sticked to something
|
|
if (!_cameraInputManager.isMoving) {
|
|
if (stickTo) _target.transform.position = stickTo.position + new Vector3(0f, 1.5f, 0f);
|
|
return;
|
|
}
|
|
|
|
// Player moved camera - unstick camera
|
|
stickTo = null;
|
|
|
|
// Calculate camera's target next relative position
|
|
var moveVector = _cameraInputManager.movementDelta * (moveSpeed * Time.deltaTime);
|
|
if (_cameraInputManager.isMovingFaster) moveVector *= moveSpeedFastMultiplier;
|
|
|
|
var position = _target.transform.TransformDirection(moveVector.x, 0, moveVector.y);
|
|
_target.transform.position += position;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Moving camera's target vertically.
|
|
/// </summary>
|
|
private void MoveVertically()
|
|
{
|
|
// IMPORTANT - target's pos already include offset!
|
|
var targetPos = _target.transform.position;
|
|
|
|
// Find point where camera's target can stick to
|
|
Physics.Raycast(
|
|
new Ray(targetPos + Vector3.up*50f, Vector3.down),
|
|
out var rayCastHit,
|
|
100f,
|
|
LayerManager.Static);
|
|
|
|
// Nothing - seems like camera floating and there is nothing above or below
|
|
if (!rayCastHit.collider) return;
|
|
|
|
// IMPORTANT - target include offset by default, but not raycast - we need add offset to raycast point!
|
|
var rayCastPos = rayCastHit.point + new Vector3(0, targetVerticalOffset, 0);
|
|
|
|
// If distance is positive we go UP, otherwise we go DOWN
|
|
var distance = rayCastPos.y - targetPos.y;
|
|
|
|
// Move camera's target towards new position, if really close then move remaining distance to prevent jiggling
|
|
var speed = Mathf.Sign(distance) * Mathf.Min(Mathf.Abs(distance), elevateSpeed * Time.fixedDeltaTime);
|
|
_target.transform.position += new Vector3(0f, speed, 0f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rotating and tilting camera.<br/>
|
|
/// Rotating camera's target.
|
|
/// </summary>
|
|
private void RotateAndTilt()
|
|
{
|
|
if (_cameraInputManager.isRotatingAndTilting == false) return;
|
|
|
|
var delta = _cameraInputManager.rotateAndTiltDelta;
|
|
var tiltDelta = delta.y * tiltSensitivity * -1;
|
|
var rotateDelta = delta.x * rotateSensitivity;
|
|
|
|
var previousEuler = _camera.transform.rotation.eulerAngles;
|
|
var nextEuler = previousEuler + new Vector3(tiltDelta, rotateDelta, 0);
|
|
|
|
if (nextEuler.x < tiltLimit.x) nextEuler.x = tiltLimit.x;
|
|
if (nextEuler.x > tiltLimit.y) nextEuler.x = tiltLimit.y;
|
|
|
|
_camera.transform.rotation = Quaternion.Euler(nextEuler);
|
|
_target.transform.rotation = Quaternion.Euler(0f, nextEuler.y, 0f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updating camera's zoom.
|
|
/// </summary>
|
|
private void Zoom()
|
|
{
|
|
if (_cameraInputManager.isZooming == false) return;
|
|
|
|
zoomCurrent -= _cameraInputManager.zoomDelta * zoomSensitivity;
|
|
|
|
if (zoomCurrent > zoomLimit.y) zoomCurrent = zoomLimit.y;
|
|
if (zoomCurrent < zoomLimit.x) zoomCurrent = zoomLimit.x;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updating camera's offset from target.
|
|
/// </summary>
|
|
private void Offset()
|
|
{
|
|
var offset = _camera.transform.TransformDirection(Vector3.back * zoomCurrent + cameraOffset);
|
|
_camera.transform.position = _target.transform.position + offset;
|
|
}
|
|
|
|
private void CameraLookAtTarget()
|
|
{
|
|
_camera.transform.LookAt(_target.transform);
|
|
}
|
|
}
|
|
}
|