最终效果:
当我们对准场景中的一个物体时,可以显示这个物体的名称或者对这个物体的描述。如图所示,我们对准了场景中的一个桌子,对这个桌子的描述:is a aimable gameobject. 会显示在一旁。除此之外,我们可以添加瞄准进入事件,瞄准离开事件,瞄准停留事件,鼠标点击事件。

思路:
实现该系统所需要编写的几个内容:
1.AimSystem 其实就是一个射线检测系统,不停的去检测场景中可以进行瞄准的物体。
2.IAimableObject 可以瞄准的物体所继承的接口。

3.AimSystemPanel UI界面 用来显示瞄准物体的名称或者描述。
AimSystem:
using KFramework; using UnityEngine; /// <summary> /// 瞄准系统 /// </summary> public class AimSystem : MonoBehaviour { public static AimSystem Instance { get; private set; } private void Awake() => Instance = this; //瞄准距离 (即射线检测的距离、检测范围) readonly float mAimDistance = 5f; /// <summary> /// 当前所瞄准的物体 /// </summary> public IAimableObject CurrentAimableObject { get; private set; } //射线 Ray ray; //是否检测到碰撞 bool isHit; //碰撞信息 RaycastHit hit; /* 射线起点 * 从屏幕正中央发出射线 * (0.5f,0.5f) */ Vector2 mCentralPoint = Vector2.one * 0.5f; //UI界面 AimSystemPanel panel; private void Start() { //打开界面 panel = UIMgr.OpenPanel<AimSystemPanel>(prefabName: "Resources/AimSystemPanel"); } public void AimEnter(string str) => panel.AimEnter(str); public void AimExit() => panel.AimExit(); private void Update() { //从主相机视角中央发出射线 ray = Camera.main.ViewportPointToRay(mCentralPoint); //是否检测到碰撞 isHit = Physics.Raycast(ray, out hit, mAimDistance); if (isHit) { /* 所检测到的物体是否继承 IAimableObject 接口 * 即是否为可瞄准物体 */ GameObject aimTarget = hit.collider.gameObject; IAimableObject aimObject = aimTarget.GetComponent<IAimableObject>(); //如果可瞄准物体所设定的可被检测距离 小于 当前实际距离 将其置为空 表示没有检测到 (null != aimObject && aimObject.AimDistance < hit.distance).Invoke(() => aimObject = null); //如果与当前可瞄准物体不一致 表示检测到新的可瞄准物体 if (aimObject != CurrentAimableObject) { /* * 如果上一个可瞄准物体不为空 执行其瞄准离开事件 * 将当前可瞄准物体 赋值为新检测到的 * 执行当前可瞄准物体的 瞄准进入事件 */ CurrentAimableObject?.OnAimExit(); CurrentAimableObject = aimObject; CurrentAimableObject?.OnAimEnter(); } //如果点击鼠标左键且当前可瞄准物体不为空 执行其鼠标点击事件 Input.GetMouseButtonDown(0).Invoke(() => CurrentAimableObject?.DoInteract()); } /* * 此处表示没有碰撞信息 * 如果当前可瞄准物体不为空 * 执行其瞄准离开事件 并将其置为空 */ else { if (null != CurrentAimableObject) { CurrentAimableObject.OnAimExit(); CurrentAimableObject = null; } } //如果当前可瞄准物体不为空 不停执行其瞄准停留事件 CurrentAimableObject?.OnAimStay(); } private void OnDestroy() { Instance = null; //卸载UI界面 if(Application.isPlaying) UIMgr.ClosePanel<AimSystemPanel>(); } }
讯享网
IAimableObject:
讯享网/// <summary> /// 可瞄准物体接口 /// </summary> public interface IAimableObject { /// <summary> /// 瞄准距离(可被检测的距离) /// </summary> float AimDistance { get; } /// <summary> /// 物体的名称或对其描述 /// </summary> string AimDescription { get; } /// <summary> /// 瞄准进入事件 /// </summary> void OnAimEnter(); /// <summary> /// 瞄准离开事件 /// </summary> void OnAimExit(); /// <summary> /// 瞄准停留事件 /// </summary> void OnAimStay(); /// <summary> /// 鼠标点击事件 /// </summary> void DoInteract(); }
AimSystemPanel 不再赘述,只需要一个Text文本框,当瞄准进入时显示其AimDescription,当瞄准离开时将Text文本框内容清空。
下面是继承接口的一个实现:
using System; using UnityEngine; /// <summary> /// 可瞄准物体基类 /// </summary> public class AimableObject : MonoBehaviour, IAimableObject { //瞄准进入事件 可以进行事件的追加和删除 private Action mOnEnterEvent; //瞄准离开事件 可以进行事件的追加和删除 private Action mOnExitEvent; //瞄准距离(可被检测的距离) 子类去重写 protected virtual float AimDistance => 5f; //物体的名称或对其描述 子类去重写 protected virtual string AimDescription => name; /// <summary> /// 瞄准进入事件 /// </summary> protected virtual void OnAimEnter() { mOnEnterEvent?.Invoke(); AimSystem.Instance.AimEnter(AimDescription); } /// <summary> /// 瞄准离开事件 /// </summary> protected virtual void OnAimExit() { mOnExitEvent?.Invoke(); AimSystem.Instance.AimExit(); } /// <summary> /// 瞄准停留事件 /// </summary> protected virtual void OnAimStay() { } /// <summary> /// 鼠标点击事件 /// </summary> protected virtual void DoInteract() { } float IAimableObject.AimDistance => AimDistance; string IAimableObject.AimDescription => AimDescription; void IAimableObject.OnAimEnter() => OnAimEnter(); void IAimableObject.OnAimExit() => OnAimExit(); void IAimableObject.OnAimStay() => OnAimStay(); void IAimableObject.DoInteract() => DoInteract(); protected virtual void OnDestroy() { mOnEnterEvent = null; mOnExitEvent = null; } /// <summary> /// 对瞄准进入事件进行追加 /// </summary> /// <param name="action"></param> public void AppendAimEnterEvent(Action action) { if (null == mOnEnterEvent) mOnEnterEvent = action; else { Delegate[] delegates = mOnEnterEvent.GetInvocationList(); if (!Array.Exists(delegates, v => v == (Delegate)action)) mOnEnterEvent += action; } } /// <summary> /// 对瞄准离开事件进行追加 /// </summary> /// <param name="action"></param> public void AppendAimExitEvent(Action action) { if (null == mOnExitEvent) mOnExitEvent = action; else { Delegate[] delegates = mOnExitEvent.GetInvocationList(); if (!Array.Exists(delegates, v => v == (Delegate)action)) mOnExitEvent += action; } } /// <summary> /// 对瞄准进入事件进行删除 /// </summary> /// <param name="action"></param> public void DeleteAimEnterEvent(Action action) { if (null == mOnEnterEvent) return; Delegate[] delegates = mOnEnterEvent.GetInvocationList(); if (Array.Exists(delegates, v => v == (Delegate)action)) mOnEnterEvent -= action; } /// <summary> /// 对瞄准离开事件进行删除 /// </summary> /// <param name="action"></param> public void DeleteAimExitEvent(Action action) { if (null == mOnExitEvent) return; Delegate[] delegates = mOnExitEvent.GetInvocationList(); if (Array.Exists(delegates, v => v == (Delegate)action)) mOnExitEvent -= action; } }
Example:
讯享网using UnityEngine; public class AimableObjectExample : AimableObject { protected override string AimDescription => "Is a aimable gameobject."; protected override float AimDistance => 4.5f; protected override void OnAimEnter() { base.OnAimEnter(); Debug.Log("OnAimEnter"); } protected override void OnAimExit() { base.OnAimExit(); Debug.Log("OnAimExit"); } protected override void DoInteract() { Debug.Log("DoInteract"); } protected override void OnAimStay() { Debug.Log("OnAimStay"); } }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/75406.html