Created
January 10, 2023 09:49
-
-
Save danieldownes/3e3c0fe221834e919a79621d14f48b7c to your computer and use it in GitHub Desktop.
Camera controls like Unity Editor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
/// <summary> | |
/// Camera controls like Unity Editor. | |
/// </summary> | |
public class SceneLikeCamera : MonoBehaviour | |
{ | |
[Header("Focus Object")] | |
[SerializeField, Tooltip("Enable double-click to focus on objects?")] | |
private bool doFocus = false; | |
[SerializeField] private float focusLimit = 100f; | |
[SerializeField] private float minFocusDistance = 5.0f; | |
private float doubleClickTime = .15f; | |
private float cooldown = 0; | |
[Header("Undo - Only undoes the Focus Object - The keys must be pressed in order.")] | |
[SerializeField] private KeyCode firstUndoKey = KeyCode.LeftControl; | |
[SerializeField] private KeyCode secondUndoKey = KeyCode.Z; | |
[Header("Movement")] | |
[SerializeField] private float moveSpeed = 1.0f; | |
[SerializeField] private float panSpeed = 3.0f; | |
[SerializeField] private float rotationSpeed = 10.0f; | |
[SerializeField] private float zoomSpeed = 10.0f; | |
//Cache last pos and rot be able to undo last focus object action. | |
Quaternion prevRot = new Quaternion(); | |
Vector3 prevPos = new Vector3(); | |
[Header("Axes Names")] | |
[SerializeField, Tooltip("Otherwise known as the vertical axis")] private string mouseY = "Mouse Y"; | |
[SerializeField, Tooltip("AKA horizontal axis")] private string mouseX = "Mouse X"; | |
[SerializeField, Tooltip("The axis you want to use for zoom.")] private string zoomAxis = "Mouse ScrollWheel"; | |
[Header("Move Keys")] | |
[SerializeField] private KeyCode forwardKey = KeyCode.W; | |
[SerializeField] private KeyCode backKey = KeyCode.S; | |
[SerializeField] private KeyCode leftKey = KeyCode.A; | |
[SerializeField] private KeyCode rightKey = KeyCode.D; | |
[SerializeField] private KeyCode upKey = KeyCode.E; | |
[SerializeField] private KeyCode downKey = KeyCode.Q; | |
[Header("Flat Move"), Tooltip("Instead of going where the camera is pointed, the camera moves only on the horizontal plane (Assuming you are working in 3D with default preferences).")] | |
[SerializeField] private KeyCode flatMoveKey = KeyCode.LeftShift; | |
[Header("Anchored Movement"), Tooltip("By default in scene-view, this is done by right-clicking for rotation or middle mouse clicking for up and down")] | |
[SerializeField] private KeyCode anchoredMoveKey = KeyCode.Mouse2; | |
[SerializeField] private KeyCode anchoredRotateKey = KeyCode.Mouse1; | |
private void Start() | |
{ | |
SavePosAndRot(); | |
} | |
void Update() | |
{ | |
if (!doFocus) | |
return; | |
//Double click for focus | |
if (cooldown > 0 && Input.GetKeyDown(KeyCode.Mouse0)) | |
FocusObject(); | |
if (Input.GetKeyDown(KeyCode.Mouse0)) | |
cooldown = doubleClickTime; | |
//--------UNDO FOCUS--------- | |
if (Input.GetKey(firstUndoKey)) | |
{ | |
if (Input.GetKeyDown(secondUndoKey)) | |
GoBackToLastPosition(); | |
} | |
cooldown -= Time.deltaTime; | |
} | |
private void LateUpdate() | |
{ | |
Vector3 move = Vector3.zero; | |
//Move and rotate the camera | |
if (Input.GetKey(anchoredRotateKey)) | |
{ | |
if (Input.GetKey(forwardKey)) | |
move += Vector3.forward * moveSpeed; | |
if (Input.GetKey(backKey)) | |
move += Vector3.back * moveSpeed; | |
if (Input.GetKey(leftKey)) | |
move += Vector3.left * moveSpeed; | |
if (Input.GetKey(rightKey)) | |
move += Vector3.right * moveSpeed; | |
if (Input.GetKey(upKey)) | |
move += Vector3.up * moveSpeed; | |
if (Input.GetKey(downKey)) | |
move += Vector3.down * moveSpeed; | |
} | |
//By far the simplest solution I could come up with for moving only on the Horizontal plane - no rotation, just cache y | |
if (Input.GetKey(flatMoveKey)) | |
{ | |
float origY = transform.position.y; | |
transform.Translate(move); | |
transform.position = new Vector3(transform.position.x, origY, transform.position.z); | |
return; | |
} | |
float mouseMoveY = Input.GetAxis(mouseY); | |
float mouseMoveX = Input.GetAxis(mouseX); | |
//Move the camera when anchored | |
if (Input.GetKey(anchoredMoveKey)) | |
{ | |
move += Vector3.up * mouseMoveY * -panSpeed; | |
move += Vector3.right * mouseMoveX * -panSpeed; | |
} | |
//Rotate the camera when anchored | |
if (Input.GetKey(anchoredRotateKey)) | |
{ | |
transform.RotateAround(transform.position, transform.right, mouseMoveY * -rotationSpeed); | |
transform.RotateAround(transform.position, Vector3.up, mouseMoveX * rotationSpeed); | |
} | |
transform.Translate(move); | |
//Scroll to zoom | |
float mouseScroll = Input.GetAxis(zoomAxis); | |
transform.Translate(Vector3.forward * mouseScroll * zoomSpeed); | |
} | |
public void FocusOnObject(Collider target) | |
{ | |
// Save for undo | |
SavePosAndRot(); | |
// Debug.Log("collider" + target.gameObject.name); | |
GameObject go = target.gameObject; | |
Vector3 targetPos = go.transform.position; | |
Vector3 targetSize = target.bounds.size; | |
//transform.position = targetPos + GetOffset(targetPos, targetSize); | |
transform.LookAt(go.transform); | |
} | |
private void FocusObject() | |
{ | |
//If we double-clicked an object in the scene, go to its position | |
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); | |
RaycastHit hit; | |
if (Physics.Raycast(ray, out hit, focusLimit)) | |
FocusOnObject(hit.collider); | |
} | |
private void SavePosAndRot() | |
{ | |
prevRot = transform.rotation; | |
prevPos = transform.position; | |
} | |
private void GoBackToLastPosition() | |
{ | |
transform.position = prevPos; | |
transform.rotation = prevRot; | |
} | |
private Vector3 GetOffset(Vector3 targetPos, Vector3 targetSize) | |
{ | |
Vector3 dirToTarget = targetPos - transform.position; | |
float focusDistance = Mathf.Max(targetSize.x, targetSize.z); | |
focusDistance = Mathf.Clamp(focusDistance, minFocusDistance, focusDistance); | |
return -dirToTarget.normalized * focusDistance; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment