鼠标滚轮:缩放
鼠标右键:旋转
鼠标中键:平移
鼠标左键:选中实体(下面的代码中未实现)
注:
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);
}
}