using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Serialization; namespace CustomTool { public class CameraController : MonoBehaviour { #region 私有变量 /// /// 是否可穿碰撞器 /// [Header("是否开启穿透检测")] [SerializeField] private bool m_IsCouldCrossCollider; /// /// 是否限定相机的移动区域 /// [Header("是否开启区域限定")] [SerializeField] private bool m_IsLimitArea = false; /// /// 是否绘制区域效果 /// [Header("是否绘制限制区域效果")] [SerializeField] private bool m_IsDragAreaEffect = false; /// /// 全场景区域限定最小点 /// [Header("大范围限制区域")] [SerializeField] private Transform m_SceneMinPoint; /// /// 全场景区域限定最大点 /// [SerializeField] private Transform m_SceneMaxPoint; /// /// 相机移动速度 /// [Header("相机相关参数")] [SerializeField] private float m_MoveSpeed = 10f; /// /// X轴视角旋转速度 /// [SerializeField] private float m_XSpeed = 250.0f; /// /// Y轴视角旋转速度 /// [SerializeField] private float m_YSpeed = 120.0f; /// /// 鼠标中间滚轮的拉近拉远速度 /// [SerializeField] private float m_MouseSpeed = 60f; /// /// 视角旋转向下最小限制 /// [SerializeField] private float m_YMinLimit = -20; /// /// 视角旋转向上最大限制 /// [SerializeField] private float m_YMaxLimit = 80; /// /// 鼠标中键移动速度限制 /// [SerializeField] public float m_SpeedLimit = 0.2f; private float xMin, xMax, yMin, yMax, zMin, zMax; // 相机的移动范围 private float m_MoveX; private float m_MoveY; private float m_MoveZ = 0; private float m_AngleX = 0.0f; private float m_AngleY = 0.0f; #endregion [Serializable] public struct LimitArea { /// /// 房屋区域的最小点 /// public Transform minPoint; /// /// 房屋区域的最大点 /// public Transform maxPoint; } /// /// 房屋区域的数组 /// [FormerlySerializedAs("houseAreas")] [Header("不可穿透区域")] [SerializeField] private LimitArea[] m_LimitAreas = null; private void Awake() { ResetInfo(); SetCameraInitData(); SetCameraPosLimite(m_SceneMinPoint.position, m_SceneMaxPoint.position); } void Update() { HandleKeyboardInput(); HandleMouseInput(); RotateView(); ViewScale(); } /// /// 重置位置信息 /// public void ResetInfo() { var angles = transform.eulerAngles; m_AngleX = angles.y; m_AngleY = angles.x; } /// /// 相机移动 /// private void HandleKeyboardInput() { // 键盘输入 m_MoveX = Input.GetAxis("Horizontal") * m_MoveSpeed * Time.deltaTime; m_MoveY = Input.GetAxis("Vertical") * m_MoveSpeed * Time.deltaTime; float moveZ = 0; // 上移和下移键 if (Input.GetKey(KeyCode.E)) { moveZ = m_MoveSpeed * Time.deltaTime; } else if (Input.GetKey(KeyCode.Q)) { moveZ = -m_MoveSpeed * Time.deltaTime; } Vector3 move = new Vector3(m_MoveX, moveZ, m_MoveY); Vector3 movePos = transform.position + transform.TransformDirection(move); if (m_IsLimitArea) { // 限制相机在指定区域内移动 movePos.x = Mathf.Clamp(movePos.x, xMin, xMax); movePos.y = Mathf.Clamp(movePos.y, yMin, yMax); movePos.z = Mathf.Clamp(movePos.z, zMin, zMax); } if (m_IsCouldCrossCollider) { // 检查并调整相机位置 foreach (LimitArea item in m_LimitAreas) { if (IsInsideHouse(movePos, item)) { movePos = AdjustPositionOutsideHouse(movePos, item); } } } transform.position = movePos; } /// /// 鼠标中键控制相机移动 /// private void HandleMouseInput() { // 鼠标中键控制移动 if (Input.GetMouseButton(2)) { float mouseX = Input.GetAxis("Mouse X") * m_MoveSpeed * Time.deltaTime; float mouseY = Input.GetAxis("Mouse Y") * m_MoveSpeed * Time.deltaTime; Vector3 move = new Vector3(mouseX, 0, mouseY); Vector3 movePos = transform.position + transform.TransformDirection(move); if (m_IsLimitArea) { // 限制相机在指定区域内移动 movePos.x = Mathf.Clamp(movePos.x, xMin, xMax); movePos.y = Mathf.Clamp(movePos.y, yMin, yMax); movePos.z = Mathf.Clamp(movePos.z, zMin, zMax); } if (m_IsCouldCrossCollider) { // 检查并调整相机位置 foreach (LimitArea item in m_LimitAreas) { if (IsInsideHouse(movePos, item)) { movePos = AdjustPositionOutsideHouse(movePos, item); } } } transform.position = movePos; } } /// /// 鼠标右键控制视角旋转 /// private void RotateView() { if (Input.GetMouseButton(1)) { if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0) { m_AngleX += Input.GetAxis("Mouse X") * m_XSpeed * 0.02f; m_AngleY -= Input.GetAxis("Mouse Y") * m_YSpeed * 0.02f; m_AngleY = ClampAngle(m_AngleY, m_YMinLimit, m_YMaxLimit); var rotation = Quaternion.Euler(m_AngleY, m_AngleX, 0); transform.rotation = rotation; } } } /// /// 滑轮控制视角移动 /// private void ViewScale() { if (Input.GetAxis("Mouse ScrollWheel") != 0) { // 鼠标滚轮控制相机距离 Vector3 scrollMove = transform.forward * (Input.GetAxis("Mouse ScrollWheel") * m_MouseSpeed * Time.deltaTime); Vector3 movePos = transform.position + scrollMove; if (m_IsLimitArea) { movePos.x = Mathf.Clamp(movePos.x, xMin, xMax); movePos.y = Mathf.Clamp(movePos.y, yMin, yMax); movePos.z = Mathf.Clamp(movePos.z, zMin, zMax); } if (m_IsCouldCrossCollider) { // 检查并调整相机位置 foreach (LimitArea item in m_LimitAreas) { if (IsInsideHouse(movePos, item)) { movePos = AdjustPositionOutsideHouse(movePos, item); } } } transform.position = movePos; } } /// /// 跳转到对应内部区域 /// /// 目标位置 /// 房间最小点 /// 房间最大点 public void JumpCorrespondingPosition(Transform _targetPosition, Transform _minPoint, Transform _maxPoint) { // 设置相机移动范围为房间范围 SetCameraPosLimite(_minPoint.position, _maxPoint.position); // 确保目标点在指定房屋区域内 Vector3 clampedTargetPoint = _targetPosition.position; clampedTargetPoint.x = Mathf.Clamp(clampedTargetPoint.x, _minPoint.position.x, _maxPoint.position.x); clampedTargetPoint.y = Mathf.Clamp(clampedTargetPoint.y, _minPoint.position.y, _maxPoint.position.y); clampedTargetPoint.z = Mathf.Clamp(clampedTargetPoint.z, _minPoint.position.z, _maxPoint.position.z); // 更新相机位置到目标点 transform.position = clampedTargetPoint; } /// /// 跳转到对应内部区域 /// /// 目标位置 /// 房间最小点 /// 房间最大点 public void JumpCorrespondingPosition(Vector3 _targetPosition, Transform _minPoint, Transform _maxPoint) { // 设置相机移动范围为房间范围 SetCameraPosLimite(_minPoint.position, _maxPoint.position); // 确保目标点在指定房屋区域内 Vector3 clampedTargetPoint = _targetPosition; clampedTargetPoint.x = Mathf.Clamp(clampedTargetPoint.x, _minPoint.position.x, _maxPoint.position.x); clampedTargetPoint.y = Mathf.Clamp(clampedTargetPoint.y, _minPoint.position.y, _maxPoint.position.y); clampedTargetPoint.z = Mathf.Clamp(clampedTargetPoint.z, _minPoint.position.z, _maxPoint.position.z); // 更新相机位置到目标点 transform.position = clampedTargetPoint; } /// /// 重置限定区域 /// /// 跳转目标点 /// 是否处于大场景限定范围,默认是true /// 如果_isLargeScene为默认值时,不需要填值 /// 如果_isLargeScene为默认值时,不需要填值 public void ResetLimit(Transform _targetPosition, bool _isLargeScene = true, Transform _minPoint = null, Transform _maxPoint = null) { if (_isLargeScene) { JumpCorrespondingPosition(_targetPosition, m_SceneMinPoint, m_SceneMaxPoint); } else { JumpCorrespondingPosition(_targetPosition, _minPoint, _maxPoint); } } /// /// 设置限定区域的状态 /// /// public void SetStatusOfRestrictedArea(bool _isActive) { m_IsCouldCrossCollider = _isActive; } /// /// 检测相机是否在物体内 /// /// /// /// private bool IsInsideHouse(Vector3 _position, LimitArea _limit) { Vector3 minPoint = _limit.minPoint.position; Vector3 maxPoint = _limit.maxPoint.position; return _position.x > minPoint.x && _position.x < maxPoint.x && _position.y > minPoint.y && _position.y < maxPoint.y && _position.z > minPoint.z && _position.z < maxPoint.z; } /// /// 判断相机的位置,并做出修改 /// /// /// /// private Vector3 AdjustPositionOutsideHouse(Vector3 _position, LimitArea _limit) { Vector3 minPoint = _limit.minPoint.position; Vector3 maxPoint = _limit.maxPoint.position; // 计算相机当前位置与房屋边界的距离 float xDistToMin = Mathf.Abs(_position.x - minPoint.x); float xDistToMax = Mathf.Abs(_position.x - maxPoint.x); float zDistToMin = Mathf.Abs(_position.z - minPoint.z); float zDistToMax = Mathf.Abs(_position.z - maxPoint.z); // 找到距离最近的边界 float minDist = Mathf.Min(xDistToMin, xDistToMax, zDistToMin, zDistToMax); // 根据最近的边界调整相机位置 if (minDist == xDistToMin) { // 相机靠近最小X边界 _position.x = minPoint.x - 0.1f; } else if (minDist == xDistToMax) { // 相机靠近最大X边界 _position.x = maxPoint.x + 0.1f; } else if (minDist == zDistToMin) { // 相机靠近最小Z边界 _position.z = minPoint.z - 0.1f; } else if (minDist == zDistToMax) { // 相机靠近最大Z边界 _position.z = maxPoint.z + 0.1f; } return _position; } /// /// 设置相机的移动范围 /// /// /// private void SetCameraPosLimite(Vector3 _minPoint, Vector3 _maxPoint) { xMin = _minPoint.x; xMax = _maxPoint.x; yMin = _minPoint.y; yMax = _maxPoint.y; zMin = _minPoint.z; zMax = _maxPoint.z; } /// /// 控制摄像机的旋转角度大小 /// /// /// /// /// private float ClampAngle(float _angle, float _min, float _max) { if (_angle < -360) { _angle += 360; } if (_angle > 360) { _angle -= 360; } return Mathf.Clamp(_angle, _min, _max); } private void OnDrawGizmos() { if (m_IsDragAreaEffect) { Gizmos.color = Color.green; Gizmos.DrawWireCube(new Vector3((xMin + xMax) / 2, (yMin + yMax) / 2, (zMin + zMax) / 2), new Vector3(xMax - xMin, yMax - yMin, zMax - zMin)); Gizmos.color = Color.red; if (m_LimitAreas != null) { foreach (LimitArea house in m_LimitAreas) { Vector3 minPoint = house.minPoint.position; Vector3 maxPoint = house.maxPoint.position; Vector3 center = (minPoint + maxPoint) / 2; Vector3 size = maxPoint - minPoint; Gizmos.DrawWireCube(center, size); } } } } /// /// 设置相机的初始数据 /// private void SetCameraInitData() { CameraConfig cameraConfig = GetCameraConfigData(); if (cameraConfig == null) { return; } m_MoveSpeed = cameraConfig.MoveSpeed; m_XSpeed = cameraConfig.XRotateSpeed; m_YSpeed = cameraConfig.YRotateSpeed; m_MouseSpeed = cameraConfig.MiddleMouseZoomSpeed; m_YMinLimit = cameraConfig.YMinLimit; m_YMaxLimit = cameraConfig.YMaxLimit; m_SpeedLimit = cameraConfig.MiddleMouseMoveSpeed; } /// /// 获取相机配置数据 /// /// private CameraConfig GetCameraConfigData() { // 拼接文件基本路径 string filePath = PathHelper.CombineFilePath(PathHelper.m_ReadOnlyPath, "Json", "CameraConfig.json"); string fileData = FileHelper.GetAllDataInfo(filePath); CameraConfig config = JsonUtility.FromJson(fileData); return config == null ? null : config; } } }