CameraController.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using UnityEngine.Serialization;
  6. namespace CustomTool
  7. {
  8. public class CameraController : MonoBehaviour
  9. {
  10. #region 私有变量
  11. /// <summary>
  12. /// 是否可穿碰撞器
  13. /// </summary>
  14. [Header("是否开启穿透检测")]
  15. [SerializeField]
  16. private bool m_IsCouldCrossCollider;
  17. /// <summary>
  18. /// 是否限定相机的移动区域
  19. /// </summary>
  20. [Header("是否开启区域限定")]
  21. [SerializeField]
  22. private bool m_IsLimitArea = false;
  23. /// <summary>
  24. /// 是否绘制区域效果
  25. /// </summary>
  26. [Header("是否绘制限制区域效果")]
  27. [SerializeField]
  28. private bool m_IsDragAreaEffect = false;
  29. /// <summary>
  30. /// 全场景区域限定最小点
  31. /// </summary>
  32. [Header("大范围限制区域")]
  33. [SerializeField]
  34. private Transform m_SceneMinPoint;
  35. /// <summary>
  36. /// 全场景区域限定最大点
  37. /// </summary>
  38. [SerializeField]
  39. private Transform m_SceneMaxPoint;
  40. /// <summary>
  41. /// 相机移动速度
  42. /// </summary>
  43. [Header("相机相关参数")]
  44. [SerializeField]
  45. private float m_MoveSpeed = 10f;
  46. /// <summary>
  47. /// X轴视角旋转速度
  48. /// </summary>
  49. [SerializeField]
  50. private float m_XSpeed = 250.0f;
  51. /// <summary>
  52. /// Y轴视角旋转速度
  53. /// </summary>
  54. [SerializeField]
  55. private float m_YSpeed = 120.0f;
  56. /// <summary>
  57. /// 鼠标中间滚轮的拉近拉远速度
  58. /// </summary>
  59. [SerializeField]
  60. private float m_MouseSpeed = 60f;
  61. /// <summary>
  62. /// 视角旋转向下最小限制
  63. /// </summary>
  64. [SerializeField]
  65. private float m_YMinLimit = -20;
  66. /// <summary>
  67. /// 视角旋转向上最大限制
  68. /// </summary>
  69. [SerializeField]
  70. private float m_YMaxLimit = 80;
  71. /// <summary>
  72. /// 鼠标中键移动速度限制
  73. /// </summary>
  74. [SerializeField]
  75. public float m_SpeedLimit = 0.2f;
  76. private float xMin, xMax, yMin, yMax, zMin, zMax; // 相机的移动范围
  77. private float m_MoveX;
  78. private float m_MoveY;
  79. private float m_MoveZ = 0;
  80. private float m_AngleX = 0.0f;
  81. private float m_AngleY = 0.0f;
  82. #endregion
  83. [Serializable]
  84. public struct LimitArea
  85. {
  86. /// <summary>
  87. /// 房屋区域的最小点
  88. /// </summary>
  89. public Transform minPoint;
  90. /// <summary>
  91. /// 房屋区域的最大点
  92. /// </summary>
  93. public Transform maxPoint;
  94. }
  95. /// <summary>
  96. /// 房屋区域的数组
  97. /// </summary>
  98. [FormerlySerializedAs("houseAreas")]
  99. [Header("不可穿透区域")]
  100. [SerializeField]
  101. private LimitArea[] m_LimitAreas = null;
  102. private void Awake()
  103. {
  104. ResetInfo();
  105. SetCameraInitData();
  106. SetCameraPosLimite(m_SceneMinPoint.position, m_SceneMaxPoint.position);
  107. }
  108. void Update()
  109. {
  110. HandleKeyboardInput();
  111. HandleMouseInput();
  112. RotateView();
  113. ViewScale();
  114. }
  115. /// <summary>
  116. /// 重置位置信息
  117. /// </summary>
  118. public void ResetInfo()
  119. {
  120. var angles = transform.eulerAngles;
  121. m_AngleX = angles.y;
  122. m_AngleY = angles.x;
  123. }
  124. /// <summary>
  125. /// 相机移动
  126. /// </summary>
  127. private void HandleKeyboardInput()
  128. {
  129. // 键盘输入
  130. m_MoveX = Input.GetAxis("Horizontal") * m_MoveSpeed * Time.deltaTime;
  131. m_MoveY = Input.GetAxis("Vertical") * m_MoveSpeed * Time.deltaTime;
  132. float moveZ = 0;
  133. // 上移和下移键
  134. if (Input.GetKey(KeyCode.E))
  135. {
  136. moveZ = m_MoveSpeed * Time.deltaTime;
  137. }
  138. else if (Input.GetKey(KeyCode.Q))
  139. {
  140. moveZ = -m_MoveSpeed * Time.deltaTime;
  141. }
  142. Vector3 move = new Vector3(m_MoveX, moveZ, m_MoveY);
  143. Vector3 movePos = transform.position + transform.TransformDirection(move);
  144. if (m_IsLimitArea)
  145. {
  146. // 限制相机在指定区域内移动
  147. movePos.x = Mathf.Clamp(movePos.x, xMin, xMax);
  148. movePos.y = Mathf.Clamp(movePos.y, yMin, yMax);
  149. movePos.z = Mathf.Clamp(movePos.z, zMin, zMax);
  150. }
  151. if (m_IsCouldCrossCollider)
  152. {
  153. // 检查并调整相机位置
  154. foreach (LimitArea item in m_LimitAreas)
  155. {
  156. if (IsInsideHouse(movePos, item))
  157. {
  158. movePos = AdjustPositionOutsideHouse(movePos, item);
  159. }
  160. }
  161. }
  162. transform.position = movePos;
  163. }
  164. /// <summary>
  165. /// 鼠标中键控制相机移动
  166. /// </summary>
  167. private void HandleMouseInput()
  168. {
  169. // 鼠标中键控制移动
  170. if (Input.GetMouseButton(2))
  171. {
  172. float mouseX = Input.GetAxis("Mouse X") * m_MoveSpeed * Time.deltaTime;
  173. float mouseY = Input.GetAxis("Mouse Y") * m_MoveSpeed * Time.deltaTime;
  174. Vector3 move = new Vector3(mouseX, 0, mouseY);
  175. Vector3 movePos = transform.position + transform.TransformDirection(move);
  176. if (m_IsLimitArea)
  177. {
  178. // 限制相机在指定区域内移动
  179. movePos.x = Mathf.Clamp(movePos.x, xMin, xMax);
  180. movePos.y = Mathf.Clamp(movePos.y, yMin, yMax);
  181. movePos.z = Mathf.Clamp(movePos.z, zMin, zMax);
  182. }
  183. if (m_IsCouldCrossCollider)
  184. {
  185. // 检查并调整相机位置
  186. foreach (LimitArea item in m_LimitAreas)
  187. {
  188. if (IsInsideHouse(movePos, item))
  189. {
  190. movePos = AdjustPositionOutsideHouse(movePos, item);
  191. }
  192. }
  193. }
  194. transform.position = movePos;
  195. }
  196. }
  197. /// <summary>
  198. /// 鼠标右键控制视角旋转
  199. /// </summary>
  200. private void RotateView()
  201. {
  202. if (Input.GetMouseButton(1))
  203. {
  204. if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0)
  205. {
  206. m_AngleX += Input.GetAxis("Mouse X") * m_XSpeed * 0.02f;
  207. m_AngleY -= Input.GetAxis("Mouse Y") * m_YSpeed * 0.02f;
  208. m_AngleY = ClampAngle(m_AngleY, m_YMinLimit, m_YMaxLimit);
  209. var rotation = Quaternion.Euler(m_AngleY, m_AngleX, 0);
  210. transform.rotation = rotation;
  211. }
  212. }
  213. }
  214. /// <summary>
  215. /// 滑轮控制视角移动
  216. /// </summary>
  217. private void ViewScale()
  218. {
  219. if (Input.GetAxis("Mouse ScrollWheel") != 0)
  220. {
  221. // 鼠标滚轮控制相机距离
  222. Vector3 scrollMove = transform.forward * (Input.GetAxis("Mouse ScrollWheel") * m_MouseSpeed * Time.deltaTime);
  223. Vector3 movePos = transform.position + scrollMove;
  224. if (m_IsLimitArea)
  225. {
  226. movePos.x = Mathf.Clamp(movePos.x, xMin, xMax);
  227. movePos.y = Mathf.Clamp(movePos.y, yMin, yMax);
  228. movePos.z = Mathf.Clamp(movePos.z, zMin, zMax);
  229. }
  230. if (m_IsCouldCrossCollider)
  231. {
  232. // 检查并调整相机位置
  233. foreach (LimitArea item in m_LimitAreas)
  234. {
  235. if (IsInsideHouse(movePos, item))
  236. {
  237. movePos = AdjustPositionOutsideHouse(movePos, item);
  238. }
  239. }
  240. }
  241. transform.position = movePos;
  242. }
  243. }
  244. /// <summary>
  245. /// 跳转到对应内部区域
  246. /// </summary>
  247. /// <param name="_targetPosition">目标位置</param>
  248. /// <param name="_minPoint">房间最小点</param>
  249. /// <param name="_maxPoint">房间最大点</param>
  250. public void JumpCorrespondingPosition(Transform _targetPosition, Transform _minPoint, Transform _maxPoint)
  251. {
  252. // 设置相机移动范围为房间范围
  253. SetCameraPosLimite(_minPoint.position, _maxPoint.position);
  254. // 确保目标点在指定房屋区域内
  255. Vector3 clampedTargetPoint = _targetPosition.position;
  256. clampedTargetPoint.x = Mathf.Clamp(clampedTargetPoint.x, _minPoint.position.x, _maxPoint.position.x);
  257. clampedTargetPoint.y = Mathf.Clamp(clampedTargetPoint.y, _minPoint.position.y, _maxPoint.position.y);
  258. clampedTargetPoint.z = Mathf.Clamp(clampedTargetPoint.z, _minPoint.position.z, _maxPoint.position.z);
  259. // 更新相机位置到目标点
  260. transform.position = clampedTargetPoint;
  261. }
  262. /// <summary>
  263. /// 跳转到对应内部区域
  264. /// </summary>
  265. /// <param name="_targetPosition">目标位置</param>
  266. /// <param name="_minPoint">房间最小点</param>
  267. /// <param name="_maxPoint">房间最大点</param>
  268. public void JumpCorrespondingPosition(Vector3 _targetPosition, Transform _minPoint, Transform _maxPoint)
  269. {
  270. // 设置相机移动范围为房间范围
  271. SetCameraPosLimite(_minPoint.position, _maxPoint.position);
  272. // 确保目标点在指定房屋区域内
  273. Vector3 clampedTargetPoint = _targetPosition;
  274. clampedTargetPoint.x = Mathf.Clamp(clampedTargetPoint.x, _minPoint.position.x, _maxPoint.position.x);
  275. clampedTargetPoint.y = Mathf.Clamp(clampedTargetPoint.y, _minPoint.position.y, _maxPoint.position.y);
  276. clampedTargetPoint.z = Mathf.Clamp(clampedTargetPoint.z, _minPoint.position.z, _maxPoint.position.z);
  277. // 更新相机位置到目标点
  278. transform.position = clampedTargetPoint;
  279. }
  280. /// <summary>
  281. /// 重置限定区域
  282. /// </summary>
  283. /// <param name="_targetPosition">跳转目标点</param>
  284. /// <param name="_isLargeScene">是否处于大场景限定范围,默认是true</param>
  285. /// <param name="_minPoint">如果_isLargeScene为默认值时,不需要填值</param>
  286. /// <param name="_maxPoint">如果_isLargeScene为默认值时,不需要填值</param>
  287. public void ResetLimit(Transform _targetPosition, bool _isLargeScene = true, Transform _minPoint = null, Transform _maxPoint = null)
  288. {
  289. if (_isLargeScene)
  290. {
  291. JumpCorrespondingPosition(_targetPosition, m_SceneMinPoint, m_SceneMaxPoint);
  292. }
  293. else
  294. {
  295. JumpCorrespondingPosition(_targetPosition, _minPoint, _maxPoint);
  296. }
  297. }
  298. /// <summary>
  299. /// 设置限定区域的状态
  300. /// </summary>
  301. /// <param name="_isActive"></param>
  302. public void SetStatusOfRestrictedArea(bool _isActive)
  303. {
  304. m_IsCouldCrossCollider = _isActive;
  305. }
  306. /// <summary>
  307. /// 检测相机是否在物体内
  308. /// </summary>
  309. /// <param name="_position"></param>
  310. /// <param name="_limit"></param>
  311. /// <returns></returns>
  312. private bool IsInsideHouse(Vector3 _position, LimitArea _limit)
  313. {
  314. Vector3 minPoint = _limit.minPoint.position;
  315. Vector3 maxPoint = _limit.maxPoint.position;
  316. return _position.x > minPoint.x && _position.x < maxPoint.x &&
  317. _position.y > minPoint.y && _position.y < maxPoint.y &&
  318. _position.z > minPoint.z && _position.z < maxPoint.z;
  319. }
  320. /// <summary>
  321. /// 判断相机的位置,并做出修改
  322. /// </summary>
  323. /// <param name="_position"></param>
  324. /// <param name="_limit"></param>
  325. /// <returns></returns>
  326. private Vector3 AdjustPositionOutsideHouse(Vector3 _position, LimitArea _limit)
  327. {
  328. Vector3 minPoint = _limit.minPoint.position;
  329. Vector3 maxPoint = _limit.maxPoint.position;
  330. // 计算相机当前位置与房屋边界的距离
  331. float xDistToMin = Mathf.Abs(_position.x - minPoint.x);
  332. float xDistToMax = Mathf.Abs(_position.x - maxPoint.x);
  333. float zDistToMin = Mathf.Abs(_position.z - minPoint.z);
  334. float zDistToMax = Mathf.Abs(_position.z - maxPoint.z);
  335. // 找到距离最近的边界
  336. float minDist = Mathf.Min(xDistToMin, xDistToMax, zDistToMin, zDistToMax);
  337. // 根据最近的边界调整相机位置
  338. if (minDist == xDistToMin)
  339. {
  340. // 相机靠近最小X边界
  341. _position.x = minPoint.x - 0.1f;
  342. }
  343. else if (minDist == xDistToMax)
  344. {
  345. // 相机靠近最大X边界
  346. _position.x = maxPoint.x + 0.1f;
  347. }
  348. else if (minDist == zDistToMin)
  349. {
  350. // 相机靠近最小Z边界
  351. _position.z = minPoint.z - 0.1f;
  352. }
  353. else if (minDist == zDistToMax)
  354. {
  355. // 相机靠近最大Z边界
  356. _position.z = maxPoint.z + 0.1f;
  357. }
  358. return _position;
  359. }
  360. /// <summary>
  361. /// 设置相机的移动范围
  362. /// </summary>
  363. /// <param name="_minPoint"></param>
  364. /// <param name="_maxPoint"></param>
  365. private void SetCameraPosLimite(Vector3 _minPoint, Vector3 _maxPoint)
  366. {
  367. xMin = _minPoint.x;
  368. xMax = _maxPoint.x;
  369. yMin = _minPoint.y;
  370. yMax = _maxPoint.y;
  371. zMin = _minPoint.z;
  372. zMax = _maxPoint.z;
  373. }
  374. /// <summary>
  375. /// 控制摄像机的旋转角度大小
  376. /// </summary>
  377. /// <param name="_angle"></param>
  378. /// <param name="_min"></param>
  379. /// <param name="_max"></param>
  380. /// <returns></returns>
  381. private float ClampAngle(float _angle, float _min, float _max)
  382. {
  383. if (_angle < -360)
  384. {
  385. _angle += 360;
  386. }
  387. if (_angle > 360)
  388. {
  389. _angle -= 360;
  390. }
  391. return Mathf.Clamp(_angle, _min, _max);
  392. }
  393. private void OnDrawGizmos()
  394. {
  395. if (m_IsDragAreaEffect)
  396. {
  397. Gizmos.color = Color.green;
  398. Gizmos.DrawWireCube(new Vector3((xMin + xMax) / 2, (yMin + yMax) / 2, (zMin + zMax) / 2),
  399. new Vector3(xMax - xMin, yMax - yMin, zMax - zMin));
  400. Gizmos.color = Color.red;
  401. if (m_LimitAreas != null)
  402. {
  403. foreach (LimitArea house in m_LimitAreas)
  404. {
  405. Vector3 minPoint = house.minPoint.position;
  406. Vector3 maxPoint = house.maxPoint.position;
  407. Vector3 center = (minPoint + maxPoint) / 2;
  408. Vector3 size = maxPoint - minPoint;
  409. Gizmos.DrawWireCube(center, size);
  410. }
  411. }
  412. }
  413. }
  414. /// <summary>
  415. /// 设置相机的初始数据
  416. /// </summary>
  417. private void SetCameraInitData()
  418. {
  419. CameraConfig cameraConfig = GetCameraConfigData();
  420. if (cameraConfig == null)
  421. {
  422. return;
  423. }
  424. m_MoveSpeed = cameraConfig.MoveSpeed;
  425. m_XSpeed = cameraConfig.XRotateSpeed;
  426. m_YSpeed = cameraConfig.YRotateSpeed;
  427. m_MouseSpeed = cameraConfig.MiddleMouseZoomSpeed;
  428. m_YMinLimit = cameraConfig.YMinLimit;
  429. m_YMaxLimit = cameraConfig.YMaxLimit;
  430. m_SpeedLimit = cameraConfig.MiddleMouseMoveSpeed;
  431. }
  432. /// <summary>
  433. /// 获取相机配置数据
  434. /// </summary>
  435. /// <returns></returns>
  436. private CameraConfig GetCameraConfigData()
  437. {
  438. // 拼接文件基本路径
  439. string filePath = PathHelper.CombineFilePath(PathHelper.m_ReadOnlyPath,
  440. "Json",
  441. "CameraConfig.json");
  442. string fileData = FileHelper.GetAllDataInfo(filePath);
  443. CameraConfig config = JsonUtility.FromJson<CameraConfig>(fileData);
  444. return config == null ? null : config;
  445. }
  446. }
  447. }