123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.Serialization;
- namespace CustomTool
- {
- public class CameraController : MonoBehaviour
- {
- #region 私有变量
- /// <summary>
- /// 是否可穿碰撞器
- /// </summary>
- [Header("是否开启穿透检测")]
- [SerializeField]
- private bool m_IsCouldCrossCollider;
- /// <summary>
- /// 是否限定相机的移动区域
- /// </summary>
- [Header("是否开启区域限定")]
- [SerializeField]
- private bool m_IsLimitArea = false;
- /// <summary>
- /// 是否绘制区域效果
- /// </summary>
- [Header("是否绘制限制区域效果")]
- [SerializeField]
- private bool m_IsDragAreaEffect = false;
- /// <summary>
- /// 全场景区域限定最小点
- /// </summary>
- [Header("大范围限制区域")]
- [SerializeField]
- private Transform m_SceneMinPoint;
- /// <summary>
- /// 全场景区域限定最大点
- /// </summary>
- [SerializeField]
- private Transform m_SceneMaxPoint;
- /// <summary>
- /// 相机移动速度
- /// </summary>
- [Header("相机相关参数")]
- [SerializeField]
- private float m_MoveSpeed = 10f;
- /// <summary>
- /// X轴视角旋转速度
- /// </summary>
- [SerializeField]
- private float m_XSpeed = 250.0f;
- /// <summary>
- /// Y轴视角旋转速度
- /// </summary>
- [SerializeField]
- private float m_YSpeed = 120.0f;
- /// <summary>
- /// 鼠标中间滚轮的拉近拉远速度
- /// </summary>
- [SerializeField]
- private float m_MouseSpeed = 60f;
- /// <summary>
- /// 视角旋转向下最小限制
- /// </summary>
- [SerializeField]
- private float m_YMinLimit = -20;
- /// <summary>
- /// 视角旋转向上最大限制
- /// </summary>
- [SerializeField]
- private float m_YMaxLimit = 80;
- /// <summary>
- /// 鼠标中键移动速度限制
- /// </summary>
- [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
- {
- /// <summary>
- /// 房屋区域的最小点
- /// </summary>
- public Transform minPoint;
- /// <summary>
- /// 房屋区域的最大点
- /// </summary>
- public Transform maxPoint;
- }
- /// <summary>
- /// 房屋区域的数组
- /// </summary>
- [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();
- }
- /// <summary>
- /// 重置位置信息
- /// </summary>
- public void ResetInfo()
- {
- var angles = transform.eulerAngles;
- m_AngleX = angles.y;
- m_AngleY = angles.x;
- }
- /// <summary>
- /// 相机移动
- /// </summary>
- 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;
- }
- /// <summary>
- /// 鼠标中键控制相机移动
- /// </summary>
- 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;
- }
- }
- /// <summary>
- /// 鼠标右键控制视角旋转
- /// </summary>
- 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;
- }
- }
- }
- /// <summary>
- /// 滑轮控制视角移动
- /// </summary>
- 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;
- }
- }
- /// <summary>
- /// 跳转到对应内部区域
- /// </summary>
- /// <param name="_targetPosition">目标位置</param>
- /// <param name="_minPoint">房间最小点</param>
- /// <param name="_maxPoint">房间最大点</param>
- 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;
- }
- /// <summary>
- /// 跳转到对应内部区域
- /// </summary>
- /// <param name="_targetPosition">目标位置</param>
- /// <param name="_minPoint">房间最小点</param>
- /// <param name="_maxPoint">房间最大点</param>
- 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;
- }
- /// <summary>
- /// 重置限定区域
- /// </summary>
- /// <param name="_targetPosition">跳转目标点</param>
- /// <param name="_isLargeScene">是否处于大场景限定范围,默认是true</param>
- /// <param name="_minPoint">如果_isLargeScene为默认值时,不需要填值</param>
- /// <param name="_maxPoint">如果_isLargeScene为默认值时,不需要填值</param>
- 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);
- }
- }
- /// <summary>
- /// 设置限定区域的状态
- /// </summary>
- /// <param name="_isActive"></param>
- public void SetStatusOfRestrictedArea(bool _isActive)
- {
- m_IsCouldCrossCollider = _isActive;
- }
- /// <summary>
- /// 检测相机是否在物体内
- /// </summary>
- /// <param name="_position"></param>
- /// <param name="_limit"></param>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// 判断相机的位置,并做出修改
- /// </summary>
- /// <param name="_position"></param>
- /// <param name="_limit"></param>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// 设置相机的移动范围
- /// </summary>
- /// <param name="_minPoint"></param>
- /// <param name="_maxPoint"></param>
- 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;
- }
- /// <summary>
- /// 控制摄像机的旋转角度大小
- /// </summary>
- /// <param name="_angle"></param>
- /// <param name="_min"></param>
- /// <param name="_max"></param>
- /// <returns></returns>
- 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);
- }
- }
- }
- }
- /// <summary>
- /// 设置相机的初始数据
- /// </summary>
- 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;
- }
-
- /// <summary>
- /// 获取相机配置数据
- /// </summary>
- /// <returns></returns>
- private CameraConfig GetCameraConfigData()
- {
- // 拼接文件基本路径
- string filePath = PathHelper.CombineFilePath(PathHelper.m_ReadOnlyPath,
- "Json",
- "CameraConfig.json");
- string fileData = FileHelper.GetAllDataInfo(filePath);
-
- CameraConfig config = JsonUtility.FromJson<CameraConfig>(fileData);
- return config == null ? null : config;
- }
- }
- }
|