290 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			290 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C#
		
	
	
	
| using System.Collections;
 | |
| using System.Collections.Generic;
 | |
| using MyFrameworkPure;
 | |
| using UnityEngine;
 | |
| 
 | |
| #if STEAMVR
 | |
| using HTC.UnityPlugin.Vive;
 | |
| #endif
 | |
| 
 | |
| namespace CommonScript
 | |
| {
 | |
|     public enum MouseButton
 | |
|     {
 | |
|         Left = 0,
 | |
|         Right,
 | |
|         Middle,
 | |
|     }
 | |
|     /// <summary>
 | |
|     /// 相机旋转的通用脚本
 | |
|     /// </summary>
 | |
|     public class CameraRotator : MonoBehaviour
 | |
|     {
 | |
|         [Header("鼠标输入")]
 | |
|         [SerializeField] private bool enableMouseInput = true;
 | |
| 
 | |
|         [SerializeField] private MouseButton mouseButton = MouseButton.Left;
 | |
|         [SerializeField] private float mouseRotSpeed = 5;
 | |
| 
 | |
|         [Header("触屏输入")]
 | |
|         [SerializeField] private bool enableTouchInput = true;
 | |
| 
 | |
| #if STEAMVR
 | |
|         [Header("Vive输入")]
 | |
|         [SerializeField] private bool enableViveInput = true;
 | |
|         [SerializeField] private ViveRoleProperty viveRoleProperty = ViveRoleProperty.New(HandRole.RightHand);
 | |
|         [SerializeField] private float viveRotSpeed = 30;
 | |
| #endif
 | |
| 
 | |
|         [Header("其他参数")]
 | |
|         [SerializeField] private Transform cameraTransform;
 | |
|         [SerializeField] private Transform target;
 | |
|         [SerializeField] private bool lookatTarget = true;
 | |
|         [SerializeField] private bool allowZoom = true;
 | |
|         [SerializeField] private float zoomSpeed = 50;
 | |
|         [SerializeField] private float farestToTarget = 3000f;
 | |
|         [SerializeField] private float nearestToTarget = 0f;
 | |
| 
 | |
|         [SerializeField] private bool clampEuler = true;
 | |
|         [SerializeField] private float minEulerX = 0;
 | |
|         [SerializeField] private float maxEulerX = 180;
 | |
|         [SerializeField] private float minEulerY = -180;
 | |
|         [SerializeField] private float maxEulerY = 180;
 | |
|         public Transform target_yinyong;
 | |
|         private Vector3 lastMousePos;
 | |
|         private Vector2 lastTouchPos;
 | |
| 
 | |
|         private Vector3 lastCameraPos;
 | |
|         private Vector3 lastCameraRot;
 | |
|         // Start is called before the first frame update
 | |
|         void Start()
 | |
|         {
 | |
|             cameraTransform = cameraTransform != null?cameraTransform:transform;
 | |
|             SetTarget(target);
 | |
|         }
 | |
| 
 | |
|         // Update is called once per frame
 | |
|         void Update()
 | |
|         {
 | |
|             if (enableMouseInput)
 | |
|                 HandleMouseInput();
 | |
|             if (enableTouchInput)
 | |
|                 HandleTouchInput();
 | |
|             //if (enableViveInput)
 | |
|             //    HandleViveInput();
 | |
|             if (clampEuler)
 | |
|                 ClampEuler();
 | |
|             if (lookatTarget && target)
 | |
|             {
 | |
|                 cameraTransform.LookAt(target);
 | |
|             }
 | |
| 
 | |
|             if (allowZoom && target)
 | |
|             {
 | |
|                 ClameDistanceToTarget();
 | |
|             }
 | |
| 
 | |
|             RecordCameraTransform();
 | |
|         }
 | |
| 
 | |
|         public void SetTarget(Transform target)
 | |
|         {
 | |
|             //校验目标物合法性
 | |
|             if (target)
 | |
|             {
 | |
|                 float distance = Vector3.Distance(cameraTransform.position, target.position);
 | |
|                 if (allowZoom && (distance > farestToTarget || distance < nearestToTarget))
 | |
|                 {
 | |
|                     Debug.LogError("相机初始位置不满足要求!");
 | |
|                     return;
 | |
|                 }
 | |
|                 Vector3 euler = VectorTool.ConvertToEuler180(cameraTransform.eulerAngles);
 | |
|                 if (clampEuler && (euler.x < minEulerX || euler.x > maxEulerX))
 | |
|                 {
 | |
|                     Debug.LogError("相机旋转X分量不满足要求");
 | |
|                     return;
 | |
|                 }
 | |
|                 if (clampEuler && (euler.y < minEulerY || euler.y > maxEulerY))
 | |
|                 {
 | |
|                     Debug.LogError("相机旋转Y分量不满足要求");
 | |
|                     return;
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (allowZoom || lookatTarget)
 | |
|                 {
 | |
|                     Debug.LogError("开启相机缩放或朝向目标开关,要求目标物不能为空!");
 | |
|                     return;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             this.target = target;
 | |
|             RecordCameraTransform();
 | |
|             target_yinyong = target;
 | |
|         }
 | |
| 
 | |
|         void HandleMouseInput()
 | |
|         {
 | |
|             if (Input.GetMouseButtonDown((int)mouseButton))
 | |
|             {
 | |
|                 lastMousePos = Input.mousePosition;
 | |
|             }
 | |
|             if (Input.GetMouseButton((int)mouseButton))
 | |
|             {
 | |
|                 Vector3 delta = Input.mousePosition - lastMousePos;
 | |
|                 if (target)
 | |
|                 {
 | |
|                     cameraTransform.RotateAround(target.position,-cameraTransform.right, delta.y * mouseRotSpeed * Time.deltaTime);
 | |
|                     ClampPosFromEulerX();
 | |
| 
 | |
|                     cameraTransform.RotateAround(target.position,Vector3.up,delta.x * mouseRotSpeed * Time.deltaTime);
 | |
|                     ClampPosFromEulerY();
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     cameraTransform.Rotate(Vector3.left * delta.y * mouseRotSpeed * Time.deltaTime, Space.Self);
 | |
|                     cameraTransform.Rotate(Vector3.up * delta.x * mouseRotSpeed * Time.deltaTime, Space.World);
 | |
|                 }
 | |
|                 lastMousePos = Input.mousePosition;
 | |
|             }
 | |
| 
 | |
|             if (allowZoom)
 | |
|             {
 | |
|                 float mouseScroll = Input.GetAxis("Mouse ScrollWheel");
 | |
|                 cameraTransform.Translate(Vector3.forward * mouseScroll * zoomSpeed * Time.deltaTime);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void HandleTouchInput()
 | |
|         {
 | |
|             if(Input.touchCount == 0)
 | |
|                 return;
 | |
|             Touch touch = Input.GetTouch(0);
 | |
|             if (touch.phase == TouchPhase.Began)
 | |
|             {
 | |
|                 lastTouchPos = touch.position;
 | |
|             }
 | |
|             else if(touch.phase == TouchPhase.Moved)
 | |
|             {
 | |
|                 Vector3 delta = touch.position - lastTouchPos;
 | |
|                 if (target)
 | |
|                 {
 | |
|                     cameraTransform.RotateAround(target.position, -cameraTransform.right, delta.y * mouseRotSpeed * Time.deltaTime);
 | |
|                     ClampPosFromEulerX();
 | |
| 
 | |
|                     cameraTransform.RotateAround(target.position, Vector3.up, delta.x * mouseRotSpeed * Time.deltaTime);
 | |
|                     ClampPosFromEulerY();
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     cameraTransform.Rotate(Vector3.left * delta.y * mouseRotSpeed * Time.deltaTime, Space.Self);
 | |
|                     cameraTransform.Rotate(Vector3.up * delta.x * mouseRotSpeed * Time.deltaTime, Space.World);
 | |
|                 }
 | |
|                 
 | |
|                 lastTouchPos = touch.position;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void HandleViveInput()
 | |
|         {
 | |
| #if STEAMVR
 | |
|             Vector2 pressPos = HTC.UnityPlugin.Vive.ViveInput.GetPadPressAxis(viveRoleProperty);
 | |
|             if(Vector2.Distance(Vector2.zero,pressPos) < 0.01f)
 | |
|                 return;
 | |
|             //将触摸板位置划分上下左右四块区域
 | |
|             float angle = Vector2.SignedAngle(Vector2.right, pressPos);
 | |
|             if (angle > -45 && angle <= 45)
 | |
|             {
 | |
|                 pressPos = Vector2.right;
 | |
|             }
 | |
|             else if(angle > 45 && angle <=135)
 | |
|             {
 | |
|                 pressPos = Vector2.up;
 | |
|             }
 | |
|             else if(angle > 135 || angle < -135)
 | |
|             {
 | |
|                 pressPos = Vector2.left;
 | |
|             }
 | |
|             else 
 | |
|             {
 | |
|                 pressPos = Vector2.down;
 | |
|             }
 | |
| 
 | |
|             if (target)
 | |
|             {
 | |
|                 cameraTransform.RotateAround(target.position, -cameraTransform.right, pressPos.y * viveRotSpeed * Time.deltaTime);
 | |
|                 ClampPosFromEulerX();
 | |
| 
 | |
|                 cameraTransform.RotateAround(target.position, Vector3.up, pressPos.x * viveRotSpeed * Time.deltaTime);
 | |
|                 ClampPosFromEulerY();
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 cameraTransform.Rotate(Vector3.left * pressPos.y * viveRotSpeed * Time.deltaTime, Space.Self);
 | |
|                 cameraTransform.Rotate(Vector3.up * pressPos.x * viveRotSpeed * Time.deltaTime, Space.World);
 | |
|             }
 | |
| #endif
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// 限制相机旋转角度
 | |
|         /// </summary>
 | |
|         void ClampEuler()
 | |
|         {
 | |
|             Vector3 euler = VectorTool.ConvertToEuler180(cameraTransform.eulerAngles);
 | |
|             euler = new Vector3(Mathf.Clamp(euler.x,minEulerX,maxEulerX),Mathf.Clamp(euler.y,minEulerY,maxEulerY),0);
 | |
|             cameraTransform.eulerAngles = euler;
 | |
|         }
 | |
| 
 | |
|         void ClampPosFromEulerX()
 | |
|         {
 | |
|             Vector3 euler = VectorTool.ConvertToEuler180(cameraTransform.eulerAngles);
 | |
|             if (euler.x < minEulerX || euler.x > maxEulerX)
 | |
|             {
 | |
|                 RestoreCameraTransform();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void ClampPosFromEulerY()
 | |
|         {
 | |
|             Vector3 euler = VectorTool.ConvertToEuler180(cameraTransform.eulerAngles);
 | |
|             if (euler.y < minEulerY || euler.y > maxEulerY)
 | |
|             {
 | |
|                 RestoreCameraTransform();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// 限制相机到目标的距离
 | |
|         /// </summary>
 | |
|         void ClameDistanceToTarget()
 | |
|         {
 | |
|             float distance = Vector3.Distance(cameraTransform.position, target.position);
 | |
|             if (distance < nearestToTarget || distance > farestToTarget)
 | |
|             {
 | |
|                 RestoreCameraTransform();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// 记录相机的变换信息
 | |
|         /// </summary>
 | |
|         void RecordCameraTransform()
 | |
|         {
 | |
|             lastCameraPos = cameraTransform.transform.position;
 | |
|             lastCameraRot = cameraTransform.transform.eulerAngles;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// 恢复相机变换到上一帧
 | |
|         /// </summary>
 | |
|         void RestoreCameraTransform()
 | |
|         {
 | |
|             cameraTransform.position = lastCameraPos;
 | |
|             cameraTransform.eulerAngles = lastCameraRot;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 |