forked from Shardstone/trail-into-darkness
First commit on my server, yey!
This commit is contained in:
171
Assets/Code/GameState/Camera/CameraController.cs
Normal file
171
Assets/Code/GameState/Camera/CameraController.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
#nullable enable
|
||||
using Nox.Platform;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Nox.Game {
|
||||
public class CameraController : ICameraController {
|
||||
private readonly PlatformSettings? platformSettings;
|
||||
private readonly InputSystem_Actions? inputActions;
|
||||
private readonly MapReference? mapReference;
|
||||
|
||||
private CameraSettings? cameraSettings;
|
||||
|
||||
private InputAction? zoomAction;
|
||||
private InputAction? panAction;
|
||||
private InputAction? holdToDragAction;
|
||||
private Bounds planeBounds;
|
||||
private Vector3 dragWorldOrigin;
|
||||
private bool isDragging;
|
||||
private readonly Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
|
||||
private readonly Texture2D cursorPoint;
|
||||
private readonly Texture2D cursorDrag;
|
||||
|
||||
public CameraReference? CameraReference { get; private set; }
|
||||
|
||||
public CameraController(PlatformSettings? platformSettings, MapReference? mapReference) {
|
||||
this.platformSettings = platformSettings;
|
||||
this.mapReference = mapReference;
|
||||
inputActions = platformSettings?.inputSettings.inputActions;
|
||||
|
||||
cursorPoint = Addressables.LoadAssetAsync<Texture2D>("Assets/Art/UI/Cursor_Pointer").WaitForCompletion();
|
||||
cursorDrag = Addressables.LoadAssetAsync<Texture2D>("Assets/Art/UI/Cursor_Drag").WaitForCompletion();
|
||||
Cursor.SetCursor(cursorPoint, new Vector2(12,4), CursorMode.Auto);
|
||||
}
|
||||
|
||||
public void Initialize() {
|
||||
if(inputActions == null || !mapReference) {
|
||||
return;
|
||||
}
|
||||
zoomAction = inputActions.Player.Zoom;
|
||||
panAction = inputActions.Player.PanMap;
|
||||
holdToDragAction = inputActions.Player.HoldToDrag;
|
||||
planeBounds = mapReference.mapPlane.GetComponent<BoxCollider>().bounds;
|
||||
SetupCamera();
|
||||
}
|
||||
|
||||
private void SetupCamera() {
|
||||
CameraReference = Object.FindAnyObjectByType<CameraReference>();
|
||||
|
||||
if(!CameraReference) {
|
||||
if(platformSettings?.cameraPrefab != null) {
|
||||
GameObject? go = Object.Instantiate(platformSettings.cameraPrefab);
|
||||
CameraReference = go.GetComponentInChildren<CameraReference>();
|
||||
if(!CameraReference) {
|
||||
Debug.LogError("Camera prefab does not contain a CameraReference component");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Debug.LogError("No camera prefab found and no camera reference found");
|
||||
}
|
||||
}
|
||||
|
||||
cameraSettings = CameraReference!.cameraSettings;
|
||||
if(!cameraSettings) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set initial zoom to maximum allowed by map boundaries
|
||||
var camera = CameraReference.mainCamera;
|
||||
if(camera.orthographic) {
|
||||
float maxHalfWidth = planeBounds.size.x * 0.5f;
|
||||
float maxHalfHeight = planeBounds.size.z * 0.5f;
|
||||
float maxOrthoSize = Mathf.Min(maxHalfHeight, maxHalfWidth / camera.aspect);
|
||||
camera.orthographicSize = Mathf.Min(cameraSettings.maxZoom, maxOrthoSize);
|
||||
}
|
||||
else {
|
||||
// Perspective camera: set height so the map fits in view
|
||||
float mapWidth = planeBounds.size.x;
|
||||
float mapHeight = planeBounds.size.z;
|
||||
float aspect = camera.aspect;
|
||||
float fovRad = camera.fieldOfView * Mathf.Deg2Rad;
|
||||
float tanFov = Mathf.Tan(fovRad / 2f);
|
||||
float requiredHeightByWidth = mapWidth / (2f * tanFov * aspect);
|
||||
float requiredHeightByHeight = mapHeight / (2f * tanFov);
|
||||
float requiredHeight = Mathf.Max(requiredHeightByWidth, requiredHeightByHeight);
|
||||
// Center camera on map and set height
|
||||
Vector3 camPos = planeBounds.center;
|
||||
camPos.y = requiredHeight;
|
||||
camera.transform.position = camPos;
|
||||
// Look straight down
|
||||
camera.transform.rotation = Quaternion.Euler(90f, 0f, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick() {
|
||||
PanCamera();
|
||||
ZoomCamera();
|
||||
}
|
||||
|
||||
private void ZoomCamera() {
|
||||
if(zoomAction == null) {
|
||||
return;
|
||||
}
|
||||
float zoomDelta = zoomAction.ReadValue<Vector2>().y;
|
||||
if(zoomDelta == 0) {
|
||||
return;
|
||||
}
|
||||
var camera = CameraReference!.mainCamera;
|
||||
if(camera.orthographic) {
|
||||
camera.orthographicSize = Mathf.Clamp(camera.orthographicSize - (zoomDelta * cameraSettings!.zoomSpeed * Time.deltaTime), cameraSettings.minZoom, cameraSettings.maxZoom);
|
||||
}
|
||||
else {
|
||||
camera.transform.Translate(Vector3.forward * zoomDelta * cameraSettings!.zoomSpeed * Time.deltaTime, Space.Self);
|
||||
}
|
||||
}
|
||||
|
||||
private void PanCamera() {
|
||||
if(holdToDragAction == null || CameraReference == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(holdToDragAction.IsInProgress()) {
|
||||
Camera camera = CameraReference.mainCamera;
|
||||
Vector2 screenPos = inputActions!.Player.Point.ReadValue<Vector2>();
|
||||
|
||||
if(!isDragging) {
|
||||
isDragging = true;
|
||||
Cursor.lockState = CursorLockMode.Confined;
|
||||
Cursor.SetCursor(cursorDrag, Vector2.zero, CursorMode.Auto);
|
||||
dragWorldOrigin = ScreenToGroundPoint(camera, screenPos);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 currentWorldPoint = ScreenToGroundPoint(camera, screenPos);
|
||||
Vector3 offset = dragWorldOrigin - currentWorldPoint;
|
||||
|
||||
Vector3 camPos = camera.transform.position;
|
||||
camPos.x += offset.x;
|
||||
camPos.z += offset.z;
|
||||
|
||||
camPos.x = Mathf.Clamp(camPos.x, planeBounds.min.x, planeBounds.max.x);
|
||||
camPos.z = Mathf.Clamp(camPos.z, planeBounds.min.z, planeBounds.max.z);
|
||||
camera.transform.position = camPos;
|
||||
|
||||
dragWorldOrigin = ScreenToGroundPoint(camera, screenPos);
|
||||
}
|
||||
else {
|
||||
if(!isDragging) {
|
||||
return;
|
||||
}
|
||||
isDragging = false;
|
||||
Cursor.lockState = CursorLockMode.None;
|
||||
Cursor.SetCursor(cursorPoint, new Vector2(12,4), CursorMode.Auto);
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 ScreenToGroundPoint(Camera camera, Vector2 screenPos) {
|
||||
Ray ray = camera.ScreenPointToRay(new Vector3(screenPos.x, screenPos.y, 0f));
|
||||
if(groundPlane.Raycast(ray, out float distance)) {
|
||||
return ray.GetPoint(distance);
|
||||
}
|
||||
return camera.transform.position;
|
||||
}
|
||||
public void Dispose() {
|
||||
inputActions?.Disable();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user