using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.InputSystem;
public class CameraBehaviour : MonoBehaviour
{
//references to relevent transforms
public PlayerAvatar r_player;
public Transform r_cameraPivot;
public Transform r_cameraTransform;
public Transform r_cameraMaxDistanceMarker;
//These are used to transition from 3rd person to OTS cameras
public float m_zoomTime;
private float m_zoomClock;
private float m_lerpA;
public float m_minZ, m_maxZ, m_otsZ;
public Vector3 m_defaultPivotLocation, m_otsPivotLocation;
//These are used to limit how far up or down the player can look
public float m_minRotationDegrees, m_maxRotationDegrees;
private float m_minRotationCos, m_maxRotationCos;
//Used to adjust how much closer to the player the camera moves when trying
//to avoid wall clipping. This can stop the player being able to see through
//the inside edge of a wall.
public float m_wallClipDistanceFactor;
//They make do stuff
private InputAction m_lookAction;
private void Awake()
{
m_minRotationCos = Mathf.Cos(m_minRotationDegrees * Mathf.Deg2Rad);
m_maxRotationCos = Mathf.Cos(m_maxRotationDegrees * Mathf.Deg2Rad);
m_zoomClock = 0f;
m_lerpA = 0f;
}
void Start()
{
r_cameraMaxDistanceMarker.localPosition = Vector3.forward * m_maxZ;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
m_lookAction = InputSystem.actions.FindAction("Look");
}
// Update is called once per frame
void FixedUpdate()
{
Vector2 lookValue = m_lookAction.ReadValue<Vector2>()
* r_player.m_lookSpeed
* Time.deltaTime;
this.transform.position = r_player.transform.position;
this.transform.rotation = r_player.transform.rotation;
PivotAroundXAxis(-lookValue.y);
AdjustCameraDistance();
}
//Does two things:
//1) Moves the camera to the OTS position when prompted
//2) Moves the camera forward to prevent wall clipping
private void AdjustCameraDistance()
{
if (m_zoomClock > 0f || r_player.m_isOTSCamera)
{
if (r_player.m_isOTSCamera && m_zoomClock == 0)
{
m_lerpA = r_cameraTransform.localPosition.z;
}
else if (!r_player.m_isOTSCamera)
{
m_lerpA = CheckCollisionDistance();
}
m_zoomClock +=
r_player.m_isOTSCamera ? Time.deltaTime : -Time.deltaTime;
m_zoomClock = Mathf.Clamp(m_zoomClock, 0f, m_zoomTime);
float t = m_zoomClock / m_zoomTime;
float dZ = Mathf.Lerp(m_lerpA, m_otsZ, t);
r_cameraTransform.localPosition = new Vector3(0f, 0f, dZ);
r_cameraPivot.localPosition = Vector3.Lerp(m_defaultPivotLocation,
m_otsPivotLocation, t);
}
else
{
float clipDist = CheckCollisionDistance();
r_cameraTransform.localPosition = new Vector3(0f, 0f, clipDist
* m_wallClipDistanceFactor);
}
}
//Checks how far away the closest wall is behind the player. If it's within
//the normal camera range, this gives the new distance to prevent clipping
//Always returns negative
float CheckCollisionDistance()
{
RaycastHit hit;
Vector3 direction = r_cameraMaxDistanceMarker.position
- r_cameraPivot.position;
float maxDistance = direction.magnitude * m_wallClipDistanceFactor;
LayerMask layerMask =~ LayerMask.GetMask(new string[] { "Player",
"Enemy" });
float dist = float.MaxValue;
if (Physics.Raycast(r_cameraPivot.position, direction, out hit,
maxDistance, layerMask))
{
//Debug.Log(hit.transform.name);
dist = hit.distance;
if(dist < 0.1)
{
Debug.Log("Hit " + hit.collider.gameObject.name + " at "
+ dist + " units");
}
}
return -1 * Mathf.Min(Mathf.Max(Mathf.Abs(dist), Mathf.Abs(m_minZ)),
Mathf.Abs(m_maxZ));
}
//Controls up-down look direction. Stops over-rotation, and also prevents
//camera from clipping through the floor.
//TODO: Stop it clipping through ceilings
void PivotAroundXAxis(float deltaX)
{
Vector3 rot = r_cameraPivot.transform.rotation.eulerAngles;
float deltaRotX = rot.x + deltaX;
float sinRotX = Mathf.Sin(deltaRotX * Mathf.Deg2Rad);
float cosRotX = Mathf.Cos(deltaRotX * Mathf.Deg2Rad);
cosRotX = (sinRotX >= 0f) ? Mathf.Clamp(cosRotX, m_maxRotationCos, 1f)
: Mathf.Clamp(cosRotX, m_minRotationCos, 1f);
rot.x = Mathf.Acos(cosRotX) * Mathf.Rad2Deg * ((sinRotX < 0) ? -1 : 1);
r_cameraPivot.transform.rotation = Quaternion.Euler(rot);
}
}