| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- using System;
- using UnityEngine;
- public class CrossHair : MonoBehaviour
- {
- /// <summary>
- /// 瞄准器,基于其位置发射射线,射线的hitpoint转屏幕坐标,该坐标即准心坐标
- /// </summary>
- public Transform aimTransform;
- /// <summary>
- /// 是否限制瞄准器在屏幕范围内
- /// </summary>
- public bool limitAimInScrren;
- private RectTransform _rectTransform;
- private RectTransform _canvasRectTransform;
- void Awake()
- {
- _rectTransform = GetComponent<RectTransform>();
- _canvasRectTransform = GetComponentInParent<Canvas>().GetComponent<RectTransform>();
- }
- void Start()
- {
- InitForLimitBound();
- }
- void LateUpdate()
- {
- if (limitAimInScrren) aimTransform.eulerAngles = LimitAngles(aimTransform.eulerAngles);
- UpdateCrossHairPosition();
- }
- void UpdateCrossHairPosition()
- {
- Ray ray = new Ray(aimTransform.position, aimTransform.forward);
- RaycastHit hitInfo;
- Vector3 hitPoint;
- if (Physics.Raycast(ray, out hitInfo, 100)) hitPoint = hitInfo.point;
- else hitPoint = aimTransform.position + aimTransform.forward * 100f;
- Vector2 viewPoint = Camera.main.WorldToViewportPoint(hitPoint);
- _rectTransform.localPosition = (viewPoint - Vector2.one * 0.5f) * _canvasRectTransform.rect.size;
- }
- #region 限制其显示范围不超出屏幕
- private float _screenWidthHalf;
- private float _screenHeightHalf;
- private float _screenNormal;
- private float _rangeRotateY;
- private float _rangeRotateX;
- /// <summary>
- /// 标记是否出界(-1:未出界;0:左边出界;1:右边出界;2:上边出界;3:下边出界;)
- /// </summary>
- [NonSerialized] public int outBoundIndex = -1;
- void InitForLimitBound()
- {
- Camera camera = Camera.main;
- _rangeRotateX = camera.fieldOfView / 2;
- _screenWidthHalf = Screen.width / 2f;
- _screenHeightHalf = Screen.height / 2f;
- _screenNormal = _screenHeightHalf / Mathf.Tan(_rangeRotateX / 180f * Mathf.PI);
- _rangeRotateY = Mathf.Atan(_screenWidthHalf / _screenNormal) / Mathf.PI * 180f;
- }
- Vector3 LimitAngles(Vector3 angles)
- {
- //Unity默认范围(0,360)格式化为自定义范围(-180,180)
- angles.y = angles.y > 180 ? angles.y - 360 : angles.y;
- angles.x = angles.x > 180 ? angles.x - 360 : angles.x;
- //记录原来的角度
- float angleY = angles.y;
- float angleX = angles.x;
- //记录是否出界
- if (angleY < -_rangeRotateY) outBoundIndex = 0;
- else if (angleY > _rangeRotateY) outBoundIndex = 1;
- else if (angleX < -_rangeRotateX) outBoundIndex = 2;
- else if (angleX > _rangeRotateX) outBoundIndex = 3;
- else outBoundIndex = -1;
- //返回限制边界后的角度
- angles.y = Mathf.Clamp(angleY, -_rangeRotateY, _rangeRotateY);
- float rayLen = _screenNormal / Mathf.Cos(Mathf.Abs(angles.y) / 180 * Mathf.PI);
- float maxRangeRotateX = Mathf.Atan(_screenHeightHalf / rayLen) / Mathf.PI * 180f;
- if (Mathf.Abs(angleX) > Mathf.Abs(maxRangeRotateX)) angles.x = maxRangeRotateX * (angleX > 0 ? 1 : -1);
- return angles;
- }
- #endregion
- }
|