973 lines
38 KiB
C#
973 lines
38 KiB
C#
using Invector.vCharacterController;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Invector.vCamera
|
|
{
|
|
|
|
public class vThirdPersonCamera : MonoBehaviour
|
|
{
|
|
private static vThirdPersonCamera _instance;
|
|
|
|
public static vThirdPersonCamera instance
|
|
{
|
|
get
|
|
{
|
|
if (_instance == null)
|
|
{
|
|
_instance = GameObject.FindObjectOfType<vThirdPersonCamera>();
|
|
|
|
//Tell unity not to destroy this object when loading a new scene!
|
|
//DontDestroyOnLoad(_instance.gameObject);
|
|
}
|
|
|
|
return _instance;
|
|
}
|
|
}
|
|
|
|
#region inspector properties
|
|
public Transform mainTarget;
|
|
[Tooltip("Lerp speed between Camera States")]
|
|
public float smoothBetweenState = 6f;
|
|
public float smoothCameraRotation = 6f;
|
|
public float smoothSwitchSide = 2f;
|
|
public float scrollSpeed = 10f;
|
|
[Tooltip("Multiplier of Mouse x and y when using joystick")]
|
|
public float joystickSensitivity = 1;
|
|
[Tooltip("What layer will be culled")]
|
|
public LayerMask cullingLayer = 1 << 0;
|
|
[Tooltip("Change this value If the camera pass through the wall")]
|
|
public float clipPlaneMargin;
|
|
public float checkHeightRadius;
|
|
public bool showGizmos;
|
|
public bool startUsingTargetRotation = true;
|
|
public bool startSmooth = false;
|
|
[Tooltip("Returns to behind the target automatically after 'behindTargetDelay' period")]
|
|
public bool autoBehindTarget = false;
|
|
[vHideInInspector("autoBehindTarget")]
|
|
public float behindTargetDelay = 2f;
|
|
[vHideInInspector("autoBehindTarget")]
|
|
public float behindTargetSmoothRotation = 1f;
|
|
|
|
[Tooltip("Debug purposes, lock the camera behind the character for better align the states")]
|
|
[SerializeField]protected bool lockCamera;
|
|
|
|
WaitForEndOfFrame waitFrame = new WaitForEndOfFrame();
|
|
public Vector2 offsetMouse;
|
|
#endregion
|
|
|
|
#region hide properties
|
|
[HideInInspector]
|
|
public int indexList, indexLookPoint;
|
|
[HideInInspector]
|
|
public float offSetPlayerPivot;
|
|
[HideInInspector]
|
|
public float distance = 5f;
|
|
[HideInInspector]
|
|
public string currentStateName;
|
|
[HideInInspector]
|
|
public Transform currentTarget;
|
|
[HideInInspector]
|
|
public vThirdPersonCameraState currentState;
|
|
[HideInInspector]
|
|
public vThirdPersonCameraListData CameraStateList;
|
|
[HideInInspector]
|
|
public Transform lockTarget;
|
|
[HideInInspector]
|
|
public Vector2 movementSpeed;
|
|
[HideInInspector]
|
|
public vThirdPersonCameraState lerpState;
|
|
|
|
protected float lockTargetSpeed;
|
|
protected float lockTargetWeight;
|
|
protected float initialCameraRotation;
|
|
|
|
protected bool cameraIsRotating;
|
|
protected Quaternion lastCameraRotation;
|
|
protected float lastRotationTimer;
|
|
|
|
protected Vector3 currentTargetPos;
|
|
protected Vector3 lookPoint;
|
|
protected Vector3 current_cPos;
|
|
protected Vector3 desired_cPos;
|
|
protected Vector3 lookTargetAdjust;
|
|
|
|
internal float mouseY = 0f;
|
|
internal float mouseX = 0f;
|
|
protected float currentHeight;
|
|
protected float currentZoom;
|
|
protected float cullingHeight;
|
|
protected float cullingDistance;
|
|
internal float switchRight;
|
|
protected float currentSwitchRight;
|
|
protected float heightOffset;
|
|
internal bool isInit;
|
|
protected bool useSmooth;
|
|
protected bool isNewTarget;
|
|
protected bool firstStateIsInit;
|
|
protected Quaternion fixedRotation;
|
|
internal Camera targetCamera;
|
|
|
|
protected float transformWeight;
|
|
protected float mouseXStart;
|
|
protected float mouseYStart;
|
|
protected Vector3 startPosition;
|
|
protected Quaternion startRotation;
|
|
|
|
protected private Vector3 cameraVelocityDamp;
|
|
protected private bool firstUpdated;
|
|
|
|
protected Transform _lookAtTarget;
|
|
|
|
|
|
protected Vector3 lastLookAtPosition, lastLookAtForward;
|
|
public bool isFreezed;
|
|
protected Transform targetLookAt
|
|
{
|
|
get
|
|
{
|
|
if (!_lookAtTarget)
|
|
{
|
|
_lookAtTarget = new GameObject("targetLookAt").transform;
|
|
_lookAtTarget.rotation = transform.rotation;
|
|
_lookAtTarget.position = mainTarget.position;
|
|
}
|
|
return _lookAtTarget;
|
|
}
|
|
}
|
|
#endregion
|
|
protected Rigidbody _selfRigidbody;
|
|
public Rigidbody selfRigidbody
|
|
{
|
|
get
|
|
{
|
|
if(!_selfRigidbody)
|
|
{
|
|
_selfRigidbody = gameObject.AddComponent<Rigidbody>();
|
|
_selfRigidbody.isKinematic = true;
|
|
_selfRigidbody.interpolation = RigidbodyInterpolation.None;
|
|
}
|
|
return _selfRigidbody;
|
|
}
|
|
|
|
}
|
|
/// <summary>
|
|
/// Lock camera angle based to the <seealso cref="currentTarget"/>. if you need just to reset angle use <seealso cref="ResetAngle"/>
|
|
/// </summary>
|
|
public bool LockCamera
|
|
{
|
|
get
|
|
{
|
|
return lockCamera;
|
|
}
|
|
set
|
|
{
|
|
|
|
lockCamera = value;
|
|
}
|
|
}
|
|
|
|
protected virtual void OnDrawGizmos()
|
|
{
|
|
if (showGizmos)
|
|
{
|
|
if (currentTarget)
|
|
{
|
|
var targetPos = new Vector3(currentTarget.position.x, currentTarget.position.y + offSetPlayerPivot, currentTarget.position.z);
|
|
Gizmos.DrawWireSphere(targetPos + Vector3.up * cullingHeight, checkHeightRadius);
|
|
Gizmos.DrawLine(targetPos, targetPos + Vector3.up * cullingHeight);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void Start()
|
|
{
|
|
|
|
Init();
|
|
}
|
|
/// <summary>
|
|
/// Init camera.
|
|
/// </summary>
|
|
public virtual void Init()
|
|
{
|
|
if (mainTarget == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
firstUpdated = true;
|
|
useSmooth = true;
|
|
targetLookAt.rotation = startUsingTargetRotation ? mainTarget.rotation : transform.rotation;
|
|
targetLookAt.position = mainTarget.position;
|
|
targetLookAt.hideFlags = HideFlags.HideInHierarchy;
|
|
startPosition = selfRigidbody.position;
|
|
startRotation = selfRigidbody.rotation;
|
|
initialCameraRotation = smoothCameraRotation;
|
|
if (!targetCamera)
|
|
{
|
|
targetCamera = Camera.main;
|
|
}
|
|
|
|
currentTarget = mainTarget;
|
|
switchRight = 1;
|
|
currentSwitchRight = 1f;
|
|
mouseXStart = transform.eulerAngles.NormalizeAngle().y;
|
|
mouseYStart = transform.eulerAngles.NormalizeAngle().x;
|
|
|
|
if (startSmooth)
|
|
{
|
|
distance = Vector3.Distance(targetLookAt.position, transform.position);
|
|
}
|
|
else
|
|
{
|
|
transformWeight = 1;
|
|
}
|
|
|
|
if (startUsingTargetRotation)
|
|
{
|
|
mouseY = currentTarget.eulerAngles.NormalizeAngle().x;
|
|
mouseX = currentTarget.eulerAngles.NormalizeAngle().y;
|
|
}
|
|
else
|
|
{
|
|
mouseY = transform.eulerAngles.NormalizeAngle().x;
|
|
mouseX = transform.eulerAngles.NormalizeAngle().y;
|
|
}
|
|
|
|
|
|
ChangeState("Default", startSmooth);
|
|
currentZoom = currentState.defaultDistance;
|
|
currentHeight = currentState.height;
|
|
|
|
currentTargetPos = new Vector3(currentTarget.position.x, currentTarget.position.y + offSetPlayerPivot, currentTarget.position.z) + currentTarget.transform.up * lerpState.height;
|
|
targetLookAt.position = currentTargetPos;
|
|
|
|
isInit = true;
|
|
}
|
|
|
|
public virtual void FixedUpdate()
|
|
{
|
|
|
|
if (mainTarget == null || targetLookAt == null || currentState == null || lerpState == null || !isInit || isFreezed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (currentState.cameraMode)
|
|
{
|
|
case TPCameraMode.FreeDirectional:
|
|
CameraMovement();
|
|
break;
|
|
case TPCameraMode.FixedAngle:
|
|
CameraMovement();
|
|
break;
|
|
case TPCameraMode.FixedPoint:
|
|
CameraFixed();
|
|
break;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Set a <seealso cref="lockTarget"/> to the camera auto rotate to look to.
|
|
/// </summary>
|
|
public virtual void SetLockTarget(Transform lockTarget)
|
|
{
|
|
if (this.lockTarget != null && this.lockTarget == lockTarget)
|
|
{
|
|
return;
|
|
}
|
|
|
|
isNewTarget = lockTarget != this.lockTarget;
|
|
this.lockTarget = lockTarget;
|
|
lockTargetWeight = 0;
|
|
this.lockTargetSpeed = 1;
|
|
}
|
|
/// <summary>
|
|
/// Set a <seealso cref="lockTarget"/> to the camera auto rotate to look to.
|
|
/// </summary>
|
|
/// <param name="lockTarget">Target to look</param>
|
|
/// <param name="heightOffset">Height offset</param>
|
|
/// <param name="lockSpeed">speed to look</param>
|
|
public virtual void SetLockTarget(Transform lockTarget, float heightOffset, float lockSpeed = 1)
|
|
{
|
|
if (this.lockTarget != null && this.lockTarget == lockTarget)
|
|
{
|
|
return;
|
|
}
|
|
|
|
isNewTarget = lockTarget != this.lockTarget;
|
|
this.lockTarget = lockTarget;
|
|
this.heightOffset = heightOffset;
|
|
lockTargetWeight = 0;
|
|
this.lockTargetSpeed = lockSpeed;
|
|
}
|
|
/// <summary>
|
|
/// Remove the <seealso cref="lockTarget"/>
|
|
/// </summary>
|
|
public virtual void RemoveLockTarget()
|
|
{
|
|
lockTargetWeight = 0;
|
|
lockTarget = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set <seealso cref="currentTarget"/>. If you need to retorn to <seealso cref="mainTarget"/>, use <seealso cref="ResetTarget"/>
|
|
/// </summary>
|
|
/// <param name="newTarget"></param>
|
|
public virtual void SetTarget(Transform newTarget)
|
|
{
|
|
lockTargetWeight = 0;
|
|
currentTarget = newTarget ? newTarget : mainTarget;
|
|
}
|
|
/// <summary>
|
|
/// Set<seealso cref="mainTarget"/> and<seealso cref= "currentTarget" />
|
|
/// </summary>
|
|
/// <param name= "newTarget" ></ param>
|
|
public virtual void SetMainTarget(Transform newTarget)
|
|
{
|
|
mainTarget = newTarget;
|
|
currentTarget = newTarget;
|
|
if (!isInit)
|
|
{
|
|
Init();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set <seealso cref="currentTarget"/> to <seealso cref="mainTarget"/>
|
|
/// </summary>
|
|
public virtual void ResetTarget()
|
|
{
|
|
if (currentTarget != mainTarget)
|
|
{
|
|
currentTarget = mainTarget;
|
|
if (!isInit)
|
|
{
|
|
Init();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the camera angle based to <seealso cref="currentTarget"/>
|
|
/// </summary>
|
|
public virtual void ResetAngle()
|
|
{
|
|
if (currentTarget)
|
|
{
|
|
mouseY = currentTarget.eulerAngles.NormalizeAngle().x;
|
|
mouseX = currentTarget.eulerAngles.NormalizeAngle().y;
|
|
}
|
|
else
|
|
{
|
|
mouseY = 0;
|
|
mouseX = 0;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert a point in the screen in a Ray for the world
|
|
/// </summary>
|
|
/// <param name="Point"></param>
|
|
/// <returns></returns>
|
|
public virtual Ray ScreenPointToRay(Vector3 Point)
|
|
{
|
|
return this.GetComponent<Camera>().ScreenPointToRay(Point);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Change CameraState
|
|
/// </summary>
|
|
/// <param name="stateName"></param>
|
|
public virtual void ChangeState(string stateName)
|
|
{
|
|
ChangeState(stateName, true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Change CameraState
|
|
/// </summary>
|
|
/// <param name="stateName"></param>
|
|
/// <param name="Use smoth"></param>
|
|
public virtual void ChangeState(string stateName, bool hasSmooth)
|
|
{
|
|
if (currentState != null && currentState.Name.Equals(stateName) || !isInit && firstStateIsInit)
|
|
{
|
|
if (firstStateIsInit)
|
|
{
|
|
useSmooth = hasSmooth;
|
|
}
|
|
|
|
return;
|
|
}
|
|
useSmooth = !firstStateIsInit ? startSmooth : hasSmooth;
|
|
// search for the camera state string name
|
|
vThirdPersonCameraState state = CameraStateList != null ? CameraStateList.tpCameraStates.Find(delegate (vThirdPersonCameraState obj) { return obj.Name.Equals(stateName); }) : new vThirdPersonCameraState("Default");
|
|
|
|
if (state != null)
|
|
{
|
|
currentStateName = stateName;
|
|
currentState.cameraMode = state.cameraMode;
|
|
lerpState = state; // set the state of transition (lerpstate) to the state finded on the list
|
|
if (!firstStateIsInit)
|
|
{
|
|
currentState.defaultDistance = Vector3.Distance(targetLookAt.position, transform.position);
|
|
currentState.forward = lerpState.forward;
|
|
currentState.height = state.height;
|
|
currentState.fov = state.fov;
|
|
if (useSmooth)
|
|
{
|
|
StartCoroutine(ResetFirstState());
|
|
}
|
|
else
|
|
{
|
|
distance = lerpState.defaultDistance;
|
|
firstStateIsInit = true;
|
|
}
|
|
}
|
|
// in case there is no smooth, a copy will be make without the transition values
|
|
if (currentState != null && !useSmooth)
|
|
{
|
|
currentState.CopyState(state);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if the state choosed if not real, the first state will be set up as default
|
|
if (CameraStateList != null && CameraStateList.tpCameraStates.Count > 0)
|
|
{
|
|
if (lerpState != null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
state = CameraStateList.tpCameraStates[0];
|
|
currentStateName = state.Name;
|
|
currentState.cameraMode = state.cameraMode;
|
|
lerpState = state;
|
|
|
|
if (currentState != null && !useSmooth)
|
|
{
|
|
currentState.CopyState(state);
|
|
}
|
|
}
|
|
}
|
|
// in case a list of states does not exist, a default state will be created
|
|
if (currentState == null)
|
|
{
|
|
currentState = new vThirdPersonCameraState("Null");
|
|
currentStateName = currentState.Name;
|
|
}
|
|
if (CameraStateList != null)
|
|
{
|
|
indexList = CameraStateList.tpCameraStates.IndexOf(state);
|
|
}
|
|
|
|
currentZoom = state.defaultDistance;
|
|
|
|
if (currentState.cameraMode == TPCameraMode.FixedAngle)
|
|
{
|
|
mouseX = currentState.fixedAngle.x;
|
|
mouseY = currentState.fixedAngle.y;
|
|
}
|
|
|
|
currentState.fixedAngle = new Vector3(mouseX, mouseY);
|
|
indexLookPoint = 0;
|
|
if (!isInit)
|
|
{
|
|
CameraMovement(true);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Change State using look at point if the cameraMode is FixedPoint
|
|
/// </summary>
|
|
/// <param name="stateName"></param>
|
|
/// <param name="pointName"></param>
|
|
/// <param name="hasSmooth"></param>
|
|
public virtual void ChangeState(string stateName, string pointName, bool hasSmooth)
|
|
{
|
|
useSmooth = hasSmooth;
|
|
if (!currentState.Name.Equals(stateName))
|
|
{
|
|
// search for the camera state string name
|
|
var state = CameraStateList.tpCameraStates.Find(delegate (vThirdPersonCameraState obj)
|
|
{
|
|
return obj.Name.Equals(stateName);
|
|
});
|
|
|
|
if (state != null)
|
|
{
|
|
currentStateName = stateName;
|
|
currentState.cameraMode = state.cameraMode;
|
|
lerpState = state; // set the state of transition (lerpstate) to the state finded on the list
|
|
// in case there is no smooth, a copy will be make without the transition values
|
|
if (currentState != null && !hasSmooth)
|
|
{
|
|
currentState.CopyState(state);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if the state choosed if not real, the first state will be set up as default
|
|
if (CameraStateList.tpCameraStates.Count > 0)
|
|
{
|
|
state = CameraStateList.tpCameraStates[0];
|
|
currentStateName = state.Name;
|
|
currentState.cameraMode = state.cameraMode;
|
|
lerpState = state;
|
|
if (currentState != null && !hasSmooth)
|
|
{
|
|
currentState.CopyState(state);
|
|
}
|
|
}
|
|
}
|
|
// in case a list of states does not exist, a default state will be created
|
|
if (currentState == null)
|
|
{
|
|
currentState = new vThirdPersonCameraState("Null");
|
|
currentStateName = currentState.Name;
|
|
}
|
|
|
|
indexList = CameraStateList.tpCameraStates.IndexOf(state);
|
|
currentZoom = state.defaultDistance;
|
|
currentState.fixedAngle = new Vector3(mouseX, mouseY);
|
|
indexLookPoint = 0;
|
|
}
|
|
|
|
if (currentState.cameraMode == TPCameraMode.FixedPoint)
|
|
{
|
|
var point = currentState.lookPoints.Find(delegate (LookPoint obj)
|
|
{
|
|
return obj.pointName.Equals(pointName);
|
|
});
|
|
if (point != null)
|
|
{
|
|
indexLookPoint = currentState.lookPoints.IndexOf(point);
|
|
}
|
|
else
|
|
{
|
|
indexLookPoint = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual IEnumerator ResetFirstState()
|
|
{
|
|
yield return new WaitForEndOfFrame();
|
|
firstStateIsInit = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Change the lookAtPoint of current state if cameraMode is FixedPoint
|
|
/// </summary>
|
|
/// <param name="pointName"></param>
|
|
public virtual void ChangePoint(string pointName)
|
|
{
|
|
if (currentState == null || currentState.cameraMode != TPCameraMode.FixedPoint || currentState.lookPoints == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var point = currentState.lookPoints.Find(delegate (LookPoint obj) { return obj.pointName.Equals(pointName); });
|
|
if (point != null)
|
|
{
|
|
indexLookPoint = currentState.lookPoints.IndexOf(point);
|
|
}
|
|
else
|
|
{
|
|
indexLookPoint = 0;
|
|
}
|
|
}
|
|
|
|
public virtual void FreezeCamera()
|
|
{
|
|
isFreezed = true;
|
|
if (mainTarget)
|
|
{
|
|
lastLookAtForward = mainTarget.InverseTransformDirection(targetLookAt.forward);
|
|
lastLookAtPosition = mainTarget.InverseTransformPoint(targetLookAt.position);
|
|
current_cPos = mainTarget.InverseTransformPoint(current_cPos);
|
|
desired_cPos = mainTarget.InverseTransformPoint(desired_cPos);
|
|
}
|
|
}
|
|
|
|
public virtual void UnFreezeCamera()
|
|
{
|
|
if (mainTarget)
|
|
{
|
|
targetLookAt.forward = mainTarget.TransformDirection(lastLookAtForward);
|
|
targetLookAt.position = mainTarget.TransformPoint(lastLookAtPosition);
|
|
current_cPos = mainTarget.TransformPoint(current_cPos);
|
|
desired_cPos = mainTarget.TransformPoint(desired_cPos);
|
|
}
|
|
isFreezed = false;
|
|
}
|
|
/// <summary>
|
|
/// Zoom baheviour
|
|
/// </summary>
|
|
/// <param name="scroolValue"></param>
|
|
/// <param name="zoomSpeed"></param>
|
|
public virtual void Zoom(float scroolValue)
|
|
{
|
|
currentZoom -= scroolValue * scrollSpeed;
|
|
}
|
|
|
|
public virtual void CheckCameraIsRotating()
|
|
{
|
|
cameraIsRotating = (transform.eulerAngles - lastCameraRotation.eulerAngles).magnitude > 0.1;
|
|
lastCameraRotation.eulerAngles = transform.eulerAngles;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Camera Rotation behaviour
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <param name="y"></param>
|
|
public virtual void RotateCamera(float x, float y)
|
|
{
|
|
if (currentState.cameraMode.Equals(TPCameraMode.FixedPoint) || !isInit)
|
|
{
|
|
smoothCameraRotation = initialCameraRotation;
|
|
return;
|
|
}
|
|
|
|
if (!currentState.cameraMode.Equals(TPCameraMode.FixedAngle))
|
|
{
|
|
// lock into a target
|
|
if (!lockTarget)
|
|
{
|
|
// free rotation
|
|
mouseX += x * (vInput.instance.inputDevice == InputDevice.Joystick ? currentState.xMouseSensitivity * joystickSensitivity : currentState.xMouseSensitivity);
|
|
mouseY -= y * (vInput.instance.inputDevice == InputDevice.Joystick ? currentState.yMouseSensitivity * joystickSensitivity : currentState.yMouseSensitivity);
|
|
|
|
movementSpeed.x = x;
|
|
movementSpeed.y = -y;
|
|
|
|
CheckCameraIsRotating();
|
|
var isAlignedWithTarget = (transform.forward - currentTarget.forward).magnitude <= 0.5f;
|
|
if (!LockCamera /*&& cameraIsRotating*/)
|
|
{
|
|
if (cameraIsRotating)
|
|
{
|
|
lastRotationTimer = Time.time;
|
|
|
|
if (movementSpeed.x != 0 || movementSpeed.y != 0)
|
|
{
|
|
smoothCameraRotation = initialCameraRotation;
|
|
}
|
|
}
|
|
|
|
mouseY = vExtensions.ClampAngle(mouseY, lerpState.yMinLimit, lerpState.yMaxLimit);
|
|
mouseX = vExtensions.ClampAngle(mouseX, lerpState.xMinLimit, lerpState.xMaxLimit);
|
|
}
|
|
else if (LockCamera || !isAlignedWithTarget && autoBehindTarget )
|
|
{
|
|
if(autoBehindTarget)
|
|
smoothCameraRotation = Mathf.Lerp(smoothCameraRotation, behindTargetSmoothRotation, 6f * Time.fixedDeltaTime);
|
|
|
|
if (LockCamera || Time.time > lastRotationTimer + behindTargetDelay)
|
|
{
|
|
mouseY = currentTarget.root.eulerAngles.NormalizeAngle().x;
|
|
mouseX = currentTarget.root.eulerAngles.NormalizeAngle().y;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
smoothCameraRotation = initialCameraRotation;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
smoothCameraRotation = initialCameraRotation;
|
|
// fixed rotation
|
|
var _x = lerpState.fixedAngle.x;
|
|
var _y = lerpState.fixedAngle.y;
|
|
mouseX = useSmooth ? Mathf.LerpAngle(mouseX, _x, smoothBetweenState * Time.fixedDeltaTime) : _x;
|
|
mouseY = useSmooth ? Mathf.LerpAngle(mouseY, _y, smoothBetweenState * Time.fixedDeltaTime) : _y;
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Switch Camera Right
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
public virtual void SwitchRight(bool value = false)
|
|
{
|
|
switchRight = value ? -1 : 1;
|
|
}
|
|
|
|
protected virtual void CalculeLockOnPoint()
|
|
{
|
|
if (currentState.cameraMode.Equals(TPCameraMode.FixedAngle) && lockTarget)
|
|
{
|
|
return; // check if angle of camera is fixed
|
|
}
|
|
|
|
var collider = lockTarget.GetComponent<Collider>(); // collider to get center of bounds
|
|
|
|
if (collider == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var _point = collider.bounds.center;
|
|
Vector3 relativePos = _point - (desired_cPos); // get position relative to transform
|
|
Quaternion rotation = Quaternion.LookRotation(relativePos); // convert to rotation
|
|
|
|
//convert angle (360 to 180)
|
|
var y = 0f;
|
|
var x = rotation.eulerAngles.y;
|
|
if (rotation.eulerAngles.x < -180)
|
|
{
|
|
y = rotation.eulerAngles.x + 360;
|
|
}
|
|
else if (rotation.eulerAngles.x > 180)
|
|
{
|
|
y = rotation.eulerAngles.x - 360;
|
|
}
|
|
else
|
|
{
|
|
y = rotation.eulerAngles.x;
|
|
}
|
|
|
|
if (lockTargetWeight < 1f)
|
|
{
|
|
lockTargetWeight += Time.fixedDeltaTime * lockTargetSpeed;
|
|
}
|
|
|
|
mouseY = Mathf.LerpAngle(mouseY, vExtensions.ClampAngle(y, currentState.yMinLimit, currentState.yMaxLimit), lockTargetWeight);
|
|
mouseX = Mathf.LerpAngle(mouseX, vExtensions.ClampAngle(x, currentState.xMinLimit, currentState.xMaxLimit), lockTargetWeight);
|
|
}
|
|
|
|
protected virtual void CameraMovement(bool forceUpdate = false)
|
|
{
|
|
if (currentTarget == null || targetCamera == null || (!firstStateIsInit && !forceUpdate))
|
|
{
|
|
return;
|
|
}
|
|
|
|
transformWeight = Mathf.Clamp(transformWeight += Time.fixedDeltaTime, 0f, 1f);
|
|
if (useSmooth)
|
|
{
|
|
currentState.Slerp(lerpState, smoothBetweenState * Time.fixedDeltaTime);
|
|
}
|
|
else
|
|
{
|
|
currentState.CopyState(lerpState);
|
|
}
|
|
|
|
if (currentState.useZoom)
|
|
{
|
|
currentZoom = Mathf.Clamp(currentZoom, currentState.minDistance, currentState.maxDistance);
|
|
distance = useSmooth ? Mathf.Lerp(distance, currentZoom, lerpState.smooth * Time.fixedDeltaTime) : currentZoom;
|
|
}
|
|
else
|
|
{
|
|
distance = useSmooth ? Mathf.Lerp(distance, currentState.defaultDistance, lerpState.smooth * Time.fixedDeltaTime) : currentState.defaultDistance;
|
|
currentZoom = currentState.defaultDistance;
|
|
}
|
|
targetCamera.fieldOfView = currentState.fov;
|
|
cullingDistance = Mathf.Lerp(cullingDistance, currentZoom, smoothBetweenState * Time.fixedDeltaTime);
|
|
currentSwitchRight = Mathf.Lerp(currentSwitchRight, switchRight, smoothSwitchSide * Time.fixedDeltaTime);
|
|
var camDir = (currentState.forward * targetLookAt.forward) + ((currentState.right * currentSwitchRight) * targetLookAt.right);
|
|
|
|
camDir = camDir.normalized;
|
|
|
|
var targetPos = new Vector3(currentTarget.position.x, currentTarget.position.y, currentTarget.position.z) + currentTarget.transform.up * offSetPlayerPivot;
|
|
currentTargetPos = targetPos;
|
|
desired_cPos = targetPos + currentTarget.transform.up * currentState.height;
|
|
current_cPos = firstUpdated ? targetPos + currentTarget.transform.up * currentHeight : Vector3.SmoothDamp(current_cPos, targetPos + currentTarget.transform.up * currentHeight, ref cameraVelocityDamp, lerpState.smoothDamp * Time.fixedDeltaTime);
|
|
firstUpdated = false;
|
|
RaycastHit hitInfo;
|
|
|
|
ClipPlanePoints planePoints = targetCamera.NearClipPlanePoints(current_cPos + (camDir * (distance)), clipPlaneMargin);
|
|
ClipPlanePoints oldPoints = targetCamera.NearClipPlanePoints(desired_cPos + (camDir * currentZoom), clipPlaneMargin);
|
|
//Check if Height is not blocked
|
|
if (Physics.SphereCast(targetPos, checkHeightRadius, currentTarget.transform.up, out hitInfo, currentState.cullingHeight + 0.2f, cullingLayer))
|
|
{
|
|
var t = hitInfo.distance - 0.2f;
|
|
t -= currentState.height;
|
|
t /= (currentState.cullingHeight - currentState.height);
|
|
cullingHeight = Mathf.Lerp(currentState.height, currentState.cullingHeight, Mathf.Clamp(t, 0.0f, 1.0f));
|
|
}
|
|
else
|
|
{
|
|
cullingHeight = useSmooth ? Mathf.Lerp(cullingHeight, currentState.cullingHeight, smoothBetweenState * Time.fixedDeltaTime) : currentState.cullingHeight;
|
|
}
|
|
//Check if desired target position is not blocked
|
|
if (CullingRayCast(desired_cPos, oldPoints, out hitInfo, currentZoom + 0.2f, cullingLayer, Color.blue))
|
|
{
|
|
var dist = hitInfo.distance;
|
|
if (dist < currentState.defaultDistance)
|
|
{
|
|
var t = dist;
|
|
t -= currentState.cullingMinDist;
|
|
t /= (currentZoom - currentState.cullingMinDist);
|
|
currentHeight = Mathf.Lerp(cullingHeight, currentState.height, Mathf.Clamp(t, 0.0f, 1.0f));
|
|
current_cPos = targetPos + currentTarget.transform.up * currentHeight;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
currentHeight = useSmooth ? Mathf.Lerp(currentHeight, currentState.height, smoothBetweenState * Time.fixedDeltaTime) : currentState.height;
|
|
}
|
|
|
|
if (cullingDistance < distance)
|
|
{
|
|
distance = cullingDistance;
|
|
}
|
|
|
|
//Check if target position with culling height applied is not blocked
|
|
if (CullingRayCast(current_cPos, planePoints, out hitInfo, distance, cullingLayer, Color.cyan))
|
|
{
|
|
distance = Mathf.Clamp(cullingDistance, 0.0f, currentState.defaultDistance);
|
|
}
|
|
|
|
var lookPoint = current_cPos + targetLookAt.forward * targetCamera.farClipPlane;
|
|
lookPoint += (targetLookAt.right * Vector3.Dot(camDir * (distance), targetLookAt.right));
|
|
targetLookAt.position = current_cPos;
|
|
|
|
float _mouseY = Mathf.LerpAngle(mouseYStart, mouseY, transformWeight);
|
|
float _mouseX = Mathf.LerpAngle(mouseXStart, mouseX, transformWeight);
|
|
Quaternion newRot = Quaternion.Euler(_mouseY + offsetMouse.y, _mouseX + offsetMouse.x, 0);
|
|
targetLookAt.rotation = useSmooth ? Quaternion.Lerp(targetLookAt.rotation, newRot, smoothCameraRotation * Time.fixedDeltaTime) : newRot;
|
|
selfRigidbody.MovePosition( Vector3.Lerp(startPosition, current_cPos + (camDir * (distance)), transformWeight));
|
|
var rotation = Quaternion.LookRotation((lookPoint) - selfRigidbody.position);
|
|
|
|
if (lockTarget)
|
|
{
|
|
CalculeLockOnPoint();
|
|
|
|
if (!(currentState.cameraMode.Equals(TPCameraMode.FixedAngle)))
|
|
{
|
|
var collider = lockTarget.GetComponent<Collider>();
|
|
if (collider != null)
|
|
{
|
|
var point = (collider.bounds.center + Vector3.up * heightOffset) - selfRigidbody.position;
|
|
var euler = Quaternion.LookRotation(point).eulerAngles - rotation.eulerAngles;
|
|
if (isNewTarget)
|
|
{
|
|
lookTargetAdjust.x = Mathf.LerpAngle(lookTargetAdjust.x, euler.x, lockTargetWeight);
|
|
lookTargetAdjust.y = Mathf.LerpAngle(lookTargetAdjust.y, euler.y, lockTargetWeight);
|
|
lookTargetAdjust.z = Mathf.LerpAngle(lookTargetAdjust.z, euler.z, lockTargetWeight);
|
|
// Quaternion.LerpUnclamped(lookTargetAdjust, Quaternion.Euler(euler), currentState.smoothFollow * Time.deltaTime);
|
|
if (Vector3.Distance(lookTargetAdjust, euler) < .5f)
|
|
{
|
|
isNewTarget = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lookTargetAdjust = euler;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lookTargetAdjust.x = Mathf.LerpAngle(lookTargetAdjust.x, 0, currentState.smooth * Time.fixedDeltaTime);
|
|
lookTargetAdjust.y = Mathf.LerpAngle(lookTargetAdjust.y, 0, currentState.smooth * Time.fixedDeltaTime);
|
|
lookTargetAdjust.z = Mathf.LerpAngle(lookTargetAdjust.z, 0, currentState.smooth * Time.fixedDeltaTime);
|
|
//lookTargetAdjust = Quaternion.LerpUnclamped(lookTargetAdjust, Quaternion.Euler(Vector3.zero), 1 * Time.deltaTime);
|
|
}
|
|
var _euler = rotation.eulerAngles + lookTargetAdjust;
|
|
_euler.z = 0;
|
|
var _rot = Quaternion.Euler(_euler + currentState.rotationOffSet);
|
|
selfRigidbody.MoveRotation(Quaternion.Lerp(startRotation, _rot, transformWeight));
|
|
movementSpeed = Vector2.zero;
|
|
}
|
|
|
|
protected virtual void CameraFixed()
|
|
{
|
|
if (useSmooth)
|
|
{
|
|
currentState.Slerp(lerpState, smoothBetweenState);
|
|
}
|
|
else
|
|
{
|
|
currentState.CopyState(lerpState);
|
|
}
|
|
|
|
transformWeight = Mathf.Clamp(transformWeight += Time.fixedDeltaTime, 0f, 1f);
|
|
var targetPos = new Vector3(currentTarget.position.x, currentTarget.position.y + offSetPlayerPivot + currentState.height, currentTarget.position.z);
|
|
currentTargetPos = useSmooth ? Vector3.MoveTowards(currentTargetPos, targetPos, currentState.smooth * Time.fixedDeltaTime) : targetPos;
|
|
current_cPos = currentTargetPos;
|
|
var pos = isValidFixedPoint ? currentState.lookPoints[indexLookPoint].positionPoint : transform.position;
|
|
transform.position = Vector3.Lerp(startPosition, useSmooth ? Vector3.Lerp(transform.position, pos, currentState.smooth * Time.fixedDeltaTime) : pos, transformWeight);
|
|
targetLookAt.position = current_cPos;
|
|
if (isValidFixedPoint && currentState.lookPoints[indexLookPoint].freeRotation)
|
|
{
|
|
var rot = Quaternion.Euler(currentState.lookPoints[indexLookPoint].eulerAngle);
|
|
transform.rotation = Quaternion.Lerp(startRotation, useSmooth ? Quaternion.Slerp(transform.rotation, rot, (currentState.smooth * 0.5f) * Time.fixedDeltaTime) : rot, transformWeight);
|
|
}
|
|
else if (isValidFixedPoint)
|
|
{
|
|
var rot = Quaternion.LookRotation(currentTargetPos - transform.position);
|
|
transform.rotation = Quaternion.Lerp(startRotation, useSmooth ? Quaternion.Slerp(transform.rotation, rot, (currentState.smooth) * Time.fixedDeltaTime) : rot, transformWeight);
|
|
}
|
|
targetCamera.fieldOfView = currentState.fov;
|
|
}
|
|
|
|
protected virtual bool isValidFixedPoint
|
|
{
|
|
get
|
|
{
|
|
return (currentState.lookPoints != null && currentState.cameraMode.Equals(TPCameraMode.FixedPoint) && (indexLookPoint < currentState.lookPoints.Count || currentState.lookPoints.Count > 0));
|
|
}
|
|
}
|
|
|
|
protected virtual bool CullingRayCast(Vector3 from, ClipPlanePoints _to, out RaycastHit hitInfo, float distance, LayerMask cullingLayer, Color color)
|
|
{
|
|
bool value = false;
|
|
if (showGizmos)
|
|
{
|
|
Debug.DrawRay(from, _to.LowerLeft - from, color);
|
|
Debug.DrawLine(_to.LowerLeft, _to.LowerRight, color);
|
|
Debug.DrawLine(_to.UpperLeft, _to.UpperRight, color);
|
|
Debug.DrawLine(_to.UpperLeft, _to.LowerLeft, color);
|
|
Debug.DrawLine(_to.UpperRight, _to.LowerRight, color);
|
|
Debug.DrawRay(from, _to.LowerRight - from, color);
|
|
Debug.DrawRay(from, _to.UpperLeft - from, color);
|
|
Debug.DrawRay(from, _to.UpperRight - from, color);
|
|
}
|
|
if (Physics.Raycast(from, _to.LowerLeft - from, out hitInfo, distance, cullingLayer))
|
|
{
|
|
value = true;
|
|
cullingDistance = hitInfo.distance;
|
|
}
|
|
|
|
if (Physics.Raycast(from, _to.LowerRight - from, out hitInfo, distance, cullingLayer))
|
|
{
|
|
value = true;
|
|
if (cullingDistance > hitInfo.distance)
|
|
{
|
|
cullingDistance = hitInfo.distance;
|
|
}
|
|
}
|
|
|
|
if (Physics.Raycast(from, _to.UpperLeft - from, out hitInfo, distance, cullingLayer))
|
|
{
|
|
value = true;
|
|
if (cullingDistance > hitInfo.distance)
|
|
{
|
|
cullingDistance = hitInfo.distance;
|
|
}
|
|
}
|
|
|
|
if (Physics.Raycast(from, _to.UpperRight - from, out hitInfo, distance, cullingLayer))
|
|
{
|
|
value = true;
|
|
if (cullingDistance > hitInfo.distance)
|
|
{
|
|
cullingDistance = hitInfo.distance;
|
|
}
|
|
}
|
|
|
|
return hitInfo.collider && value;
|
|
}
|
|
}
|
|
} |