鼠标滚轮:缩放
鼠标右键:旋转
鼠标中键:平移
鼠标左键:选中实体(下面的代码中未实现)
注:
1.地形必须在Terrain图层下
2.相机上必须挂载Rigidbody+Collider,防止钻到地下。
Rigidbody的Interpolate:Interpolate
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; public class Viewer : MonoBehaviour { public Texture2D RotateIcon; public Texture2D PanIcon; public Rigidbody rigibodyCamera; public bool IsRecoverCameraForword = false; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { //鼠标是否在UI上 if (EventSystem.current != null && EventSystem.current.IsPointerOverGameObject()) { return; } //旋转视角 if (Input.GetMouseButtonDown(1)) { Cursor.SetCursor(RotateIcon, Vector3.zero, CursorMode.Auto); } if (Input.GetMouseButtonUp(1)) { Cursor.SetCursor(null, Vector3.zero, CursorMode.Auto); } if (Input.GetMouseButton(1)) { Vector3 ptCenter = rigibodyCamera.transform.position - rigibodyCamera.transform.forward * 0.1f; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hitInfo; LayerMask mask = 1 << (LayerMask.NameToLayer("Terrain")); //鼠标点在地面上,以鼠标点为旋转中心 if (Physics.Raycast(ray, out hitInfo, Mathf.Infinity, mask.value)) { ptCenter = hitInfo.point; float dist = Vector3.Distance(ptCenter, rigibodyCamera.transform.position); float axis_x = Input.GetAxis("Mouse X"); float axis_y = Input.GetAxis("Mouse Y"); float radius = 10.0f * dist; //防止相机钻到地面下 radius = GetMoveableRadius(radius); if (Mathf.Abs(axis_x) > Mathf.Abs(axis_y)) { float drag_x_speed = Mathf.Rad2Deg * (radius / dist); float rotX = axis_x * drag_x_speed * Time.deltaTime; rigibodyCamera.transform.RotateAround(ptCenter, Vector3.up, rotX); } else { float drag_y_speed = Mathf.Rad2Deg * (radius / dist); float rotY = axis_y * drag_y_speed * Time.deltaTime; rigibodyCamera.transform.RotateAround(ptCenter, -rigibodyCamera.transform.right, rotY); } } //鼠标没点在地面上,自由旋转 else { float axis_x = Input.GetAxis("Mouse X"); float axis_y = Input.GetAxis("Mouse Y"); if (Mathf.Abs(axis_x) > Mathf.Abs(axis_y)) { float drag_x_speed = 50.0f; float rotX = axis_x * drag_x_speed * Time.deltaTime; rigibodyCamera.transform.RotateAround(ptCenter, Vector3.up, rotX); } else { float drag_y_speed = 30.0f; float rotY = axis_y * drag_y_speed * Time.deltaTime; rigibodyCamera.transform.RotateAround(ptCenter, -rigibodyCamera.transform.right, rotY); } } } //放大 if (Input.GetAxis("Mouse ScrollWheel") > 0) { float speed = 50.0f; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hitInfo; LayerMask mask = 1 << (LayerMask.NameToLayer("Terrain")); if (Physics.Raycast(ray, out hitInfo, Mathf.Infinity, mask.value)) { speed = 0.25f * Vector3.Distance(hitInfo.point, ray.origin); } //防止相机钻到地面下 speed = GetMoveableRadius(speed); //相机往鼠标点的地方移动 Ray ray2 = Camera.main.ScreenPointToRay(Input.mousePosition); rigibodyCamera.MovePosition(rigibodyCamera.position + ray2.direction * speed); } //缩小 if (Input.GetAxis("Mouse ScrollWheel") < 0) { float speed = 50.0f; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hitInfo; LayerMask mask = 1 << (LayerMask.NameToLayer("Terrain")); if (Physics.Raycast(ray, out hitInfo, Mathf.Infinity, mask.value)) { speed = 0.5f * Vector3.Distance(hitInfo.point, ray.origin); } //防止相机钻到地面下 speed = GetMoveableRadius(speed); //相机往鼠标点的地方反方向移动 Ray ray2 = Camera.main.ScreenPointToRay(Input.mousePosition); rigibodyCamera.MovePosition(rigibodyCamera.position - ray2.direction * speed); if(IsRecoverCameraForword) { RecoverCameraForword(); } } //鼠标左键操作 if (Input.GetMouseButtonDown(2)) { Cursor.SetCursor(PanIcon, Vector3.zero, CursorMode.Auto); } if (Input.GetMouseButtonUp(2)) { Cursor.SetCursor(null, Vector3.zero, CursorMode.Auto); } if (Input.GetMouseButton(2)) { float speed = 20.0f; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hitInfo; LayerMask mask = 1 << (LayerMask.NameToLayer("Terrain")); if (Physics.Raycast(ray, out hitInfo, Mathf.Infinity, mask.value)) { speed = 0.05f * Vector3.Distance(hitInfo.point, ray.origin); } speed = GetMoveableRadius(speed); float x_mouse = -Input.GetAxis("Mouse X"); float y_mouse = -Input.GetAxis("Mouse Y"); float angle = Vector3.Angle(Camera.main.transform.forward, Vector3.down); if(angle < 5) { Vector3 vecTemp = Vector3.zero; vecTemp += speed * x_mouse * Camera.main.transform.right; vecTemp += 0.4f * speed * y_mouse * Camera.main.transform.up; //防止相机钻到地面下 float len = GetMoveableRadius(vecTemp.magnitude); rigibodyCamera.MovePosition(rigibodyCamera.position + vecTemp.normalized * len); } else { Vector3 vecTemp = Vector3.zero; Vector3 dir = Vector3.ProjectOnPlane(Camera.main.transform.forward, Vector3.up); vecTemp += speed * x_mouse * Camera.main.transform.right; vecTemp += speed * y_mouse * dir.normalized; //防止相机钻到地面下 float len = GetMoveableRadius(vecTemp.magnitude); rigibodyCamera.MovePosition(rigibodyCamera.position + vecTemp.normalized * len); } } } //计算可移动距离 private float GetMoveableRadius(float radius) { int i = 0; while (true) { i++; if (i > 50) { radius = 0.0f; break; } if (IsHaveCollider(Camera.main.transform.position, radius)) { radius = 0.5f * radius; } else { break; } } return radius; } //判断某个点,一定距离内有无碰撞物,-1为小于最小距离,0为位于两个距离内,1为大于最大距离 bool IsHaveCollider(Vector3 ptCenter, float radius1) { Collider[] collider1 = Physics.OverlapSphere(ptCenter, radius1); if (collider1.Length > 1) { return true; } return false; } //慢慢将相机朝下 void RecoverCameraForword() { Quaternion lodRotatiton = rigibodyCamera.transform.rotation; lodRotatiton.SetLookRotation(Vector3.down, Vector3.forward); Quaternion rot = Quaternion.Lerp(rigibodyCamera.transform.rotation, lodRotatiton, 0.08f); rigibodyCamera.MoveRotation(rot); } }