using System; using UnityEngine; public class CrossHair : MonoBehaviour { /// /// 瞄准器,基于其位置发射射线,射线的hitpoint转屏幕坐标,该坐标即准心坐标 /// public Transform aimTransform; /// /// 是否限制瞄准器在屏幕范围内 /// public bool limitAimInScrren; private RectTransform _rectTransform; private RectTransform _canvasRectTransform; void Awake() { _rectTransform = GetComponent(); _canvasRectTransform = GetComponentInParent().GetComponent(); } 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; /// /// 标记是否出界(-1:未出界;0:左边出界;1:右边出界;2:上边出界;3:下边出界;) /// [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 }