CrossHair.cs 3.2 KB

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