Files
BITFALL/Assets/Plugins/FImpossible Creations/Plugins - Shared/FBasic Assets/Behaviours/Cameras/FBasic_TPPCameraBehaviour.cs
CortexCore ba342d6627 1
2023-11-30 00:23:23 +08:00

230 lines
8.1 KiB
C#

using UnityEngine;
namespace FIMSpace.Basics
{
/// <summary>
/// FM: Simple component to controll behaviour of camera in TPP mode
/// </summary>
public class FBasic_TPPCameraBehaviour : MonoBehaviour
{
[Header("Transform to be followed by camera")]
public Transform ToFollow;
[Header("Offset in position in reference to target transform (focus point)")]
public Vector3 FollowingOffset = new Vector3(0f, 1.5f, 0f);
[Header("Offset in position in reference to camera orientation")]
public Vector3 FollowingOffsetDirection = new Vector3(0f, 0f, 0f);
/// <summary> Variables to controll distance of camera to following object </summary>
[Header("Clamp values for zoom of camera")]
public Vector2 DistanceRanges = new Vector2(5f, 10f);
private float targetDistance;
private float animatedDistance;
/// <summary> Variables to controll rotation of camera around followed object </summary>
public Vector2 RotationRanges = new Vector2(-60f, 60f);
private Vector2 targetSphericRotation = new Vector2(0f, 0f);
private Vector2 animatedSphericRotation = new Vector2(0f, 0f);
[Space(10)]
[Tooltip("Sensitivity value for rotating camera around following object")]
public float RotationSensitivity = 10f;
[Header("If you want camera rotation to be smooth")]
[Range(0.1f, 1f)]
// V1.1
public float RotationSpeed = 1f;
[Header("If you want camera to follow target with some smoothness")]
[Range(0f,1f)]
// V1.1
public float HardFollowValue = 1f;
[Header("If you want to hold cursor (cursor switch on TAB)")]
public bool LockCursor = true;
/// <summary> Just to make turning off lock cursor less annoying </summary>
private bool rotateCamera = true;
/// <summary> Raycast checking if there is obstacle blocking our vision </summary>
private RaycastHit sightObstacleHit;
[Header("Layer mask to check obstacles in sight ray")]
public LayerMask SightLayerMask;
/// <summary> Target position for camera from basic calculations, if raycast hit something, there is used other position </summary>
private Vector3 targetPosition;
[Header("How far forward raycast should check collision for camera")]
public float CollisionOffset = 1f;
//public EFUpdateClock UpdateClock = EFUpdateClock.Update;
/// <summary>
/// Setting some basic variables for initialization
/// </summary>
void Start()
{
targetDistance = (DistanceRanges.x + DistanceRanges.y) / 2;
animatedDistance = DistanceRanges.y;
targetSphericRotation = new Vector2(0f, 23f);
animatedSphericRotation = targetSphericRotation;
if ( LockCursor )
{
HelperSwitchCursor();
}
}
void UpdateMethods()
{
InputCalculations();
ZoomCalculations();
FollowCalculations();
RaycastCalculations();
SwitchCalculations();
}
/// <summary>
/// Execute methods responsible for component's behaviour
/// </summary>
void LateUpdate()
{
//if (UpdateClock != EFUpdateClock.LateUpdate) return;
UpdateMethods();
}
//void Update()
//{
// if (UpdateClock != EFUpdateClock.Update) return;
// UpdateMethods();
//}
//void FixedUpdate()
//{
// if (UpdateClock != EFUpdateClock.FixedUpdate) return;
// UpdateMethods();
//}
/// <summary>
/// Calculations for input mouse controll
/// </summary>
void InputCalculations()
{
targetDistance -= (Input.GetAxis("Mouse ScrollWheel") * 5f);
if (!rotateCamera) return;
targetSphericRotation.x += Input.GetAxis("Mouse X") * RotationSensitivity;
targetSphericRotation.y -= Input.GetAxis("Mouse Y") * RotationSensitivity;
}
/// <summary>
/// Calculations for zoom / distance value of camera
/// </summary>
private void ZoomCalculations()
{
if ( !sightObstacleHit.transform ) targetDistance = Mathf.Clamp(targetDistance, DistanceRanges.x, DistanceRanges.y);
animatedDistance = Mathf.Lerp(animatedDistance, targetDistance, Time.deltaTime * 8f);
}
/// <summary>
/// Simple calculations to follow target object
/// </summary>
private void FollowCalculations()
{
targetSphericRotation.y = HelperClampAngle(targetSphericRotation.y, RotationRanges.x, RotationRanges.y);
if (RotationSpeed < 1f) animatedSphericRotation = new Vector2(Mathf.LerpAngle(animatedSphericRotation.x, targetSphericRotation.x, Time.deltaTime * 30 * RotationSpeed), Mathf.LerpAngle(animatedSphericRotation.y, targetSphericRotation.y, Time.deltaTime * 30 * RotationSpeed)); else animatedSphericRotation = targetSphericRotation;
Quaternion rotation = Quaternion.Euler(animatedSphericRotation.y, animatedSphericRotation.x, 0f);
transform.rotation = rotation;
Vector3 targetPosition = ToFollow.transform.position + FollowingOffset;
if ( HardFollowValue < 1f)
{
float lerpValue = Mathf.Lerp(0.5f, 40f, HardFollowValue);
targetPosition = Vector3.Lerp(this.targetPosition, targetPosition, Time.deltaTime * lerpValue);
}
this.targetPosition = targetPosition;
}
/// <summary>
/// Basic collision check to prevent camera from going through objects
/// </summary>
private void RaycastCalculations()
{
Vector3 followPoint = ToFollow.transform.position + FollowingOffset + transform.TransformVector(FollowingOffsetDirection);
Quaternion cameraDir = Quaternion.Euler(targetSphericRotation.y, targetSphericRotation.x, 0f);
Ray directionRay = new Ray(followPoint, cameraDir * -Vector3.forward);
// If there is something in sight ray way
if ( Physics.Raycast(directionRay, out sightObstacleHit, targetDistance + CollisionOffset, SightLayerMask, QueryTriggerInteraction.Ignore) )
{
transform.position = sightObstacleHit.point - directionRay.direction * CollisionOffset;
}
else
{
Vector3 rotationOffset = transform.rotation * -Vector3.forward * animatedDistance;
transform.position = targetPosition + rotationOffset + transform.TransformVector(FollowingOffsetDirection);
}
}
/// <summary>
/// Calculations for switching cursor state etc.
/// </summary>
private void SwitchCalculations()
{
if ( LockCursor )
{
if (Input.GetKeyDown(KeyCode.Tab))
{
HelperSwitchCursor();
if (Cursor.visible) rotateCamera = false; else rotateCamera = true;
}
}
}
#region Helpers
/// <summary>
/// Clamping angle in 360 circle
/// </summary>
private float HelperClampAngle(float angle, float min, float max)
{
if (angle < -360)
angle += 360.0f;
if (angle > 360)
angle -= 360.0f;
return Mathf.Clamp(angle, min, max);
}
/// <summary>
/// Switching cursor state for right work of camera rotating mechanics
/// </summary>
private void HelperSwitchCursor()
{
if (Cursor.visible)
{
if (Application.isFocused)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
}
else
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
}
#endregion
}
}