CrossHair.cs 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. using System;
  2. using UnityEngine;
  3. namespace SmartBowSDK
  4. {
  5. public class CrossHair : MonoBehaviour
  6. {
  7. /// <summary>
  8. /// 瞄准器,基于其位置发射射线,射线的hitpoint转屏幕坐标,该坐标即准心坐标
  9. /// </summary>
  10. public Transform aimTransform;
  11. /// <summary>
  12. /// 是否限制瞄准器在屏幕范围内
  13. /// </summary>
  14. public bool limitAimInScrren;
  15. private RectTransform _rectTransform;
  16. private RectTransform _canvasRectTransform;
  17. void Awake()
  18. {
  19. _rectTransform = GetComponent<RectTransform>();
  20. _canvasRectTransform = GetComponentInParent<Canvas>().GetComponent<RectTransform>();
  21. }
  22. void Start()
  23. {
  24. InitForLimitBound();
  25. }
  26. void LateUpdate()
  27. {
  28. if (limitAimInScrren) aimTransform.eulerAngles = LimitAngles(aimTransform.eulerAngles);
  29. UpdateCrossHairPosition();
  30. }
  31. void UpdateCrossHairPosition()
  32. {
  33. Ray ray = new Ray(aimTransform.position, aimTransform.forward);
  34. RaycastHit hitInfo;
  35. Vector3 hitPoint;
  36. if (Physics.Raycast(ray, out hitInfo, 100)) hitPoint = hitInfo.point;
  37. else hitPoint = aimTransform.position + aimTransform.forward * 100f;
  38. Vector2 viewPoint = Camera.main.WorldToViewportPoint(hitPoint);
  39. _rectTransform.localPosition = (viewPoint - Vector2.one * 0.5f) * _canvasRectTransform.rect.size;
  40. }
  41. #region 限制其显示范围不超出屏幕
  42. private float _screenWidthHalf;
  43. private float _screenHeightHalf;
  44. private float _screenNormal;
  45. private float _rangeRotateY;
  46. private float _rangeRotateX;
  47. /// <summary>
  48. /// 标记是否出界(-1:未出界;0:左边出界;1:右边出界;2:上边出界;3:下边出界;)
  49. /// </summary>
  50. [NonSerialized] public int outBoundIndex = -1;
  51. void InitForLimitBound()
  52. {
  53. Camera camera = Camera.main;
  54. _rangeRotateX = camera.fieldOfView / 2;
  55. _screenWidthHalf = Screen.width / 2f;
  56. _screenHeightHalf = Screen.height / 2f;
  57. _screenNormal = _screenHeightHalf / Mathf.Tan(_rangeRotateX / 180f * Mathf.PI);
  58. _rangeRotateY = Mathf.Atan(_screenWidthHalf / _screenNormal) / Mathf.PI * 180f;
  59. }
  60. Vector3 LimitAngles(Vector3 angles)
  61. {
  62. //Unity默认范围(0,360)格式化为自定义范围(-180,180)
  63. angles.y = angles.y > 180 ? angles.y - 360 : angles.y;
  64. angles.x = angles.x > 180 ? angles.x - 360 : angles.x;
  65. //记录原来的角度
  66. float angleY = angles.y;
  67. float angleX = angles.x;
  68. //记录是否出界
  69. if (angleY < -_rangeRotateY) outBoundIndex = 0;
  70. else if (angleY > _rangeRotateY) outBoundIndex = 1;
  71. else if (angleX < -_rangeRotateX) outBoundIndex = 2;
  72. else if (angleX > _rangeRotateX) outBoundIndex = 3;
  73. else outBoundIndex = -1;
  74. //返回限制边界后的角度
  75. angles.y = Mathf.Clamp(angleY, -_rangeRotateY, _rangeRotateY);
  76. float rayLen = _screenNormal / Mathf.Cos(Mathf.Abs(angles.y) / 180 * Mathf.PI);
  77. float maxRangeRotateX = Mathf.Atan(_screenHeightHalf / rayLen) / Mathf.PI * 180f;
  78. if (Mathf.Abs(angleX) > Mathf.Abs(maxRangeRotateX)) angles.x = maxRangeRotateX * (angleX > 0 ? 1 : -1);
  79. return angles;
  80. }
  81. #endregion
  82. }
  83. }