Files
3d-bianpo/Assets/Scripts/App/ControlMove.cs
2026-03-03 11:30:53 +08:00

238 lines
8.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
using UnityEngine.EventSystems;
public class ControlMove : MonoBehaviour
{
private float moveSpeed = 50f; // 右键平移速度
[Header("滚轮缩放速度系数")]
public float zoomSpeed = 10f; // 滚轮缩放速度
[Header("相机与水库中心的最大距离")]
public float maxDistance = 600f; // 最大缩放距离
[Header("相机的最大高度限制")]
public float maxHeight = 220f; // 最大高度限制
[Header("右键平移速度衰减系数")]
public float rightClickPanSpeed = 100f; // 右键平移速度除数
private Vector3 inScript; // 引用焦点脚本,提供 core
[Header("左键拖拽旋转灵敏度系数")]
public float rotationSensitivity = 0.2f; // 左键拖拽旋转灵敏度
private Camera cam; // 主相机引用
private bool isRotating = false; // 是否正在旋转标志
private Vector2 lastMousePos; // 上次鼠标位置(用于旋转计算)
[Header("初始距离中心")]
public Vector3 reservoirCenter; // 水库中心坐标
[Header("初始旋转中心")]
public Vector3 startinScript; // 初始焦点位置
private Rigidbody rb; // 刚体组件(如需要物理模拟)
private bool isCameraCtrl = true; // 相机是否可控制
//相机操作有效性判断
private bool isClickUI = false;
void Start()
{
rb = GetComponent<Rigidbody>();
cam = Camera.main;
if (inScript == Vector3.zero)
{
GetInScriptCore();
}
}
void Update()
{
if (isCameraCtrl)
{
//操作有效性判断
if (EventSystem.current != null)
{
if (Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1) || Input.GetMouseButtonDown(2))
{
isClickUI = EventSystem.current.IsPointerOverGameObject();
}
if (Input.GetMouseButtonUp(0) || Input.GetMouseButtonUp(1) || Input.GetMouseButtonUp(2))
{
isClickUI = false;
}
}
if (!isClickUI)
{
Vector3 core = inScript;
// —— 右键平移 ——
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 = transform.position + (-transform.right * mx + -transform.up * my) * moveSpeed * Time.deltaTime;
Vector3 desiredPosition = transform.position + (-transform.right * mx + -transform.up * my) * moveSpeed / rightClickPanSpeed;
// 判断是否与障碍物发生碰撞
if (!WillCollideWithObstacle(desiredPosition))
{
// transform.position = Vector3.Lerp(transform.position, desiredPosition, moveSpeed * Time.deltaTime);
transform.position = desiredPosition;
}
}
// —— 滚轮缩放 ——
float scroll = Input.GetAxis("Mouse ScrollWheel");
if (Mathf.Abs(scroll) > 0.001f)
{
Vector3 desiredPosition = transform.position + transform.forward * scroll * zoomSpeed;
// 判断是否与障碍物发生碰撞
if (!WillCollideWithObstacle(desiredPosition))
{
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 = transform.position;
//transform.RotateAround(core, Vector3.up, delta.x);
Vector3 localPosHorizonal = transform.position - core;
Quaternion rotationHorizonal = Quaternion.AngleAxis(delta.x, Vector3.up);
Vector3 newLocalPosHorizonal = rotationHorizonal * localPosHorizonal;
Vector3 newPosHorizonal = core + newLocalPosHorizonal;
// 检查旋转后是否发生碰撞
if (!WillCollideWithObstacle(newPosHorizonal))
{
// 如果没有碰撞,执行旋转
transform.RotateAround(core, Vector3.up, delta.x);
}
else
{
// 如果碰撞了,撤销旋转,恢复到原来的位置
}
// 2. 俯仰旋转
Vector3 dir = (transform.position - core).normalized;
Vector3 flat = new Vector3(dir.x, 0f, dir.z).normalized;
float selfFlatX = transform.forward.x;
float selfFlatZ = transform.forward.z;
Vector3 selfFlat = new Vector3(selfFlatX, 0f, selfFlatZ).normalized;
float selfPitch = Vector3.SignedAngle(selfFlat, transform.forward, transform.right);
if (selfPitch <= 80f && selfPitch >= 0f)
{
float pitchDelta = delta.y * -1f;
Vector3 localPosVertical = transform.position - core;
Quaternion rotationVertical = Quaternion.AngleAxis(pitchDelta, transform.right);
Vector3 newPosVertical = core + rotationVertical * localPosVertical;
if (!WillCollideWithObstacle(newPosVertical))
{
transform.RotateAround(core, transform.right, pitchDelta);
}
}
else if (selfPitch > 80f)
{
float pitchDelta = delta.y * -1f;
if (pitchDelta < 0f)
{
transform.RotateAround(core, transform.right, pitchDelta);
}
}
else if (selfPitch < 0f)
{
float pitchDelta = delta.y * -1f;
if (pitchDelta > 0f)
{
transform.RotateAround(core, transform.right, pitchDelta);
}
}
}
}
}
}
// 碰撞检测方法
bool WillCollideWithObstacle(Vector3 targetPosition)
{
// 计算从当前位置到目标位置的方向和距离
Vector3 moveDir = targetPosition - transform.position;
float moveDist = moveDir.magnitude;
// 使用 SphereCast 检查即将到达的位置是否会与障碍物发生碰撞
RaycastHit hit;
if (Physics.SphereCast(transform.position, 0.5f, moveDir.normalized, out hit, moveDist, LayerMask.GetMask("Default"), QueryTriggerInteraction.Collide))
{
// 如果检测到碰撞,返回 true
// Debug.Log("collider");
return true;
}
else if (Vector3.Distance(targetPosition, reservoirCenter) < maxDistance && targetPosition.y < maxHeight)
{
// 如果在范围内,返回 false
return false;
}
else
// Debug.Log("outRange");
return true;
}
public void GetInScriptCore()
{
inScript = startinScript;
}
public void GetInScriptCore(Vector3 position)
{
inScript = position;
}
public void StartCameraControl()
{
isCameraCtrl = true;
isClickUI = false;
}
//停止相机控制
public void StopCameraControl()
{
isCameraCtrl = false;
}
}