using DG.Tweening; using UnityEngine; using NaughtyAttributes; using UnityEngine.EventSystems; namespace Framework.Scripts.Runtime.Engine.Engine.Camera.CameraControl { public class CameraControlComponent : ICameraController { public enum CameraEnum { TopView, FrontView } //相机跟随的目标物体,一般是一个空物体 [SerializeField] private GameObject target; [HorizontalLine(color: EColor.Blue)] [SerializeField] [Label("启用旋转")] private bool enableMouseFunctions = true; [SerializeField] [Label("启用鼠标碰到UI禁用脚本")] private bool enableMouseOverUI = true; [SerializeField] private CameraEnum cameraEnum; private float middleSpeed = 2; private int MouseWheelSensitivity = 1; //滚轮灵敏度设置 private int MouseZoomMin = 10; //相机距离最小值 private int MouseZoomMax = 9999; //相机距离最大值 private float xSpeed = 250.0f; //旋转视角时相机x轴转速 private float ySpeed = 120.0f; //旋转视角时相机y轴转速 private float Distance = 20; //相机和target之间的距离,因为相机的Z轴总是指向target,也就是相机z轴方向上的距离 //[BoxGroup("参数")][SerializeField][Label("角度最小限制")] private int yMinLimit = -360; //[BoxGroup("参数")][SerializeField][Label("角度最大限制")] private int yMaxLimit = 360; private Vector2 minMaxSlider; private float x = 0.0f; //存储相机的euler角 private float y = 0.0f; //存储相机的euler角 private Vector3 targetOnScreenPosition; //目标的屏幕坐标,第三个值为z轴距离 private Quaternion storeRotation; //存储相机的姿态四元数 private Vector3 CameraTargetPosition; //target的位置 private Vector3 initPosition; //平移时用于存储平移的起点位置 private Vector3 cameraX; //相机的x轴方向向量 private Vector3 cameraY; //相机的y轴方向向量 private Vector3 cameraZ; //相机的z轴方向向量 private Vector3 initScreenPos; //中键刚按下时鼠标的屏幕坐标(第三个值其实没什么用) private Vector3 curScreenPos; //当前鼠标的屏幕坐标(第三个值其实没什么用) private Vector2 jilu; private Transform cameraTransform; public void Init(Transform cam, Transform target) { cameraTransform = cam; this.target = target.gameObject; cameraEnum = CameraEnum.FrontView; Vector3 angles = cameraTransform.eulerAngles; x = angles.y; y = angles.x; CameraTargetPosition = target.transform.position; Distance = Vector3.Distance(cameraTransform.position, target.transform.position); // 给摄像机一个初始的位置和角度 SetCameraPositionAndRotation(); } public void MoveTargetTo(Vector3 newPosition, float newfloat) { target.transform.DOMove(newPosition, 2).OnUpdate(() => { Vector3 mPosition = storeRotation * new Vector3(0.0F, 0.0F, -Distance) + target.transform.position; cameraTransform.position = mPosition; CameraTargetPosition = target.transform.position; } ); } void SetCameraPositionAndRotation() { //Vector3 position = rotation * new Vector3(0.0f, 0.0f, -11) + target.transform.position; x += Input.GetAxis("Mouse X") * xSpeed * 0.02f; y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f; y = ClampAngle(y, minMaxSlider.x, minMaxSlider.y); storeRotation = Quaternion.Euler(y, x, 0); var position = storeRotation * new Vector3(0.0f, 0.0f, -Distance) + CameraTargetPosition; cameraTransform.rotation = storeRotation; cameraTransform.position = position; } //将angle限制在min~max之间 static float ClampAngle(float angle, float min, float max) { if (angle < -360) angle += 360; if (angle > 360) angle -= 360; return Mathf.Clamp(angle, min, max); } public GameObject GetTarget() { return target; } public void UpdateValue(Vector2 minMax) { minMaxSlider = minMax; } public void ControlCamera() { if (enableMouseOverUI) { if (EventSystem.current.IsPointerOverGameObject()) { return; } } if (enableMouseFunctions) { //鼠标右键旋转功能 if (Input.GetMouseButton(1)) { //如果是顶视图,只能左右旋转,不能上下 if (cameraEnum == CameraEnum.FrontView) { x += Input.GetAxis("Mouse X") * xSpeed * 0.02f; y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f; y = ClampAngle(y, minMaxSlider.x, minMaxSlider.y); storeRotation = Quaternion.Euler(y, x, 0); var position = storeRotation * new Vector3(0.0f, 0.0f, -Distance) + CameraTargetPosition; Debug.Log(storeRotation); cameraTransform.rotation = storeRotation; cameraTransform.position = position; } else { x += Input.GetAxis("Mouse X") * xSpeed * 0.02f; //y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f; //y = ClampAngle(y, minMaxSlider.x, minMaxSlider.y); storeRotation = Quaternion.Euler(90, x, 0); var position = storeRotation * new Vector3(0.0f, 0.0f, -Distance) + CameraTargetPosition; cameraTransform.rotation = storeRotation; cameraTransform.position = position; } } else if (Input.GetAxis("Mouse ScrollWheel") != 0) //鼠标滚轮缩放功能 { if (Distance >= MouseZoomMin && Distance <= MouseZoomMax) { Distance -= Input.GetAxis("Mouse ScrollWheel") * MouseWheelSensitivity; } if (Distance < MouseZoomMin) { Distance = MouseZoomMin; } if (Distance > MouseZoomMax) { Distance = MouseZoomMax; } cameraTransform.position = storeRotation * new Vector3(0.0F, 0.0F, -Distance) + CameraTargetPosition; } //鼠标中键平移 if (Input.GetMouseButtonDown(2)) { cameraX = cameraTransform.right; cameraY = cameraTransform.up; cameraZ = cameraTransform.forward; initScreenPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, targetOnScreenPosition.z); Debug.Log("downOnce"); //targetOnScreenPosition.z为目标物体到相机xmidbuttonDownPositiony平面的法线距离 if (UnityEngine.Camera.main != null) targetOnScreenPosition = UnityEngine.Camera.main.WorldToScreenPoint(CameraTargetPosition); initPosition = CameraTargetPosition; } if (Input.GetMouseButton(2)) { curScreenPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, targetOnScreenPosition.z); //0.01这个系数是控制平移的速度,要根据相机和目标物体的distance来灵活选择 Vector3 vv = initPosition - (0.01f * middleSpeed) * ((curScreenPos.x - initScreenPos.x) * cameraX + (curScreenPos.y - initScreenPos.y) * cameraY); target.transform.position = new Vector3(vv.x, vv.y, vv.z); //重新计算位置 Vector3 mPosition = storeRotation * new Vector3(0.0F, 0.0F, -Distance) + target.transform.position; cameraTransform.position = mPosition; // //用这个会让相机的平移变得更平滑,但是可能在你buttonup时未使相机移动到应到的位置,导致再进行旋转与缩放操作时出现短暂抖动 //transform.position=Vector3.Lerp(transform.position,mPosition,Time.deltaTime*moveSpeed); } if (Input.GetMouseButtonUp(2)) { Debug.Log("upOnce"); //平移结束把cameraTargetPosition的位置更新一下,不然会影响缩放与旋转功能 CameraTargetPosition = target.transform.position; } } } } }