373 lines
11 KiB
C#
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;
|
|
} |