193 lines
7.1 KiB
C#
193 lines
7.1 KiB
C#
using UnityEngine;
|
||
using UnityEngine.EventSystems;
|
||
|
||
public class ControlMoving : MonoBehaviour
|
||
{
|
||
public float moveSpeed = 50f; // 右键平移速度
|
||
public float zoomSpeed = 10f; // 滚轮缩放速度
|
||
public DoubleClickToFocus doubleClickToFocusScript; // 引用焦点脚本,提供 core
|
||
public float rotationSensitivity = 0.2f; // 左键拖拽旋转灵敏度
|
||
|
||
private Camera cam;
|
||
private bool isRotating = false;
|
||
private Vector2 lastMousePos;
|
||
|
||
|
||
void Start()
|
||
{
|
||
cam = Camera.main;
|
||
Vector3 core = doubleClickToFocusScript.core;
|
||
if (doubleClickToFocusScript == null)
|
||
Debug.LogError("请在 Inspector 中把挂有 ClickToFocus 的物体拖给 inScript");
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
//if (EventSystem.current != null && EventSystem.current.IsPointerOverGameObject())
|
||
//{
|
||
// return; // 直接 return,你下面所有相机逻辑都不执行
|
||
//}
|
||
//if (SliderDragDetector.isSliderDragging)
|
||
// return;
|
||
//if (doubleClickToFocusScript == null) return;
|
||
Vector3 core = doubleClickToFocusScript.core;
|
||
|
||
// —— 右键平移 ——
|
||
if (Input.GetMouseButton(1))
|
||
{
|
||
moveSpeed = Vector3.Distance(core, transform.position) / 2f;//这里涉及到像素和实际空间米的关系转换
|
||
float mx = Input.GetAxis("Mouse X");
|
||
float my = Input.GetAxis("Mouse Y");
|
||
Vector3 desiredPosition = cam.transform.position + (-cam.transform.right * mx + -cam.transform.up * my) * moveSpeed * Time.deltaTime;
|
||
|
||
// 判断是否与障碍物发生碰撞
|
||
if (!WillCollideWithObstacle(desiredPosition))
|
||
{
|
||
cam.transform.position = desiredPosition;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
// —— 滚轮缩放 ——
|
||
float scroll = Input.GetAxis("Mouse ScrollWheel");
|
||
if (Mathf.Abs(scroll) > 0.001f)
|
||
{
|
||
Vector3 desiredPosition = cam.transform.position + cam.transform.forward * scroll * zoomSpeed;
|
||
|
||
// 判断是否与障碍物发生碰撞
|
||
if (!WillCollideWithObstacle(desiredPosition))
|
||
{
|
||
cam.transform.position = desiredPosition;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
// —— 左键开始/结束旋转 ——
|
||
if (Input.GetMouseButtonDown(0))
|
||
{
|
||
isRotating = true;
|
||
lastMousePos = Input.mousePosition;
|
||
}
|
||
if (Input.GetMouseButtonUp(0))
|
||
{
|
||
isRotating = false;
|
||
}
|
||
|
||
// —— 左键拖拽:RotateAround 实现 + 俯仰限制 ——
|
||
if (isRotating && Input.GetMouseButton(0))
|
||
{
|
||
Vector2 curr = Input.mousePosition;
|
||
Vector2 delta = (curr - lastMousePos) * rotationSensitivity;
|
||
lastMousePos = curr;
|
||
|
||
// 1. 水平绕世界 Y 轴旋转
|
||
//Vector3 desiredPosition = cam.transform.position;
|
||
//cam.transform.RotateAround(core, Vector3.up, delta.x);
|
||
|
||
Vector3 localPosHorizonal = cam.transform.position - core;
|
||
Quaternion rotationHorizonal = Quaternion.AngleAxis(delta.x, Vector3.up);
|
||
Vector3 newLocalPosHorizonal = rotationHorizonal * localPosHorizonal;//四元数*向量,旋转轴永远经过向量的起点
|
||
Vector3 newPosHorizonal = core + newLocalPosHorizonal;
|
||
|
||
// 检查旋转后是否发生碰撞
|
||
if (!WillCollideWithObstacle(newPosHorizonal))
|
||
{
|
||
// 如果没有碰撞,执行旋转
|
||
cam.transform.RotateAround(core, Vector3.up, delta.x);
|
||
}
|
||
else
|
||
{
|
||
// 如果碰撞了,就不动
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
// 2. 俯仰旋转
|
||
//Vector3 dir = (cam.transform.position - core).normalized;
|
||
//Vector3 flat = new Vector3(dir.x, 0f, dir.z).normalized;
|
||
//相机看的方向是正 z 方向。也是 forward 的方向。
|
||
float selfFlatX = cam.transform.forward.x;
|
||
float selfFlatZ = cam.transform.forward.z;
|
||
Vector3 selfFlat = new Vector3(selfFlatX, 0f, selfFlatZ).normalized;//把相机看的方向。在世界空间留下水平(X Z)。垂直量(Y)去掉。
|
||
//第一个参数和第二个参数绕着第三个参数(绕着 right 旋转),取值在-180~180
|
||
//cam.transform.right永远是垂直着你所看到的方向的,所以它垂直着你的这个selfFlat和cam.transform.forward
|
||
//这么做是为了得到你的相机,抬头或者是低头度数是多少
|
||
//既然是从平面开始,终点是上或下,原则上应该遵循顺时针为正,逆时针为负。
|
||
float selfPitch = Vector3.SignedAngle(selfFlat, cam.transform.forward, cam.transform.right);//俯视为正,仰视为负,cam.transform.right这玩意是旋转轴,
|
||
|
||
|
||
if (selfPitch <= 80f && selfPitch >= -80f)
|
||
{
|
||
|
||
float pitchDelta = delta.y * -1f;
|
||
|
||
Vector3 localPosVertical = cam.transform.position - core;
|
||
Quaternion rotationVertical = Quaternion.AngleAxis(pitchDelta, cam.transform.right);//构造出cam.transform.right绕着旋转pitchDelta的旋转值
|
||
Vector3 newPosVertical = core + rotationVertical * localPosVertical;//rotationVertical * localPosVertical这个量是旋转中心指向新位置的向量。
|
||
//某个物体的 rotation 等于一个四元数,这是一种用法,还有就是用四元素来相乘,qA * qB = 先旋转 qB,再旋转 qA
|
||
//我这里是用四元素乘一个向量,是把这个向量按照四元素的内容来旋转,可以想象把cam.transform.right平移到旋转中心,他肯定很永远和地面平行,并且和localPosVertical垂直。
|
||
//给localPosVertical这个向量按照rotationVertical旋转
|
||
// 判断是否与障碍物发生碰撞
|
||
|
||
//整体思路是先手动判断RotateAround的落脚点是否碰撞,然后再使用
|
||
if (!WillCollideWithObstacle(newPosVertical))
|
||
{
|
||
cam.transform.RotateAround(core, cam.transform.right, pitchDelta);
|
||
}
|
||
|
||
}
|
||
else if (selfPitch > 80f)
|
||
{
|
||
float pitchDelta = delta.y * -1f;
|
||
if (pitchDelta < 0f)
|
||
{
|
||
cam.transform.RotateAround(core, cam.transform.right, pitchDelta);
|
||
}
|
||
}
|
||
else if (selfPitch < -80f)
|
||
{
|
||
float pitchDelta = delta.y * -1f;
|
||
if (pitchDelta > 0f)
|
||
{
|
||
cam.transform.RotateAround(core, cam.transform.right, pitchDelta);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 碰撞检测方法
|
||
bool WillCollideWithObstacle(Vector3 targetPosition)
|
||
{
|
||
// 计算从当前位置到目标位置的方向和距离
|
||
Vector3 moveDir = targetPosition - cam.transform.position;
|
||
float moveDist = moveDir.magnitude;
|
||
|
||
// 使用 SphereCast 检查即将到达的位置是否会与障碍物发生碰撞
|
||
RaycastHit hit;
|
||
if (Physics.SphereCast(cam.transform.position, 0.08f, moveDir, out hit, moveDist, LayerMask.GetMask("Default"), QueryTriggerInteraction.Ignore) )
|
||
{
|
||
// 如果检测到碰撞,返回 true
|
||
Debug.Log("collider");
|
||
return true;
|
||
}
|
||
else if ( Mathf.Pow(targetPosition.x+50f, 2f)+ Mathf.Pow(targetPosition.z+30f , 2f)<60000f && targetPosition.y<80f)
|
||
{
|
||
// 如果在范围内,返回 false
|
||
return false;
|
||
}
|
||
else
|
||
Debug.Log("outRange");
|
||
return true;//这个true是为了有返回值,实际上走不到这一步
|
||
|
||
}
|
||
}
|