338 lines
7.5 KiB
C#
338 lines
7.5 KiB
C#
|
|
using System.Collections;
|
||
|
|
using UnityEngine;
|
||
|
|
|
||
|
|
/**
|
||
|
|
Crude camera controller for demonstrating how volumetric light behaves with camera movement and rotations.
|
||
|
|
*/
|
||
|
|
namespace CritterVolumetricLighting
|
||
|
|
{
|
||
|
|
public class CameraController : MonoBehaviour
|
||
|
|
{
|
||
|
|
public Transform target;
|
||
|
|
public float rotationSpeed = 125f;
|
||
|
|
public float rotationAngle = 90f;
|
||
|
|
public float movementSpeed = 10f;
|
||
|
|
|
||
|
|
|
||
|
|
private Coroutine _currentRotationCoroutine = null;
|
||
|
|
|
||
|
|
private float _movementMultiplier = 1f;
|
||
|
|
private float _lastAngle;
|
||
|
|
private float _lastStationaryAngle;
|
||
|
|
private float _newTargetAngle;
|
||
|
|
private float _cooldownTimer = 0;
|
||
|
|
private float _cdTimerQ = 0;
|
||
|
|
private float _cdTimerE = 0;
|
||
|
|
private float _startDistance;
|
||
|
|
|
||
|
|
private int _movingClockWise; // -1 = not moving, 0 = false, 1 = true
|
||
|
|
private int _que = 0;
|
||
|
|
|
||
|
|
|
||
|
|
void Start()
|
||
|
|
{
|
||
|
|
Vector3 delta = this.transform.position - target.position;
|
||
|
|
_startDistance = delta.magnitude;
|
||
|
|
|
||
|
|
_movingClockWise = -1;
|
||
|
|
_lastStationaryAngle = this.transform.eulerAngles.y;
|
||
|
|
|
||
|
|
|
||
|
|
// StartCoroutine(TempCoroutine());
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
IEnumerator TempCoroutine()
|
||
|
|
{
|
||
|
|
yield return new WaitForSeconds(1f);
|
||
|
|
_cdTimerQ = 0;
|
||
|
|
float moveAngle;
|
||
|
|
if (_movingClockWise == 0)
|
||
|
|
{
|
||
|
|
_que = 0;
|
||
|
|
moveAngle = 0;
|
||
|
|
} else if (_movingClockWise == 1)
|
||
|
|
{
|
||
|
|
if (_que >= 1)
|
||
|
|
{
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
_que++;
|
||
|
|
}
|
||
|
|
} else // -1...
|
||
|
|
{
|
||
|
|
moveAngle = rotationAngle;
|
||
|
|
}
|
||
|
|
|
||
|
|
_movingClockWise = 1;
|
||
|
|
StartRotation(rotationAngle);
|
||
|
|
yield return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void Update()
|
||
|
|
{
|
||
|
|
|
||
|
|
if (_cooldownTimer < 0.1f)
|
||
|
|
{
|
||
|
|
_cooldownTimer += Time.deltaTime;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
_lastAngle = this.transform.eulerAngles.y;
|
||
|
|
|
||
|
|
if (_cdTimerQ < 0.15f)
|
||
|
|
{
|
||
|
|
_cdTimerQ += Time.deltaTime;
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
HandleQ();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (_cdTimerE < 0.15f)
|
||
|
|
{
|
||
|
|
_cdTimerE += Time.deltaTime;
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
HandleE();
|
||
|
|
}
|
||
|
|
|
||
|
|
this.transform.position = target.position - _startDistance * this.transform.forward;
|
||
|
|
HandleMovement(target);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void HandleQ()
|
||
|
|
{
|
||
|
|
bool qPressed = false;
|
||
|
|
#if ENABLE_INPUT_SYSTEM
|
||
|
|
qPressed = UnityEngine.InputSystem.Keyboard.current.qKey.isPressed;
|
||
|
|
#else
|
||
|
|
qPressed = Input.GetKey(KeyCode.Q);
|
||
|
|
#endif
|
||
|
|
if (qPressed)
|
||
|
|
{
|
||
|
|
_cdTimerQ = 0;
|
||
|
|
float moveAngle;
|
||
|
|
if (_movingClockWise == 0)
|
||
|
|
{
|
||
|
|
_que = 0;
|
||
|
|
moveAngle = 0;
|
||
|
|
} else if (_movingClockWise == 1)
|
||
|
|
{
|
||
|
|
if (_que >= 1)
|
||
|
|
{
|
||
|
|
return; // We're already going in that direction
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
_que++;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
} else // -1...
|
||
|
|
{
|
||
|
|
moveAngle = rotationAngle;
|
||
|
|
}
|
||
|
|
|
||
|
|
_movingClockWise = 1;
|
||
|
|
StartRotation(moveAngle);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void HandleE()
|
||
|
|
{
|
||
|
|
bool ePressed = false;
|
||
|
|
#if ENABLE_INPUT_SYSTEM
|
||
|
|
ePressed = UnityEngine.InputSystem.Keyboard.current.eKey.isPressed;
|
||
|
|
#else
|
||
|
|
ePressed = Input.GetKey(KeyCode.E);
|
||
|
|
#endif
|
||
|
|
if (ePressed)
|
||
|
|
{
|
||
|
|
_cdTimerE = 0;
|
||
|
|
float moveAngle;
|
||
|
|
if (_movingClockWise == 0)
|
||
|
|
{
|
||
|
|
if (_que <= -1)
|
||
|
|
{
|
||
|
|
return; // We're already going in that direction
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
_que--;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
} else if (_movingClockWise == 1)
|
||
|
|
{
|
||
|
|
_que = 0;
|
||
|
|
moveAngle = 0;
|
||
|
|
} else // -1...
|
||
|
|
{
|
||
|
|
moveAngle = -rotationAngle;
|
||
|
|
}
|
||
|
|
|
||
|
|
_movingClockWise = 0;
|
||
|
|
StartRotation(moveAngle);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void HandleMovement(Transform mover)
|
||
|
|
{
|
||
|
|
Vector3 forwardDirection = this.transform.forward;
|
||
|
|
Vector3 rightDirection = this.transform.right;
|
||
|
|
|
||
|
|
forwardDirection.y = 0f; // Remove vertical component
|
||
|
|
rightDirection.y = 0f; // Remove vertical component
|
||
|
|
forwardDirection.Normalize();
|
||
|
|
rightDirection.Normalize();
|
||
|
|
|
||
|
|
// Movement based on input
|
||
|
|
Vector3 movement = Vector3.zero;
|
||
|
|
# if ENABLE_INPUT_SYSTEM
|
||
|
|
if (UnityEngine.InputSystem.Keyboard.current.wKey.isPressed)
|
||
|
|
{
|
||
|
|
movement += forwardDirection;
|
||
|
|
}
|
||
|
|
if (UnityEngine.InputSystem.Keyboard.current.sKey.isPressed)
|
||
|
|
{
|
||
|
|
movement -= forwardDirection;
|
||
|
|
}
|
||
|
|
if (UnityEngine.InputSystem.Keyboard.current.aKey.isPressed)
|
||
|
|
{
|
||
|
|
movement -= rightDirection;
|
||
|
|
}
|
||
|
|
if (UnityEngine.InputSystem.Keyboard.current.dKey.isPressed)
|
||
|
|
{
|
||
|
|
movement += rightDirection;
|
||
|
|
}
|
||
|
|
#else
|
||
|
|
if (Input.GetKey(KeyCode.W))
|
||
|
|
{
|
||
|
|
movement += forwardDirection;
|
||
|
|
}
|
||
|
|
if (Input.GetKey(KeyCode.S))
|
||
|
|
{
|
||
|
|
movement -= forwardDirection;
|
||
|
|
}
|
||
|
|
if (Input.GetKey(KeyCode.A))
|
||
|
|
{
|
||
|
|
movement -= rightDirection;
|
||
|
|
}
|
||
|
|
if (Input.GetKey(KeyCode.D))
|
||
|
|
{
|
||
|
|
movement += rightDirection;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
// Normalize the movement vector to prevent faster diagonal movement
|
||
|
|
if (movement.magnitude > 1f)
|
||
|
|
{
|
||
|
|
movement.Normalize();
|
||
|
|
}
|
||
|
|
|
||
|
|
# if ENABLE_INPUT_SYSTEM
|
||
|
|
if (UnityEngine.InputSystem.Keyboard.current.spaceKey.isPressed)
|
||
|
|
{
|
||
|
|
_movementMultiplier = 3f;
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
_movementMultiplier = 1f;
|
||
|
|
}
|
||
|
|
#else
|
||
|
|
if (Input.GetKey(KeyCode.LeftShift))
|
||
|
|
{
|
||
|
|
_movementMultiplier = 3f;
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
_movementMultiplier = 1f;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
mover.Translate(movement * movementSpeed * Time.deltaTime * _movementMultiplier);
|
||
|
|
}
|
||
|
|
|
||
|
|
void StartRotation(float angle)
|
||
|
|
{
|
||
|
|
_cooldownTimer = 0;
|
||
|
|
if (_currentRotationCoroutine != null)
|
||
|
|
{
|
||
|
|
StopCoroutine(_currentRotationCoroutine);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
_newTargetAngle = _lastStationaryAngle + angle;
|
||
|
|
_currentRotationCoroutine = StartCoroutine(RotateAroundTarget(_newTargetAngle));
|
||
|
|
}
|
||
|
|
|
||
|
|
IEnumerator RotateAroundTarget(float targetAngle, bool cameFromCoroutine = false)
|
||
|
|
{
|
||
|
|
// Debug.Log("TargetAngle: "+targetAngle+" lastAngle: "+lastAngle);
|
||
|
|
float angle = Mathf.DeltaAngle(_lastAngle, targetAngle);
|
||
|
|
|
||
|
|
Vector3 rotationAxis = target.up;
|
||
|
|
|
||
|
|
float totalRotationTime = Mathf.Abs(angle) / rotationSpeed; // Total time to complete the rotation
|
||
|
|
// totalRotationTime = 10000f;
|
||
|
|
float elapsedTime = 0f;
|
||
|
|
|
||
|
|
float initialRotation = transform.eulerAngles.y;
|
||
|
|
|
||
|
|
while (elapsedTime < totalRotationTime)
|
||
|
|
{
|
||
|
|
elapsedTime += Time.deltaTime;
|
||
|
|
float t = elapsedTime / totalRotationTime; // calculate current progress
|
||
|
|
|
||
|
|
float usedT;
|
||
|
|
if (_que == 0)
|
||
|
|
{
|
||
|
|
usedT = SmoothStep(t, cameFromCoroutine); // apply easing
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
usedT = SmoothStep(t, cameFromCoroutine); // Don't apply easing when we are in que.
|
||
|
|
}
|
||
|
|
|
||
|
|
Vector3 rotationCenter = target.position; // update rotation center each frame
|
||
|
|
|
||
|
|
float targetRotation = initialRotation + usedT * angle; // target rotation after applying easing
|
||
|
|
float rotationThisFrame = targetRotation - transform.eulerAngles.y; // rotation to be done this frame
|
||
|
|
|
||
|
|
transform.RotateAround(rotationCenter, rotationAxis, rotationThisFrame);
|
||
|
|
|
||
|
|
yield return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
_lastStationaryAngle = this.transform.eulerAngles.y;
|
||
|
|
|
||
|
|
if (_que != 0)
|
||
|
|
{
|
||
|
|
_que = 0;
|
||
|
|
_newTargetAngle = _lastStationaryAngle + angle;
|
||
|
|
StopCoroutine(_currentRotationCoroutine);
|
||
|
|
_currentRotationCoroutine = StartCoroutine(RotateAroundTarget(_newTargetAngle, true));
|
||
|
|
yield return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
// apply a final rotation to ensure we exactly hit the target angle
|
||
|
|
Vector3 finalRotationCenter = target.position;
|
||
|
|
float finalRotation = targetAngle - transform.eulerAngles.y;
|
||
|
|
transform.RotateAround(finalRotationCenter, rotationAxis, finalRotation);
|
||
|
|
|
||
|
|
_movingClockWise = -1;
|
||
|
|
_lastStationaryAngle = this.transform.eulerAngles.y;
|
||
|
|
_currentRotationCoroutine = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
float SmoothStep(float hardT, bool cameFromCoroutine)
|
||
|
|
{
|
||
|
|
return SmoothStepLogic(hardT);
|
||
|
|
}
|
||
|
|
|
||
|
|
float SmoothStepLogic(float steppedValue)
|
||
|
|
{
|
||
|
|
return steppedValue * steppedValue * (3f - 2f* steppedValue);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|