hellbound/Assets/Sources/Feel/MMTools/ToolsForMMFeedbacks/Tools/Camera/MMGhostCamera.cs

290 lines
9.9 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System;
using MoreMountains.Tools;
using MoreMountains.Feedbacks;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace MoreMountains.Tools
{
/// <summary>
/// Add this class to a camera and you'll be able to pilot it using the horizontal/vertical axis, and up/down controls set via its inspector.
/// It's got an activation button, a run button, and an option to slow down time (this will require a MMTimeManager present in the scene)
/// </summary>
[AddComponentMenu("More Mountains/Tools/Camera/MMGhostCamera")]
public class MMGhostCamera : MonoBehaviour
{
[Header("Speed")]
/// the camera's movement speed
public float MovementSpeed = 10f;
/// the factor by which to multiply the speed when "running"
public float RunFactor = 4f;
/// the movement's acceleration
public float Acceleration = 5f;
/// the movement's deceleration
public float Deceleration = 5f;
/// the speed at which the camera rotates
public float RotationSpeed = 40f;
[Header("Controls")]
/// the button used to toggle the camera on/off
public KeyCode ActivateButton = KeyCode.RightShift;
/// the name of the InputManager's horizontal axis
public string HorizontalAxisName = "Horizontal";
/// the name of the InputManager's vertical axis
public string VerticalAxisName = "Vertical";
/// the button to use to go up
public KeyCode UpButton = KeyCode.Space;
/// the button to use to go down
public KeyCode DownButton = KeyCode.C;
/// the button to use to switch between mobile and desktop control mode
public KeyCode ControlsModeSwitch = KeyCode.M;
/// the button used to modify the timescale
public KeyCode TimescaleModificationButton = KeyCode.F;
/// the button used to run while it's pressed
public KeyCode RunButton = KeyCode.LeftShift;
/// the mouse's sensitivity
public float MouseSensitivity = 0.02f;
/// the right stick sensitivity
public float MobileStickSensitivity = 2f;
[Header("Timescale Modification")]
/// the amount to modify the timescale by when pressing the timescale button
public float TimescaleModifier = 0.5f;
[Header("Settings")]
/// whether or not this camera should activate on start
public bool AutoActivation = true;
/// whether or not movement (up/down/left/right/forward/backward) is enabled
public bool MovementEnabled = true;
// whether or not rotation is enabled
public bool RotationEnabled = true;
[MMReadOnly]
/// whether this camera is active or not right now
public bool Active = false;
[MMReadOnly]
/// whether time is being altered right now or not
public bool TimeAltered = false;
[Header("Virtual Joysticks")]
public bool UseMobileControls;
[MMCondition("UseMobileControls", true)]
public GameObject LeftStickContainer;
[MMCondition("UseMobileControls", true)]
public GameObject RightStickContainer;
[MMCondition("UseMobileControls", true)]
public MMTouchJoystick LeftStick;
[MMCondition("UseMobileControls", true)]
public MMTouchJoystick RightStick;
protected Vector3 _currentInput;
protected Vector3 _lerpedInput;
protected Vector3 _normalizedInput;
protected float _acceleration;
protected float _deceleration;
protected Vector3 _movementVector = Vector3.zero;
protected float _speedMultiplier;
protected Vector3 _newEulerAngles;
/// <summary>
/// On start, activate our camera if needed
/// </summary>
protected virtual void Start()
{
if (AutoActivation)
{
ToggleFreeCamera();
}
}
/// <summary>
/// On Update we grab our input and move accordingly
/// </summary>
protected virtual void Update()
{
if (Input.GetKeyDown(ActivateButton))
{
ToggleFreeCamera();
}
if (!Active)
{
return;
}
GetInput();
Translate();
Rotate();
Move();
HandleMobileControls();
}
/// <summary>
/// Grabs and stores the various input values
/// </summary>
protected virtual void GetInput()
{
if (!UseMobileControls || (LeftStick == null))
{
_currentInput.x = Input.GetAxis("Horizontal");
_currentInput.y = 0f;
_currentInput.z = Input.GetAxis("Vertical");
}
else
{
_currentInput.x = LeftStick._joystickValue.x;
_currentInput.y = 0f;
_currentInput.z = LeftStick._joystickValue.y;
}
if (Input.GetKey(UpButton))
{
_currentInput.y = 1f;
}
if (Input.GetKey(DownButton))
{
_currentInput.y = -1f;
}
_speedMultiplier = Input.GetKey(RunButton) ? RunFactor : 1f;
_normalizedInput = _currentInput.normalized;
if (Input.GetKeyDown(TimescaleModificationButton))
{
ToggleSlowMotion();
}
}
/// <summary>
/// Turns controls to mobile if needed
/// </summary>
protected virtual void HandleMobileControls()
{
if (Input.GetKeyDown(ControlsModeSwitch))
{
UseMobileControls = !UseMobileControls;
}
if (UseMobileControls)
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
else if (Active)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
if (LeftStickContainer != null)
{
LeftStickContainer?.SetActive(UseMobileControls);
}
if (RightStickContainer != null)
{
RightStickContainer?.SetActive(UseMobileControls);
}
}
/// <summary>
/// Computes the new position
/// </summary>
protected virtual void Translate()
{
if (!MovementEnabled)
{
return;
}
if ((Acceleration == 0) || (Deceleration == 0))
{
_lerpedInput = _currentInput;
}
else
{
if (_normalizedInput.magnitude == 0)
{
_acceleration = Mathf.Lerp(_acceleration, 0f, Deceleration * Time.deltaTime);
_lerpedInput = Vector3.Lerp(_lerpedInput, _lerpedInput * _acceleration, Time.deltaTime * Deceleration);
}
else
{
_acceleration = Mathf.Lerp(_acceleration, 1f, Acceleration * Time.deltaTime);
_lerpedInput = Vector3.ClampMagnitude(_normalizedInput, _acceleration);
}
}
_movementVector = _lerpedInput;
_movementVector *= MovementSpeed * _speedMultiplier;
if (_movementVector.magnitude > MovementSpeed * _speedMultiplier)
{
_movementVector = Vector3.ClampMagnitude(_movementVector, MovementSpeed * _speedMultiplier);
}
}
/// <summary>
/// Computes the new rotation
/// </summary>
protected virtual void Rotate()
{
if (!RotationEnabled)
{
return;
}
_newEulerAngles = this.transform.eulerAngles;
if (!UseMobileControls || (LeftStick == null))
{
_newEulerAngles.x += -Input.GetAxis("Mouse Y") * 359f * MouseSensitivity;
_newEulerAngles.y += Input.GetAxis("Mouse X") * 359f * MouseSensitivity;
}
else
{
_newEulerAngles.x += -RightStick._joystickValue.y * MobileStickSensitivity;
_newEulerAngles.y += RightStick._joystickValue.x * MobileStickSensitivity;
}
_newEulerAngles = Vector3.Lerp(this.transform.eulerAngles, _newEulerAngles, Time.deltaTime * RotationSpeed);
}
/// <summary>
/// Modifies the camera's transform's position and rotation
/// </summary>
protected virtual void Move()
{
transform.eulerAngles = _newEulerAngles;
transform.position += transform.rotation * _movementVector * Time.deltaTime;
}
/// <summary>
/// Toggles the timescale modification
/// </summary>
protected virtual void ToggleSlowMotion()
{
TimeAltered = !TimeAltered;
if (TimeAltered)
{
MMTimeScaleEvent.Trigger(MMTimeScaleMethods.For, TimescaleModifier, 1f, true, 5f, true);
}
else
{
MMTimeScaleEvent.Trigger(MMTimeScaleMethods.Unfreeze, 1f, 0f, false, 0f, false);
}
}
/// <summary>
/// Toggles the camera's active state
/// </summary>
protected virtual void ToggleFreeCamera()
{
Active = !Active;
Cursor.lockState = Active ? CursorLockMode.Locked : CursorLockMode.None;
Cursor.visible = !Active;
}
}
}