Last active
February 18, 2022 08:43
-
-
Save Oyshoboy/e61ec4ce9ccca6ce25a62222edb4a999 to your computer and use it in GitHub Desktop.
A simple , but smooth flying camera controller for unity, with all basic features and configurable properties.
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 System.Collections.Generic; | |
using UnityEngine; | |
public class SimpleCameraControl : MonoBehaviour | |
{ | |
#region Variables | |
[Header("Fov Settings")] private float _currFov = 90; | |
[SerializeField] private float _translationSpeed = 2; | |
public float fovSpeedMod = 5; | |
[Header("Camera")] public Camera recordingCamera; | |
[Header("Smooth Movement")] public KeyCode speedIncreaseKey = KeyCode.LeftAlt; | |
public KeyCode speedDecreaseKey = KeyCode.LeftControl; | |
public float acceleration = 2; // how fast you accelerate | |
public float accStep = 0.25f; | |
public float accSprintMultiplier = 4; // how much faster you go when "sprinting" | |
public float dampingCoefficient = 4; // how quickly you break to a halt after you stop your input | |
public bool focusOnEnable = true; // whether or not to focus and lock cursor immediately on enable | |
public float lookSensitivity = 1f; | |
Vector3 velocity; // current velocity | |
public enum RotationAxes | |
{ | |
MouseXAndY = 0, | |
MouseX = 1, | |
MouseY = 2 | |
} | |
[Header("Smooth Rotation")] public RotationAxes axes = RotationAxes.MouseXAndY; | |
public float sensitivityX = 1F; | |
public float sensitivityY = 1F; | |
public float minimumX = -360F; | |
public float maximumX = 360F; | |
public float minimumY = -360F; | |
public float maximumY = 360F; | |
float rotationX = 0F; | |
float rotationY = 0F; | |
private List<float> rotArrayX = new List<float>(); | |
float rotAverageX = 0F; | |
private List<float> rotArrayY = new List<float>(); | |
float rotAverageY = 0F; | |
public float frameCounter = 20; | |
Quaternion originalRotation; | |
#endregion UI | |
private CursorLockMode _wantedMode; | |
bool Focused | |
{ | |
get => Cursor.lockState == CursorLockMode.Locked; | |
set | |
{ | |
Cursor.lockState = value ? CursorLockMode.Locked : CursorLockMode.None; | |
Cursor.visible = value == false; | |
} | |
} | |
private Vector3 _initPosition; | |
private Vector3 _initRotation; | |
private void Start() | |
{ | |
_initPosition = transform.position; | |
_initRotation = transform.eulerAngles; | |
InitSmoothRot(); | |
} | |
void OnEnable() | |
{ | |
if (focusOnEnable) Focused = true; | |
} | |
void OnDisable() => Focused = false; | |
private void InitSmoothRot() | |
{ | |
Rigidbody rb = GetComponent<Rigidbody>(); | |
if (rb) | |
rb.freezeRotation = true; | |
originalRotation = transform.rotation; | |
} | |
void Update() | |
{ | |
SpeedChangeControl(); | |
FovHandler(); | |
if (Focused) | |
{ | |
RotationHandler(); | |
} | |
} | |
private void SpeedChangeControl() | |
{ | |
var newAcc = acceleration; | |
if (Input.GetKey(speedIncreaseKey)) | |
{ | |
newAcc += accStep; | |
} | |
if (Input.GetKey(speedDecreaseKey)) | |
{ | |
newAcc -= accStep; | |
} | |
newAcc = Mathf.Clamp(newAcc, 0.25f, 25f); | |
acceleration = newAcc; | |
} | |
private void LateUpdate() | |
{ | |
if (Focused) | |
{ | |
UpdateInput(); | |
} | |
else if (Input.GetMouseButtonDown(0)) | |
Focused = true; | |
// Physics | |
velocity = Vector3.Lerp(velocity, Vector3.zero, dampingCoefficient * Time.deltaTime); | |
transform.position += velocity * Time.deltaTime; | |
} | |
void UpdateInput() | |
{ | |
// Position | |
velocity += GetAccelerationVector() * Time.deltaTime; | |
if (Input.GetKeyDown(KeyCode.Escape)) | |
Focused = false; | |
} | |
Vector3 GetAccelerationVector() | |
{ | |
Vector3 moveInput = default; | |
void AddMovement(KeyCode key, Vector3 dir) | |
{ | |
if (Input.GetKey(key)) | |
moveInput += dir; | |
} | |
AddMovement(KeyCode.W, Vector3.forward); | |
AddMovement(KeyCode.S, Vector3.back); | |
AddMovement(KeyCode.D, Vector3.right); | |
AddMovement(KeyCode.A, Vector3.left); | |
AddMovement(KeyCode.E, Vector3.up); | |
AddMovement(KeyCode.Q, Vector3.down); | |
Vector3 direction = transform.TransformVector(moveInput.normalized); | |
if (Input.GetKey(KeyCode.LeftShift)) | |
return direction * (acceleration * accSprintMultiplier); // "sprinting" | |
return direction * acceleration; // "walking" | |
} | |
private void RotationHandler() | |
{ | |
if (axes == RotationAxes.MouseXAndY) | |
{ | |
rotAverageY = 0f; | |
rotAverageX = 0f; | |
rotationY += Input.GetAxis("Mouse Y") * sensitivityY; | |
rotationX += Input.GetAxis("Mouse X") * sensitivityX; | |
rotArrayY.Add(rotationY); | |
rotArrayX.Add(rotationX); | |
if (rotArrayY.Count >= frameCounter) | |
{ | |
rotArrayY.RemoveAt(0); | |
} | |
if (rotArrayX.Count >= frameCounter) | |
{ | |
rotArrayX.RemoveAt(0); | |
} | |
for (int j = 0; j < rotArrayY.Count; j++) | |
{ | |
rotAverageY += rotArrayY[j]; | |
} | |
for (int i = 0; i < rotArrayX.Count; i++) | |
{ | |
rotAverageX += rotArrayX[i]; | |
} | |
rotAverageY /= rotArrayY.Count; | |
rotAverageX /= rotArrayX.Count; | |
rotAverageY = ClampAngle(rotAverageY, minimumY, maximumY); | |
rotAverageX = ClampAngle(rotAverageX, minimumX, maximumX); | |
CutOffRotationWithinLimits(); | |
Quaternion yQuaternion = Quaternion.AngleAxis(rotAverageY, Vector3.left); | |
Quaternion xQuaternion = Quaternion.AngleAxis(rotAverageX, Vector3.up); | |
var newRot = originalRotation * xQuaternion * yQuaternion; | |
var newEuler = newRot.eulerAngles; | |
newEuler = new Vector3(newEuler.x, newEuler.y, 0); | |
transform.rotation = Quaternion.Euler(newEuler); | |
} | |
else if (axes == RotationAxes.MouseX) | |
{ | |
rotAverageX = 0f; | |
rotationX += Input.GetAxis("Mouse X") * sensitivityX; | |
rotArrayX.Add(rotationX); | |
if (rotArrayX.Count >= frameCounter) | |
{ | |
rotArrayX.RemoveAt(0); | |
} | |
for (int i = 0; i < rotArrayX.Count; i++) | |
{ | |
rotAverageX += rotArrayX[i]; | |
} | |
rotAverageX /= rotArrayX.Count; | |
rotAverageX = ClampAngle(rotAverageX, minimumX, maximumX); | |
Quaternion xQuaternion = Quaternion.AngleAxis(rotAverageX, Vector3.up); | |
transform.rotation = originalRotation * xQuaternion; | |
} | |
else | |
{ | |
rotAverageY = 0f; | |
rotationY += Input.GetAxis("Mouse Y") * sensitivityY; | |
rotArrayY.Add(rotationY); | |
if (rotArrayY.Count >= frameCounter) | |
{ | |
rotArrayY.RemoveAt(0); | |
} | |
for (int j = 0; j < rotArrayY.Count; j++) | |
{ | |
rotAverageY += rotArrayY[j]; | |
} | |
rotAverageY /= rotArrayY.Count; | |
rotAverageY = ClampAngle(rotAverageY, minimumY, maximumY); | |
Quaternion yQuaternion = Quaternion.AngleAxis(rotAverageY, Vector3.left); | |
transform.rotation = originalRotation * yQuaternion; | |
} | |
} | |
private void CutOffRotationWithinLimits() | |
{ | |
if (rotAverageY <= minimumY) | |
{ | |
rotationY = minimumY; | |
} | |
else if (rotAverageY >= maximumY) | |
{ | |
rotationY = maximumY; | |
} | |
} | |
public static float ClampAngle(float angle, float min, float max) | |
{ | |
angle = angle % 360; | |
if ((angle >= -360F) && (angle <= 360F)) | |
{ | |
if (angle < -360F) | |
{ | |
angle += 360F; | |
} | |
if (angle > 360F) | |
{ | |
angle -= 360F; | |
} | |
} | |
return Mathf.Clamp(angle, min, max); | |
} | |
private void FovHandler() | |
{ | |
if (recordingCamera == null) return; | |
//var camera = GetComponent<Camera>(); | |
_currFov += Input.mouseScrollDelta.y * _translationSpeed; | |
_currFov = Mathf.Clamp(_currFov, 1, 120); | |
var calcFov = Mathf.Lerp(recordingCamera.fieldOfView, _currFov, Time.deltaTime * fovSpeedMod); | |
var newFov = calcFov; | |
recordingCamera.fieldOfView = newFov; | |
} | |
// Apply requested cursor state | |
private void SetCursorState() | |
{ | |
if (Input.GetKeyDown(KeyCode.Escape)) | |
{ | |
Cursor.lockState = _wantedMode = CursorLockMode.None; | |
} | |
if (Input.GetMouseButtonDown(0)) | |
{ | |
_wantedMode = CursorLockMode.Locked; | |
} | |
// Apply cursor state | |
Cursor.lockState = _wantedMode; | |
// Hide cursor when locking | |
Cursor.visible = (CursorLockMode.Locked != _wantedMode); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment