using UnityEngine; namespace Gaia { public class CameraController : MonoBehaviour { public GameObject target; public float targetHeight = 5f; public float distance = 12f; public float offsetFromWall = 0.1f; public float maxDistance = 20f; public float minDistance = 0.6f; public float xSpeed = 200f; public float ySpeed = 200f; public float yMinLimit = -80f; public float yMaxLimit = 80f; public float zoomRate = 40f; public float rotationDampening = 0.5f; public float zoomDampening = 5f; public LayerMask collisionLayers = -1; public bool lockToRearOfTarget; public bool allowMouseInputX = true; public bool allowMouseInputY = true; private float xDeg; private float yDeg; private float currentDistance; private float desiredDistance; private float correctedDistance; private bool rotateBehind; private bool mouseSideButton; private float pbuffer; private void Start() { Vector3 eulerAngles = base.transform.eulerAngles; xDeg = eulerAngles.x; yDeg = eulerAngles.y; currentDistance = distance; desiredDistance = distance; correctedDistance = distance; if (lockToRearOfTarget) { rotateBehind = true; } if (target == null) { target = GameObject.FindGameObjectWithTag("Player"); } } private void LateUpdate() { if (target == null) { return; } if (pbuffer > 0f) { pbuffer -= Time.deltaTime; } if (pbuffer < 0f) { pbuffer = 0f; } if (mouseSideButton && Input.GetAxis("Vertical") != 0f) { mouseSideButton = false; } if (GUIUtility.hotControl == 0) { if (Input.GetMouseButton(0) || Input.GetMouseButton(1)) { if (allowMouseInputX) { xDeg += Input.GetAxis("Mouse X") * xSpeed * 0.02f; } else { RotateBehindTarget(); } if (allowMouseInputY) { yDeg -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f; } if (!lockToRearOfTarget) { rotateBehind = false; } } else if (Input.GetAxis("Vertical") != 0f || Input.GetAxis("Horizontal") != 0f || rotateBehind || mouseSideButton) { RotateBehindTarget(); } } yDeg = ClampAngle(yDeg, yMinLimit, yMaxLimit); Quaternion quaternion = Quaternion.Euler(yDeg, xDeg, 0f); desiredDistance -= Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * zoomRate * Mathf.Abs(desiredDistance); desiredDistance = Mathf.Clamp(desiredDistance, minDistance, maxDistance); correctedDistance = desiredDistance; Vector3 vector = new Vector3(0f, 0f - targetHeight, 0f); Vector3 end = target.transform.position - (quaternion * Vector3.forward * desiredDistance + vector); Vector3 vector2 = new Vector3(target.transform.position.x, target.transform.position.y + targetHeight, target.transform.position.z); bool flag = false; if (Physics.Linecast(vector2, end, out var hitInfo, collisionLayers)) { correctedDistance = Vector3.Distance(vector2, hitInfo.point) - offsetFromWall; flag = true; } currentDistance = ((!flag || correctedDistance > currentDistance) ? Mathf.Lerp(currentDistance, correctedDistance, Time.deltaTime * zoomDampening) : correctedDistance); currentDistance = Mathf.Clamp(currentDistance, minDistance, maxDistance); end = target.transform.position - (quaternion * Vector3.forward * currentDistance + vector); base.transform.rotation = quaternion; base.transform.position = end; } private void RotateBehindTarget() { float y = target.transform.eulerAngles.y; float y2 = base.transform.eulerAngles.y; xDeg = Mathf.LerpAngle(y2, y, rotationDampening * Time.deltaTime); if (y == y2) { if (!lockToRearOfTarget) { rotateBehind = false; } } else { rotateBehind = true; } } private float ClampAngle(float angle, float min, float max) { if (angle < -360f) { angle += 360f; } if (angle > 360f) { angle -= 360f; } return Mathf.Clamp(angle, min, max); } } }