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; /// /// 禁止操作 /// 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; } /// /// /// void Start() { //SetUp(); //thisTra = new ModelTraState(transform); //targetTra = new ModelTraState(Target); } /// /// /// 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; } /// /// 检查鼠标是否在UI上 /// /// /// public bool CheckMouseOnUI() { if (EventSystem.current.IsPointerOverGameObject()) { PointerEventData pointerEventData = new PointerEventData(EventSystem.current); pointerEventData.position = Input.mousePosition; List result = new List(); EventSystem.current.RaycastAll(pointerEventData, result); if (result.Count > 0) { if (result[0].gameObject.layer == 13) return true; } return false; } return false; } /// /// /// 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(); } } /// /// 平移 /// 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) ); } /// /// 旋转 /// 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; } /// /// 缩放 /// /// 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); } /// /// 重置位置 /// 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; }