RoamCameraController.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using DG.Tweening;
  4. using UnityEngine.EventSystems;
  5. using UnityEngine.UIElements;
  6. using QFramework;
  7. /// <summary>
  8. /// 漫游视角 相机控制脚本
  9. /// </summary>
  10. public class RoamCameraController : MonoSingleton<RoamCameraController>
  11. {
  12. /// <summary>
  13. /// 相机状态类
  14. /// </summary>
  15. private class CameraState
  16. {
  17. /// <summary>
  18. /// 坐标x值
  19. /// </summary>
  20. public float posX;
  21. /// <summary>
  22. /// 坐标y值
  23. /// </summary>
  24. public float posY;
  25. /// <summary>
  26. /// 坐标z值
  27. /// </summary>
  28. public float posZ;
  29. /// <summary>
  30. /// 旋转x值
  31. /// </summary>
  32. public float rotX;
  33. /// <summary>
  34. /// 旋转y值
  35. /// </summary>
  36. public float rotY;
  37. /// <summary>
  38. /// 旋转z值
  39. /// </summary>
  40. public float rotZ;
  41. //活动区域限制
  42. private readonly float xMinValue;
  43. private readonly float xMaxValue;
  44. private readonly float yMinValue;
  45. private readonly float yMaxValue;
  46. private readonly float zMinValue;
  47. private readonly float zMaxValue;
  48. /// <summary>
  49. /// 默认构造函数
  50. /// </summary>
  51. public CameraState()
  52. {
  53. xMinValue = float.MinValue;
  54. xMaxValue = float.MaxValue;
  55. yMinValue = float.MinValue;
  56. yMaxValue = float.MaxValue;
  57. zMinValue = float.MinValue;
  58. zMaxValue = float.MaxValue;
  59. }
  60. /// <summary>
  61. /// 构造函数
  62. /// </summary>
  63. /// <param name="xMinValue"></param>
  64. /// <param name="xMaxValue"></param>
  65. /// <param name="yMinValue"></param>
  66. /// <param name="yMaxValue"></param>
  67. /// <param name="zMinValue"></param>
  68. /// <param name="zMaxValue"></param>
  69. public CameraState(float xMinValue, float xMaxValue, float yMinValue, float yMaxValue, float zMinValue, float zMaxValue)
  70. {
  71. this.xMinValue = xMinValue;
  72. this.xMaxValue = xMaxValue;
  73. this.yMinValue = yMinValue;
  74. this.yMaxValue = yMaxValue;
  75. this.zMinValue = zMinValue;
  76. this.zMaxValue = zMaxValue;
  77. }
  78. /// <summary>
  79. /// 根据Transform组件更新状态
  80. /// </summary>
  81. /// <param name="t">Transform组件</param>
  82. public void SetFromTransform(Transform t)
  83. {
  84. posX = t.position.x;
  85. posY = t.position.y;
  86. posZ = t.position.z;
  87. rotX = t.eulerAngles.x;
  88. rotY = t.eulerAngles.y;
  89. rotZ = t.eulerAngles.z;
  90. }
  91. /// <summary>
  92. /// 移动
  93. /// </summary>
  94. public void Translate(Vector3 translation)
  95. {
  96. Vector3 rotatedTranslation = Quaternion.Euler(rotX, rotY, rotZ) * translation;
  97. posX += rotatedTranslation.x;
  98. posY += rotatedTranslation.y;
  99. posZ += rotatedTranslation.z;
  100. posX = Mathf.Clamp(posX, xMinValue, xMaxValue);
  101. posY = Mathf.Clamp(posY, yMinValue, yMaxValue);
  102. posZ = Mathf.Clamp(posZ, zMinValue, zMaxValue);
  103. }
  104. /// <summary>
  105. /// 根据目标状态插值运算
  106. /// </summary>
  107. /// <param name="target">目标状态</param>
  108. /// <param name="positionLerpPct">位置插值率</param>
  109. /// <param name="rotationLerpPct">旋转插值率</param>
  110. public void LerpTowards(CameraState target, float positionLerpPct, float rotationLerpPct)
  111. {
  112. posX = Mathf.Lerp(posX, target.posX, positionLerpPct);
  113. posY = Mathf.Lerp(posY, target.posY, positionLerpPct);
  114. posZ = Mathf.Lerp(posZ, target.posZ, positionLerpPct);
  115. rotX = Mathf.Lerp(rotX, target.rotX, rotationLerpPct);
  116. rotY = Mathf.Lerp(rotY, target.rotY, rotationLerpPct);
  117. rotZ = Mathf.Lerp(rotZ, target.rotZ, rotationLerpPct);
  118. }
  119. /// <summary>
  120. /// 根据状态刷新Transform组件
  121. /// </summary>
  122. /// <param name="t">Transform组件</param>
  123. public void UpdateTransform(Transform t)
  124. {
  125. t.position = new Vector3(posX, posY, posZ);
  126. t.rotation = Quaternion.Euler(rotX, rotY, rotZ);
  127. }
  128. }
  129. #region Private Variables
  130. //控制开关
  131. [SerializeField]
  132. public bool toggle = true;
  133. //是否限制活动范围
  134. [SerializeField]
  135. private bool isRangeClamped;
  136. //限制范围 当isRangeClamped为true时起作用
  137. [SerializeField]
  138. private float xMinValue = -100f; //x最小值
  139. [SerializeField]
  140. private float xMaxValue = 100f; //x最大值
  141. [SerializeField]
  142. private float yMinValue = 0f; //y最小值
  143. [SerializeField]
  144. private float yMaxValue = 100f; //y最大值
  145. [SerializeField]
  146. private float zMinValue = -100f; //z最小值
  147. [SerializeField]
  148. private float zMaxValue = 100f; //z最大值
  149. //移动速度
  150. [SerializeField]
  151. private float translateSpeed = 10f;
  152. public float TranslateSpeed
  153. {
  154. get { return translateSpeed; }
  155. set { translateSpeed = value; }
  156. }
  157. //加速系数 Shift按下时起作用
  158. [SerializeField]
  159. private float boost = 3.5f;
  160. //插值到目标位置所需的时间
  161. [Range(0.01f, 1f), SerializeField]
  162. private float positionLerpTime = 1f;
  163. //插值到目标旋转所需的时间
  164. [Range(0.01f, 1f), SerializeField]
  165. private float rotationLerpTime = 1f;
  166. //鼠标运动的灵敏度
  167. [Range(0.1f, 10f), SerializeField]
  168. private float mouseMovementSensitivity = 1f;
  169. //鼠标滚轮运动的速度
  170. [SerializeField]
  171. private float mouseScrollMoveSpeed = 10f;
  172. public float MouseScrollMoveSpeed
  173. {
  174. get { return mouseMovementSensitivity; }
  175. set { mouseMovementSensitivity = value; }
  176. }
  177. //用于鼠标滚轮移动 是否反转方向
  178. [SerializeField]
  179. private bool invertScrollDirection = false;
  180. //视角旋转是否反转y反向
  181. [SerializeField]
  182. private bool invertY = false;
  183. //用于限制垂直方向上旋转的最大值
  184. [SerializeField]
  185. private float verticalLimitMax = 60f;
  186. //用于限制垂直方向上旋转的最小值
  187. [SerializeField]
  188. private float verticalLimitMin = -60f;
  189. //移动量
  190. private Vector3 translation = Vector3.zero;
  191. //Tween动画
  192. private Tween tween;
  193. private CameraState initialCameraState;
  194. private CameraState targetCameraState;
  195. private CameraState interpolatingCameraState;
  196. #endregion
  197. #region Private Methods
  198. private void Awake()
  199. {
  200. //初始化
  201. if (isRangeClamped)
  202. {
  203. initialCameraState = new CameraState(xMinValue, xMaxValue, yMinValue, yMaxValue, zMinValue, zMaxValue);
  204. targetCameraState = new CameraState(xMinValue, xMaxValue, yMinValue, yMaxValue, zMinValue, zMaxValue);
  205. interpolatingCameraState = new CameraState(xMinValue, xMaxValue, yMinValue, yMaxValue, zMinValue, zMaxValue);
  206. }
  207. else
  208. {
  209. initialCameraState = new CameraState();
  210. targetCameraState = new CameraState();
  211. interpolatingCameraState = new CameraState();
  212. }
  213. interpolatingCameraState.SetFromTransform(transform);
  214. targetCameraState.SetFromTransform(transform);
  215. }
  216. private void OnEnable()
  217. {
  218. initialCameraState.SetFromTransform(transform);
  219. targetCameraState.SetFromTransform(transform);
  220. interpolatingCameraState.SetFromTransform(transform);
  221. }
  222. private void LateUpdate()
  223. {
  224. if (!toggle) return;
  225. //关闭UI移动
  226. if (EventSystem.current.IsPointerOverGameObject()) return;
  227. OnRotateUpdate();
  228. OnTranslateUpdate();
  229. OnResetUpdate();
  230. }
  231. private void OnRotateUpdate()
  232. {
  233. #if ENABLE_INPUT_SYSTEM
  234. bool pressed = Mouse.current.rightButton.isPressed;
  235. #else
  236. bool pressed = Input.GetMouseButton(1);
  237. #endif
  238. if (pressed)
  239. {
  240. #if ENABLE_INPUT_SYSTEM
  241. Vector2 input = Mouse.current.delta.ReadValue();
  242. #else
  243. Vector2 input = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
  244. #endif
  245. input.y *= invertY ? 1 : -1;
  246. //float mouseSensitivityFactor = mouseRotationSensitivityCurve.Evaluate(input.magnitude);
  247. targetCameraState.rotY += input.x * mouseMovementSensitivity;
  248. targetCameraState.rotX += input.y * mouseMovementSensitivity;
  249. targetCameraState.rotX = Mathf.Clamp(targetCameraState.rotX, verticalLimitMin, verticalLimitMax);
  250. }
  251. }
  252. private void OnResetUpdate()
  253. {
  254. #if ENABLE_INPUT_SYSTEM
  255. bool uPressed = Keyboard.current.uKey.wasPressedThisFrame;
  256. #else
  257. bool uPressed = Input.GetKeyDown(KeyCode.U);
  258. #endif
  259. //U键按下重置到初始状态
  260. if (uPressed)
  261. {
  262. ResetCamera();
  263. }
  264. }
  265. private void OnTranslateUpdate()
  266. {
  267. float timeDelatime = 0.02f;
  268. if (Time.timeScale == 1) timeDelatime = Time.deltaTime;
  269. translation = GetInputTranslation() * timeDelatime * translateSpeed;
  270. targetCameraState.Translate(translation);
  271. float positionLerpPct = 1f - Mathf.Exp(Mathf.Log(1f - .99f) / positionLerpTime * timeDelatime);
  272. float rotationLerpPct = 1f - Mathf.Exp(Mathf.Log(1f - .99f) / rotationLerpTime * timeDelatime);
  273. interpolatingCameraState.LerpTowards(targetCameraState, positionLerpPct, rotationLerpPct);
  274. interpolatingCameraState.UpdateTransform(transform);
  275. }
  276. //移动启动时间
  277. private float MoveKeyStartLerp;
  278. //获取输入
  279. private Vector3 GetInputTranslation()
  280. {
  281. Vector3 ts = new Vector3();
  282. //键盘W、A、S、D、Q、E控制运动方向
  283. #if ENABLE_INPUT_SYSTEM
  284. if (Keyboard.current.wKey.isPressed) ts += Vector3.forward;
  285. if (Keyboard.current.sKey.isPressed) ts += Vector3.back;
  286. if (Keyboard.current.aKey.isPressed) ts += Vector3.left;
  287. if (Keyboard.current.dKey.isPressed) ts += Vector3.right;
  288. if (Keyboard.current.qKey.isPressed) ts += Vector3.down;
  289. if (Keyboard.current.eKey.isPressed) ts += Vector3.up;
  290. #else
  291. //初始按键移动的时候移动速度渐增
  292. if (!Input.GetKey(KeyCode.W)
  293. && !Input.GetKey(KeyCode.S)
  294. && !Input.GetKey(KeyCode.A)
  295. && !Input.GetKey(KeyCode.D)
  296. && !Input.GetKey(KeyCode.Q)
  297. && !Input.GetKey(KeyCode.E))
  298. MoveKeyStartLerp = 0;
  299. if (Input.GetKey(KeyCode.W)
  300. || Input.GetKey(KeyCode.S)
  301. || Input.GetKey(KeyCode.A)
  302. || Input.GetKey(KeyCode.D)
  303. || Input.GetKey(KeyCode.Q)
  304. || Input.GetKey(KeyCode.E))
  305. {
  306. MoveKeyStartLerp += Time.deltaTime/2;
  307. MoveKeyStartLerp = Mathf.Clamp(MoveKeyStartLerp, 0, 1);
  308. }
  309. if (Input.GetKey(KeyCode.W)) ts += Vector3.forward;
  310. if (Input.GetKey(KeyCode.S)) ts += Vector3.back;
  311. if (Input.GetKey(KeyCode.A)) ts += Vector3.left;
  312. if (Input.GetKey(KeyCode.D)) ts += Vector3.right;
  313. if (Input.GetKey(KeyCode.Q)) ts += Vector3.down;
  314. if (Input.GetKey(KeyCode.E)) ts += Vector3.up;
  315. ts = ts * MoveKeyStartLerp;
  316. #endif
  317. #if ENABLE_INPUT_SYSTEM
  318. //读取鼠标滚轮滚动值
  319. float wheelValue = Mouse.current.scroll.ReadValue().y;
  320. #else
  321. float wheelValue = Input.GetAxis("Mouse ScrollWheel");
  322. #endif
  323. ts += (wheelValue == 0
  324. ? Vector3.zero
  325. : (wheelValue > 0 ? Vector3.forward : Vector3.back) * (invertScrollDirection ? -1 : 1)) * mouseScrollMoveSpeed;
  326. #if ENABLE_INPUT_SYSTEM
  327. //左Shift键按下时加速
  328. if (Keyboard.current.leftShiftKey.isPressed) ts *= boost;
  329. #elif ENABLE_INPUT_SYSTEM
  330. if (Input.GetKey(KeyCode.LeftShift)) ts *= boost;
  331. #else
  332. if (Input.GetMouseButton(2))
  333. {
  334. ts.y = -Input.GetAxis("Mouse Y");
  335. ts.x = -Input.GetAxis("Mouse X");
  336. }
  337. #endif
  338. return ts;
  339. }
  340. #if UNITY_EDITOR
  341. private void OnDrawGizmos()
  342. {
  343. //如果限制活动范围 将区域范围绘制出来
  344. if (isRangeClamped)
  345. {
  346. Gizmos.color = Color.red;
  347. Vector3[] points = new Vector3[8]
  348. {
  349. new Vector3(xMinValue, yMinValue, zMinValue),
  350. new Vector3(xMaxValue, yMinValue, zMinValue),
  351. new Vector3(xMaxValue, yMinValue, zMaxValue),
  352. new Vector3(xMinValue, yMinValue, zMaxValue),
  353. new Vector3(xMinValue, yMaxValue, zMinValue),
  354. new Vector3(xMaxValue, yMaxValue, zMinValue),
  355. new Vector3(xMaxValue, yMaxValue, zMaxValue),
  356. new Vector3(xMinValue, yMaxValue, zMaxValue)
  357. };
  358. for (int i = 0; i < 4; i++)
  359. {
  360. int start = i % 4;
  361. int end = (i + 1) % 4;
  362. Gizmos.DrawLine(points[start], points[end]);
  363. Gizmos.DrawLine(points[start + 4], points[end + 4]);
  364. Gizmos.DrawLine(points[start], points[i + 4]);
  365. }
  366. }
  367. }
  368. #endif
  369. #endregion
  370. #region Public Methods
  371. /// <summary>
  372. /// 设置相机可移动与否
  373. /// </summary>
  374. /// <param name="state"></param>
  375. public void SetCameraMoveState(bool state)
  376. {
  377. if (state)
  378. {
  379. interpolatingCameraState.SetFromTransform(transform);
  380. targetCameraState.SetFromTransform(transform);
  381. }
  382. toggle = state;
  383. }
  384. /// <summary>
  385. /// 重置摄像机到初始状态
  386. /// </summary>
  387. public void ResetCamera()
  388. {
  389. initialCameraState.UpdateTransform(transform);
  390. targetCameraState.SetFromTransform(transform);
  391. interpolatingCameraState.SetFromTransform(transform);
  392. }
  393. /// <summary>
  394. /// 聚焦
  395. /// </summary>
  396. /// <param name="position">目标位置</param>
  397. /// <param name="rotation">目标旋转</param>
  398. /// <param name="duration">时长</param>
  399. public void Focus(Vector3 position, Vector3 rotation, float duration, bool _toggle = true)
  400. {
  401. tween?.Kill();
  402. toggle = false;
  403. transform.DORotate(rotation, duration);
  404. tween = transform.DOMove(position, duration).Play()
  405. .OnKill(() =>
  406. {
  407. if (UIKit.GetPanel<CameraPoseSetPanel>())
  408. {
  409. toggle = true;
  410. }
  411. else
  412. {
  413. toggle = _toggle;
  414. }
  415. interpolatingCameraState.SetFromTransform(transform);
  416. targetCameraState.SetFromTransform(transform);
  417. tween = null;
  418. });
  419. }
  420. public void SetCameraState(Vector3 position, Vector3 rotation)
  421. {
  422. if (position == Vector3.zero) return;
  423. transform.eulerAngles = rotation;
  424. transform.position = position;
  425. interpolatingCameraState.SetFromTransform(transform);
  426. targetCameraState.SetFromTransform(transform);
  427. }
  428. public void ChangeIsRangeClamped()
  429. {
  430. isRangeClamped = !isRangeClamped;
  431. }
  432. #endregion
  433. }