using System.Collections;
using UnityEngine;
using DG.Tweening;
using UnityEngine.EventSystems;
[RequireComponent(typeof(Camera))]
///
/// 摄像机控制脚本
///
public class CameraOrbit : CameraBase
{
[Header("开关")]
[Tooltip("是否可控.关闭则无法控制摄像机")]
public bool controlable = true;
[HideInInspector]
///
/// 是否初始化
///
public bool hasInit = false;
[Header("是否可以旋转")]
///
/// 是否可以旋转
///
public bool allowRotate = true;
[Header("是否可以平移")]
///
/// 是否可以平移
///
public bool allowPan = true;
[Header("是否双击定位")]
///
/// 是否双击定位
///
public bool allLocate = true;
[Header("是否自动旋转")]
///
/// 是否自动旋转
///
private bool autoRotate = false;
[Header("Movement")]
public CameraMovementType movementType = CameraMovementType.Normal;
[Header("旋转按键")]
public CameraMouseInputType rotateInputKey = CameraMouseInputType.LeftMouse;
[Header("平移按键")]
public CameraMouseInputType panInputKey = CameraMouseInputType.RightMouse;
[Header("观察的目标")]
public Vector3 target;
public Transform targetTrans;
[Header("摄像机与目标之间的距离")]
public float Distance = 150f;
[Header("限制")]
[Tooltip("摄像机与目标之间的距离限制")]
public Vector2 distanceClamp = new Vector2(1, 1000);
public Vector2 yLimitClamp = new Vector2(-20, 90);
public Vector2 xLimitClamp = new Vector2(360, 360);
public Vector2 yHeightLimitClamp = new Vector2(-Mathf.Infinity, Mathf.Infinity);
[Header("控制参数")]
[Header("鼠标滑动灵敏度")]
[Range(0.01f, 10)]
public float axisSensitivity = 3;
[Range(1, 100)]
public float axisLerp = 10;
[Header("鼠标滚轮灵敏度")]
[Range(0.001f, 10)]
float scrollSensitivity = 0.02f;
[Range(1, 100)]
float zoomLerp = 20;
[Header("相机平移灵敏度")]
[Range(0.01f, 10)]
public float panSensitivity = 1f;
[Header("相机自动旋转速度")]
[Range(0.01f, 10)]
public float autoRotateSpeed = 2f;
[Range(1, 100)]
public float panLerp = 15;
[Range(1, 100)]
private float lerpSpeed = 5;
[Header("切换目标时黑屏时间")]
[Range(0.01f, 10)]
public float swichtSpeed = 1;
public Ease ease = Ease.Linear;
private float x, y;
private float horizontal;
private float vertical;
private float distance = 0;
private Vector3 panOffset;
private Vector3 zoomVector;
private Vector3 currentPosition;
private Quaternion currentRotation;
private float initXRotation;
private bool isSwitchingTarget = false;
private float fadeAlpha = 0;
private bool control = true;
[SerializeField]
private Texture2D fadeTexture = null;
public bool Controlable
{
get { return controlable; }
set { controlable = value; }
}
private void Awake()
{
Init();
}
private void LateUpdate()
{
target = targetTrans.position;
Detection();
if (!controlable) return;
if (isSwitchingTarget)
return;
if (autoRotate)
{
AutoRotate();
}
if (control)
{
if (allowRotate)
{
ZoomControl(false);
OrbitControl();
}
else
{
ZoomControl(true);
}
if (allowPan)
{
PanControl();
}
}
if (allLocate)
{
//DclickLocate();
}
target = LimitHeight(target);
}
///
/// 初始化
///
private void Init()
{
distance = Distance;
Vector3 eulerAngles = Transform.eulerAngles;
x = eulerAngles.y;
y = eulerAngles.x;
initXRotation = eulerAngles.y;
horizontal = x;
vertical = y;
hasInit = true;
}
///
/// 旋转控制
///
private void OrbitControl()
{
if (controlable)
{
if (IsInputKeyRotate)
{
horizontal += (axisSensitivity) * AxisX;
vertical -= (axisSensitivity) * AxisY;
}
}
float delta = Time.deltaTime;
vertical = ClampAngle(vertical, yLimitClamp.x, yLimitClamp.y);
if (xLimitClamp.x < 360 && xLimitClamp.y < 360)
{
horizontal = ClampAngle(horizontal, (initXRotation - xLimitClamp.y), (xLimitClamp.x + initXRotation));
}
x = Mathf.Lerp(x, horizontal, Time.deltaTime * axisLerp);
y = Mathf.Lerp(y, vertical, Time.deltaTime * axisLerp);
y = ClampAngle(y, yLimitClamp.x, yLimitClamp.y);
currentRotation = Quaternion.Euler(y, x, 0f);
currentPosition = (currentRotation * zoomVector) + target;
switch (movementType)
{
case CameraMovementType.Dynamic:
Transform.position = Vector3.Lerp(Transform.position, currentPosition, (lerpSpeed) * delta);
Transform.rotation = Quaternion.Lerp(Transform.rotation, currentRotation, (lerpSpeed * 2) * delta);
break;
case CameraMovementType.Normal:
Transform.position = currentPosition;
Transform.rotation = currentRotation;
break;
case CameraMovementType.Towars:
Transform.position = Vector3.MoveTowards(Transform.position, currentPosition, lerpSpeed);
Transform.rotation = Quaternion.RotateTowards(Transform.rotation, currentRotation, lerpSpeed);
break;
}
}
///
/// 距离控制
///
///
private void ZoomControl(bool autoApply)
{
float delta = Time.deltaTime;
distance = Mathf.Clamp(distance - (MouseScrollWheel * scrollSensitivity * 10), distanceClamp.x, distanceClamp.y);
distance = (distance < 1) ? 1 : distance;
Distance = Mathf.SmoothStep(Distance, distance, delta * zoomLerp);
zoomVector = new Vector3(0, 0, -Distance);
if (autoApply)
{
currentPosition = (currentRotation * zoomVector) + target;
switch (movementType)
{
case CameraMovementType.Dynamic:
Transform.position = Vector3.Lerp(Transform.position, currentPosition, (lerpSpeed) * delta);
Transform.rotation = Quaternion.Lerp(Transform.rotation, currentRotation, (lerpSpeed * 2) * delta);
break;
case CameraMovementType.Normal:
Transform.position = currentPosition;
Transform.rotation = currentRotation;
break;
case CameraMovementType.Towars:
Transform.position = Vector3.MoveTowards(Transform.position, currentPosition, lerpSpeed);
Transform.rotation = Quaternion.RotateTowards(Transform.rotation, currentRotation, lerpSpeed);
break;
}
}
}
///
/// 平移控制
///
private void PanControl()
{
if (IsInputKeyPan)
{
Vector3 offset;
if (Input.GetKey(KeyCode.LeftControl))
{
offset = -transform.right.normalized * AxisX + transform.forward.normalized * AxisY;
}
else
{
offset = -transform.right.normalized * AxisX - transform.up.normalized * AxisY;
}
#if !UNITY_EDITOR
offset = new Vector3(offset.x, 0, offset.z);
#endif
panOffset = Vector3.Lerp(panOffset, offset, panLerp * Time.deltaTime);
}
else
{
panOffset = Vector3.Lerp(panOffset, Vector3.zero, panLerp * Time.deltaTime);
}
target += panOffset * panSensitivity * 10 * GetZoom();
}
///
/// 控制检测,按下的一瞬间是否在UI上,是的话无法控制相机
///
private void Detection()
{
if (Input.GetMouseButtonUp(0) || Input.GetMouseButtonUp(1) || Input.GetMouseButtonUp(2))
{
control = true;
}
if (Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1) || Input.GetMouseButtonDown(2))
{
if (EventSystem.current.IsPointerOverGameObject())
{
control = false;
}
}
}
private bool IsInputKeyRotate
{
get
{
switch (rotateInputKey)
{
case CameraMouseInputType.All:
return (Input.GetKey(KeyCode.Mouse0) || Input.GetKey(KeyCode.Mouse1) || Input.GetKey(KeyCode.Mouse2) || Input.GetMouseButton(0));
case CameraMouseInputType.LeftAndRight:
return (Input.GetKey(KeyCode.Mouse0) || Input.GetKey(KeyCode.Mouse1));
case CameraMouseInputType.LeftMouse:
return (Input.GetKey(KeyCode.Mouse0));
case CameraMouseInputType.RightMouse:
return (Input.GetKey(KeyCode.Mouse1));
case CameraMouseInputType.MouseScroll:
return (Input.GetKey(KeyCode.Mouse2));
case CameraMouseInputType.MobileTouch:
return (Input.GetMouseButton(0) || Input.GetMouseButton(1));
default:
return (Input.GetKey(KeyCode.Mouse0));
}
}
}
private bool IsInputKeyPan
{
get
{
switch (panInputKey)
{
case CameraMouseInputType.All:
return (Input.GetKey(KeyCode.Mouse0) || Input.GetKey(KeyCode.Mouse1) || Input.GetKey(KeyCode.Mouse2) || Input.GetMouseButton(0));
case CameraMouseInputType.LeftAndRight:
return (Input.GetKey(KeyCode.Mouse0) || Input.GetKey(KeyCode.Mouse1));
case CameraMouseInputType.LeftMouse:
return (Input.GetKey(KeyCode.Mouse0));
case CameraMouseInputType.RightMouse:
return (Input.GetKey(KeyCode.Mouse1));
case CameraMouseInputType.MouseScroll:
return (Input.GetKey(KeyCode.Mouse2));
case CameraMouseInputType.MobileTouch:
return (Input.GetMouseButton(0) || Input.GetMouseButton(1));
default:
return (Input.GetKey(KeyCode.Mouse0));
}
}
}
public void SetTarget(Vector3 newTarget)
{
newTarget = LimitHeight(newTarget);
target = newTarget;
}
public void SetTargetLerp(Vector3 newTarget)
{
newTarget = LimitHeight(newTarget);
DOTween.To(() => target, x => target = x, newTarget, 0.2f).SetEase(ease);
}
public void SetTarget(Transform newTarget)
{
StopCoroutine("TranslateTarget");
StartCoroutine("TranslateTarget", newTarget);
}
private IEnumerator TranslateTarget(Transform newTarget)
{
isSwitchingTarget = true;
while (fadeAlpha < 1)
{
transform.position = Vector3.Lerp(transform.position, transform.position + new Vector3(0, 2, -2), Time.deltaTime);
fadeAlpha += Time.smoothDeltaTime * swichtSpeed;
yield return null;
}
target = newTarget.position;
isSwitchingTarget = false;
while (fadeAlpha > 0)
{
fadeAlpha -= Time.smoothDeltaTime * swichtSpeed;
yield return null;
}
}
///
/// 双击定位
///
private void DclickLocate()
{
if (EventSystem.current.IsPointerOverGameObject()) return;
//if (Inputs.Key.DoubleClick(KeyCode.Mouse0, 0.2f))
//{
// Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// if (Physics.Raycast(ray, out RaycastHit hit))
// {
// SetTargetLerp(hit.point);
// }
//}
}
///
/// 限制目标点高度
///
private Vector3 LimitHeight(Vector3 _target)
{
return new Vector3(_target.x, Mathf.Clamp(_target.y, yHeightLimitClamp.x, yHeightLimitClamp.y), _target.z);
}
///
/// 设置九个方向朝向
///
///
public void SetViewPoint(CameraOrientation Orient = CameraOrientation.Forward)
{
switch (Orient)
{
case CameraOrientation.Forward:
vertical = 0; horizontal = 0;
break;
case CameraOrientation.Behind:
vertical = 0; horizontal = 180;
break;
case CameraOrientation.Left:
vertical = 0; horizontal = 90;
break;
case CameraOrientation.Right:
vertical = 0; horizontal = -90;
break;
case CameraOrientation.LeftForward:
vertical = 0; horizontal = -45;
break;
case CameraOrientation.RightForward:
vertical = 0; horizontal = -135;
break;
case CameraOrientation.LeftBehind:
vertical = 0; horizontal = 45;
break;
case CameraOrientation.RightBehind:
vertical = 0; horizontal = 135;
break;
case CameraOrientation.Top:
vertical = 90; horizontal = 0;
break;
}
}
///
/// 镜头拉近拉远
///
///
public void Zoom(float value, float timer = 0.5f)
{
float targetDis = distance + value;
DOTween.To(() => distance, x => distance = x, targetDis, timer).OnUpdate(() =>
{
distance = Mathf.Clamp(distance, distanceClamp.x, distanceClamp.y);
});
}
///
///
///
///
public void SetStaticZoom(float value)
{
distance += value;
}
///
/// 设置位置
///
/// 注视点位置
/// 与注视点距离
/// 竖直角度
/// 水平角度
public void SetPosition(Vector3 newTarget, float dis, float angleX = 45, float angleY = 0, float timer = 0.2f)
{
newTarget = LimitHeight(newTarget);
target = newTarget;
distance += dis;
DOTween.To(() => distance, x => distance = x, dis, timer).OnUpdate(() =>
{
distance = Mathf.Clamp(distance, distanceClamp.x, distanceClamp.y);
});
horizontal = angleY;
vertical = angleX;
}
///
/// 定位摄像机到某个位置
///
///
public void ResetPosition(Vector3 position, float timer = 0.2f)
{
float targetDis = Vector3.Distance(target, position);
DOTween.To(() => distance, x => distance = x, targetDis, timer).OnUpdate(() =>
{
distance = Mathf.Clamp(distance, distanceClamp.x, distanceClamp.y);
});
Vector3 tempPos = position - target;
double square = tempPos.x * tempPos.x + tempPos.z * tempPos.z;
double sqrt = System.Math.Sqrt(square);
float ratio = (float)sqrt / targetDis;
float deg = Mathf.Acos(ratio);
float angle = deg * Mathf.Rad2Deg;
vertical = angle * Mathf.Sign(tempPos.y);
square = targetDis * targetDis - tempPos.y * tempPos.y;
sqrt = System.Math.Sqrt(square);
if (sqrt == 0) sqrt = 0.001f;
ratio = tempPos.x / (float)sqrt;
deg = Mathf.Acos(ratio);
angle = 90 - deg * Mathf.Rad2Deg;
angle += 180;
if (tempPos.z < 0)
{
angle = 180 - angle;
}
horizontal = angle;
x %= 360;
}
///
/// 设置与目标之间的距离
///
///
public void SetDistance(float value)
{
if (value <= 0)
{
value = 0;
}
distance = value;
}
///
/// 设置距离最大最小值
///
///
///
public void SetDistanceClamp(float min = 1, float max = 10000)
{
distanceClamp = new Vector2(min, max);
}
///
/// 相机自动旋转
///
private void AutoRotate()
{
horizontal -= autoRotateSpeed * Time.deltaTime;
}
///
/// 设置是否自动旋转
///
///
public void SetAutoRotate(bool rotate, float speed = 2)
{
autoRotate = rotate;
autoRotateSpeed = speed;
}
///
/// 获取整体缩放
///
///
private float GetZoom()
{
return Distance / 100;
}
///
///
///
public float Horizontal
{
get
{
return horizontal;
}
set
{
horizontal += value;
}
}
///
///
///
public float Vertical
{
get
{
return vertical;
}
set
{
vertical += value;
}
}
private void OnGUI()
{
if (isSwitchingTarget)
{
GUI.color = new Color(1, 1, 1, fadeAlpha);
if (fadeTexture != null)
GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), fadeTexture, ScaleMode.StretchToFill);
return;
}
}
private void OnDestroy()
{
hasInit = false;
}
void OnDrawGizmosSelected()
{
Gizmos.color = new Color32(0, 221, 221, 255);
if (target != null)
{
Gizmos.DrawLine(transform.position, target);
Gizmos.matrix = Matrix4x4.TRS(target, transform.rotation, new Vector3(1f, 0, 1f));
Gizmos.DrawWireSphere(target, Distance);
Gizmos.matrix = Matrix4x4.identity;
}
Gizmos.DrawCube(transform.position, new Vector3(1, 0.2f, 0.2f));
Gizmos.DrawCube(transform.position, Vector3.one / 2);
}
///
/// 限制角度
///
///
///
///
///
public static float ClampAngle(float angle, float min, float max)
{
if (angle < -360f)
{
angle += 360f;
}
if (angle > 360f)
{
angle -= 360f;
}
return Mathf.Clamp(angle, min, max);
}
}