ShanxiKnowledgeBase/SXKnowledgeBase-master/sxknowledgebase/Assets/Scripts/Camera/OrbitCamera.cs

373 lines
11 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using DG.Tweening;
public class OrbitCamera /*: bl_CameraBase*/ : MonoBehaviour
{
public static OrbitCamera Instance;
/// <summary>
/// 禁止操作
/// </summary>
public static bool ProhibitOperations;
//private GameManager GameManager { get { return GameManager.Instance; } }
[Header("Target")]
public Transform Target;
[Header("Settings")]
public bool AutoTakeInfo = true;
public float Distance = 5f;
public Vector2 DistanceClamp = new Vector2(5f, 90);
public Vector2 YAngelLimitClamp = new Vector2(-20, 80);
public Vector2 XAngelLimitClamp = new Vector2(360, 360); //Clamp the horizontal angle from the start position (max left = x, max right = y) >= 360 = not limit
[Range(0.01f, 50), Header("平移"), Tooltip("平移灵敏度")]
public float PanSpeed = 0.5f;
public Vector2 PanXClamp = new Vector2(-100, 300);
public Vector2 PanYClamp = new Vector2(-100, 300);
public Vector2 PanZClamp = new Vector2(-100, 300);
[Range(0.1f, 50f), Header("缩放"), Tooltip("缩放灵敏度")]
public float ZoomSpeed = 2f;
[Range(1, 25)]
public float ZoomLerpSpeed = 7;
[Header("动态调整平移、缩放速度")]
public bool DynamicSpeed;
public float DynamicMultiple = 2;
[Range(0.1f, 5f), Header("旋转"), Tooltip("旋转灵敏度")]
public float RotateSpeed = 0.2f;
[Range(0.1f, 15)]
public float RotateLerpSpeed = 7;
[Header("ReadOnly")]
[SerializeField]
private float y;
[SerializeField]
private float x;
[HideInInspector]
public float distance = 0;
public float horizontal;
public float vertical;
private Vector3 ZoomVector;
private Quaternion CurrentRotation;
private Vector3 CurrentPosition;
private float initXRotation;
#region MyRegion
private bool Reseting = false;
private ModelTraState thisTra;
private ModelTraState targetTra;
#endregion
private void Awake()
{
Instance = this;
}
/// <summary>
///
/// </summary>
void Start()
{
//SetUp();
//thisTra = new ModelTraState(transform);
//targetTra = new ModelTraState(Target);
}
/// <summary>
///
/// </summary>
void SetUp()
{
if (AutoTakeInfo)
{
distance = Vector3.Distance(transform.position, Target.position);
Distance = distance;
Vector3 eulerAngles = transform.eulerAngles;
x = eulerAngles.y;
y = eulerAngles.x;
initXRotation = eulerAngles.y;
horizontal = x;
vertical = y;
}
else
{
distance = Distance;
}
Reseting = false;
}
/// <summary>
/// 检查鼠标是否在UI上
/// </summary>
/// <param name="uiPanel"></param>
/// <returns></returns>
public bool CheckMouseOnUI()
{
if (EventSystem.current.IsPointerOverGameObject())
{
PointerEventData pointerEventData = new PointerEventData(EventSystem.current);
pointerEventData.position = Input.mousePosition;
List<RaycastResult> result = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointerEventData, result);
if (result.Count > 0)
{
if (result[0].gameObject.layer == 13)
return true;
}
return false;
}
return false;
}
/// <summary>
///
/// </summary>
void LateUpdate()
{
//if (Target == null)
//{
// Debug.LogWarning("Target is not assigned to orbit camera!", this);
// return;
//}
if (ProhibitOperations)
return;
#region ControlByKeyboard
if (Input.GetMouseButton(2))
{
float mx = Input.GetAxis("Mouse X");
float my = Input.GetAxis("Mouse Y");
PanControl(mx, my);
}
if (Input.GetMouseButton(1))
{
float mx = Input.GetAxis("Mouse X");
float my = Input.GetAxis("Mouse Y");
OrbitControll(mx, my);
}
if (Input.GetAxis("Mouse ScrollWheel") != 0)
{
float ms = Input.GetAxis("Mouse ScrollWheel");
ZoomControll(ms);
}
#endregion
if (!Reseting)
{
ZoomApply();
OrbitApply();
}
}
/// <summary>
/// 平移
/// </summary>
public void PanControl(float AxisX, float AxisY)
{
float speedXModify = Mathf.Clamp(PanSpeed * distance / DistanceClamp.y, 0.01f, 1f);
float speedYModify = Mathf.Clamp(PanSpeed * distance / DistanceClamp.y, 0.01f, 1f);
speedXModify = DynamicSpeed ? speedXModify * DynamicSpeedByDistance() : speedXModify;
speedYModify = DynamicSpeed ? speedXModify * DynamicSpeedByDistance() : speedYModify;
Target.position -= transform.right * AxisX * speedXModify; //左右
Target.position -= transform.up * AxisY * speedYModify;//上下
//Target.position -= new Vector3(transform.forward.x, 0, transform.forward.z) * AxisY * speedYModify;//前后
Target.position = new Vector3(
//Mathf.Clamp(Target.position.x, -1000, 1000),
//Mathf.Clamp(Target.position.y, PanYClamp.x, PanYClamp.y),
//Mathf.Clamp(Target.position.z, -1000, 1000)
Mathf.Clamp(Target.position.x, PanXClamp.x, PanXClamp.y),
Mathf.Clamp(Target.position.y, PanYClamp.x, PanYClamp.y),
Mathf.Clamp(Target.position.z, PanZClamp.x, PanZClamp.y)
);
}
/// <summary>
/// 旋转
/// </summary>
public void OrbitControll(float AxisX, float AxisY)
{
horizontal += RotateSpeed * AxisX;
vertical -= RotateSpeed * AxisY;
//clamp 'vertical' angle
vertical = ClampAngle(vertical, YAngelLimitClamp.x, YAngelLimitClamp.y);
if (XAngelLimitClamp.x < 360 && XAngelLimitClamp.y < 360)
{
horizontal = ClampAngle(horizontal, (initXRotation - XAngelLimitClamp.y), (XAngelLimitClamp.x + initXRotation));
}
}
private void OrbitApply()
{
//smooth movement of responsiveness input.
x = Mathf.Lerp(x, horizontal, Time.deltaTime * RotateLerpSpeed);
y = Mathf.Lerp(y, vertical, Time.deltaTime * RotateLerpSpeed);
//clamp 'y' angle
y = ClampAngle(y, YAngelLimitClamp.x, YAngelLimitClamp.y);
//convert vector to quaternion for apply to rotation
CurrentRotation = Quaternion.Euler(y, x, 0f);
//calculate the position and clamp on a circle
CurrentPosition = ((CurrentRotation * ZoomVector)) + Target.position;
//switch in the movement select
transform.position = CurrentPosition;
transform.rotation = CurrentRotation;
}
/// <summary>
/// 缩放
/// </summary>
/// <param name="scale"></param>
public void ZoomControll(float scale)
{
//var dynamicVaule = Mathf.Clamp(distance / (DistanceClamp.y - DistanceClamp.x), 0.1f, 1f);
var dynamicVaule = DynamicSpeed ? scale * DynamicSpeedByDistance() : scale;
distance = Mathf.Clamp(distance - ZoomSpeed * dynamicVaule, DistanceClamp.x, DistanceClamp.y);
//根据距离动态调整缩放速度
//0.1 - 1
//Mathf.Clamp(distance / (DistanceClamp.y - DistanceClamp.x), 0.1f, 1f);
//clamp distance and check this.
//if (scale >= 0f)
// distance = Mathf.Clamp(distance * (1 - ZoomSpeed * (1 - scale)), DistanceClamp.x, DistanceClamp.y);
//else
// distance = Mathf.Clamp(distance * (1 + ZoomSpeed * (scale - 1)), DistanceClamp.x, DistanceClamp.y);
}
private void ZoomApply()
{
//distance = (distance < 0.1f) ? 0.1f : distance;// distance is recommendable never is least than 1
//Distance = Mathf.SmoothStep(Distance, distance, Time.deltaTime * ZoomLerpSpeed);
Distance = Mathf.Lerp(Distance, distance, Time.deltaTime * ZoomLerpSpeed);
//apply distance to vector depth z
ZoomVector = new Vector3(0f, 0f, -this.Distance);
}
/// <summary>
/// 重置位置
/// </summary>
public void ResetTransform(System.Action callback)
{
Reseting = true;
transform.DOMove(thisTra.Position, 0.5f);
transform.DORotate(thisTra.Rotation, 0.5f);
Target.DOMove(targetTra.Position, 0.5f).OnComplete(() =>
{
SetUp();
callback?.Invoke();
});
}
void OnDrawGizmosSelected()
{
Gizmos.color = new Color32(0, 221, 221, 255);
if (Target != null)
{
Gizmos.DrawLine(transform.position, Target.position);
Gizmos.matrix = Matrix4x4.TRS(Target.position, transform.rotation, new Vector3(1f, 0, 1f));
Gizmos.DrawWireSphere(Target.position, Distance);
Gizmos.matrix = Matrix4x4.identity;
}
Gizmos.DrawCube(transform.position, new Vector3(1, 0.2f, 0.2f));
Gizmos.DrawCube(transform.position, Vector3.one / 2);
}
public float ClampAngle(float angle, float min, float max)
{
if (angle < -360f)
{
angle += 360f;
}
if (angle > 360f)
{
angle -= 360f;
}
return Mathf.Clamp(angle, min, max);
}
public float DynamicSpeedByDistance()
{
var value = 1 + distance / (DistanceClamp.y - DistanceClamp.x) * DynamicMultiple;
return value;
}
public void Init(CameraSettingsParam cameraSettings, Transform Target)
{
Reseting = true;
//回到正面
//transform.eulerAngles = Vector3.zero;
transform.rotation = Quaternion.Euler(cameraSettings.CameraInitEulerAng);
Vector3 eulerAngles = transform.eulerAngles;
x = eulerAngles.y;
y = eulerAngles.x;
initXRotation = eulerAngles.y;
horizontal = x;
vertical = y;
Distance = cameraSettings.Distance;
DistanceClamp = cameraSettings.DistanceClamp;
PanSpeed = cameraSettings.PanSpeed;
ZoomSpeed = cameraSettings.ZoomSpeed;
this.Target.position = Target.position;
SetUp();
thisTra = new ModelTraState(transform);
targetTra = new ModelTraState(this.Target);
}
}
public class ModelTraState
{
public ModelTraState(Transform tra)
{
if (tra != null)
{
Position = tra.position;
Rotation = tra.rotation.eulerAngles;
Scale = tra.localScale;
}
else
{
Position = Vector3.zero;
Rotation = Vector3.zero;
}
}
public Vector3 Position;
public Vector3 Rotation;
public Vector3 Scale;
}