diff --git a/Assets/CameraBehaviour.cs b/Assets/CameraBehaviour.cs new file mode 100644 index 0000000..b0507c6 --- /dev/null +++ b/Assets/CameraBehaviour.cs @@ -0,0 +1,145 @@ +using UnityEngine; + +public class CameraBehaviour : MonoBehaviour +{ + public Transform target; + + private const int MouseWheelSensitivity = 1; //滚轮灵敏度设置 + private const int MouseZoomMin = 1; //相机距离最小值 + private const int MouseZoomMax = 20; //相机距离最大值 + private const float XSpeed = 250.0f; + private const float YSpeed = 120.0f; + + private const int YMinLimit = -360; + private const int YMaxLimit = 360; + + private float _eulerX; //存储相机的euler角 + private float _eulerY; //存储相机的euler角 + + private float _distance = 5; //相机和target之间的距离,因为相机的Z轴总是指向target,也就是相机z轴方向上的距离 + private Vector3 _targetOnScreenPosition; //目标的屏幕坐标,第三个值为z轴距离 + private Quaternion _cameraRotation; //存储相机的姿态四元数 + private Vector3 _targetPosition; //target的位置 + private Vector3 _initPosition; //平移时用于存储平移的起点位置 + private Vector3 _cameraX; //相机的x轴方向向量 + private Vector3 _cameraY; //相机的y轴方向向量 + private Vector3 _cameraZ; //相机的z轴方向向量 + + private Vector3 _initScreenPosition; //中键刚按下时鼠标的屏幕坐标(第三个值其实没什么用) + private Vector3 _cursorScreenPosition; //当前鼠标的屏幕坐标(第三个值其实没什么用) + + private void Start() + { + //这里就是设置一下初始的相机视角以及一些其他变量,这里的x和y。。。是和下面getAxis的mouse x与mouse y对应 + var angles = transform.eulerAngles; + _eulerX = angles.y; + _eulerY = angles.x; + _targetPosition = target.position; + _cameraRotation = Quaternion.Euler(_eulerY + 60, _eulerX, 0); + // 引入中间变量 提高代码效率 + var transform1 = transform; + transform1.rotation = _cameraRotation; //设置相机姿态 + /*var position = + _cameraRotation * new Vector3(0.0F, 0.0F, -_distance) + + _targetPosition; //四元数表示一个旋转,四元数乘以向量相当于把向量旋转对应角度,然后加上目标物体的位置就是相机位置了*/ + transform1.position = _cameraRotation * new Vector3(0, 0, -_distance) + _targetPosition; //设置相机位置 + } + + private void Update() + { + //鼠标右键旋转功能 + if (Input.GetMouseButton(1)) + { + _eulerX += Input.GetAxis("Mouse X") * XSpeed * 0.02f; + _eulerY -= Input.GetAxis("Mouse Y") * YSpeed * 0.02f; + + _eulerY = ClampAngle(_eulerY, YMinLimit, YMaxLimit); + + _cameraRotation = Quaternion.Euler(_eulerY + 60, _eulerX, 0); + var position = _cameraRotation * new Vector3(0.0f, 0.0f, -_distance) + _targetPosition; + + // 引入中间变量 提高代码效率 + var transform1 = transform; + transform1.rotation = _cameraRotation; + transform1.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; + } + + transform.position = _cameraRotation * new Vector3(0.0F, 0.0F, -_distance) + _targetPosition; + } + + //鼠标中键平移 + if (Input.GetMouseButtonDown(2)) + { + // 添加中间变量 + // 提高代码效率 + var transform1 = transform; + _cameraX = transform1.right; + _cameraY = transform1.up; + _cameraZ = transform1.forward; + + _initScreenPosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, _targetOnScreenPosition.z); + + //targetOnScreenPosition.z为目标物体到相机平面的法线距离 + _targetOnScreenPosition = Camera.main!.WorldToScreenPoint(_targetPosition); + _initPosition = _targetPosition; + } + + if (Input.GetMouseButton(2)) + { + _cursorScreenPosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, _targetOnScreenPosition.z); + //0.01这个系数是控制平移的速度,要根据相机和目标物体的distance来灵活选择 + target.position = _initPosition - 0.01f * ((_cursorScreenPosition.x - _initScreenPosition.x) * _cameraX + + (_cursorScreenPosition.y - _initScreenPosition.y) * _cameraY); + + //重新计算位置 + var mPosition = _cameraRotation * new Vector3(0.0F, 0.0F, -_distance) + target.position; + transform.position = mPosition; + + // //用这个会让相机的平移变得更平滑,但是可能在你ButtonUp时未使相机移动到应到的位置,导致再进行旋转与缩放操作时出现短暂抖动 + //transform.position=Vector3.Lerp(transform.position,mPosition,Time.deltaTime*moveSpeed); + } + + if (Input.GetMouseButtonUp(2)) + { + Debug.Log("upOnce"); + //平移结束把cameraTargetPosition的位置更新一下,不然会影响缩放与旋转功能 + _targetPosition = target.position; + } + } + + //将angle限制在min~max之间 + private 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); + } + + /*void testScreenToWorldPoint() + { + //第三个坐标指的是在相机z轴指向方向上的距离 + Vector3 screenPoint = Camera.main.WorldToScreenPoint(_targetPosition); + Debug.Log("ScreenPoint: " + screenPoint); + + // var worldPosition = Camera.main.ScreenToWorldPoint(new Vector3(1,1,10)); + // Debug.Log("worldPosition: "+worldPosition); + }*/ +} \ No newline at end of file diff --git a/Assets/CameraBehaviour.cs.meta b/Assets/CameraBehaviour.cs.meta new file mode 100644 index 0000000..e702713 --- /dev/null +++ b/Assets/CameraBehaviour.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9189b565e8ba9bfc3bdaa38149e3e13f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity index 101525e..0465b9b 100644 --- a/Assets/Scenes/SampleScene.unity +++ b/Assets/Scenes/SampleScene.unity @@ -339,6 +339,7 @@ GameObject: - component: {fileID: 963194228} - component: {fileID: 963194227} - component: {fileID: 963194226} + - component: {fileID: 963194229} m_Layer: 0 m_Name: Main Camera m_TagString: MainCamera @@ -412,6 +413,19 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &963194229 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9189b565e8ba9bfc3bdaa38149e3e13f, type: 3} + m_Name: + m_EditorClassIdentifier: + target: {fileID: 320693310} --- !u!1 &1880773849 GameObject: m_ObjectHideFlags: 0