之前我们实现了“UGUI面板跟随标注3D模型功能”,效果如下图:
发现要是物体都移出视野外后提示都会消失,在需要重点提示的对象上,如果不在视野内有指示效果会更好,于是本文的实现的功能就很有必要,效果如下:
要实现在屏幕内的动态提示,只需要实现两个重要步骤:
1计算出提示UI在屏幕空间内的位置;
2计算出箭头指向的方向。
流程图如下:
本案例是在这两篇文章的基础上开发的:
Unity3d C# 实现UGUI面板跟随标注3D模型功能(含源码)
Unity3d C# 实现纯鼠标平滑控制场景摄像头(相机)实现自由旋转、移动和围绕节点移动旋转等功能(含源码工程)
如果有不明白的地方可以过去瞅一眼。
按如上的实现思路我们开始着手实现。
UI较简单,网上下个箭头图片,并新增了如下图的节点:
[Header("目标点")] public Transform target; [Header("UI画布")] public Canvas canvas; [Header("箭头节点(向上)")] public RectTransform arrow; //方向不对需要调制
分别需要配置如上图的节点,只需拖入即可。
注意的是箭头的图片箭头方向需向上,如果不同方向的话,自己改GetArrowEuler函数吧。
Vector2 viewPos = Camera.main.WorldToViewportPoint(target.position); Vector3 dir = (target.position - Camera.main.transform.position).normalized; float dot = Vector3.Dot(Camera.main.transform.forward, dir); if (dot > 0 && viewPos.x > 0 && viewPos.x < 1 && viewPos.y > 0 && viewPos.y < 1) return true; else return false;
private Vector2 GetTipPosInRect(Vector2 pos, Rect rect) { return new Vector2(Mathf.Clamp(pos.x, rect.xMin, rect.xMax), Mathf.Clamp(pos.y, rect.yMin, rect.yMax)); } private Rect GetRectInCanvas() { Rect rect = Rect.zero; Vector2 area = canvas.GetComponent<RectTransform>().sizeDelta; rect.xMax = area.x - TipTrans.sizeDelta.x / 2; rect.yMax = area.y - TipTrans.sizeDelta.y / 2; rect.xMin = TipTrans.sizeDelta.x / 2; rect.yMin = TipTrans.sizeDelta.y / 2; return rect; }
public Vector3 GetArrowEuler(Vector3 TargetPos) { float dx = TargetPos.x - arrow.transform.position.x; float dy = TargetPos.y - arrow.transform.position.y; float RotZ = Mathf.Atan2(dy, dx) * 180 / Mathf.PI; RotZ -= 90; float DRotZ = RotZ - arrow.eulerAngles.z; if (DRotZ > 180) DRotZ -= 360; return new Vector3(0, 0, arrow.eulerAngles.z + DRotZ); }
if (!target) return; if (IsInScreen()) { transform.localScale = Vector3.zero; return; } transform.localScale = Vector3.one; var screenPos = RectTransformUtility.WorldToScreenPoint(Camera.main, target.position); TipTrans.position = GetTipPosInRect(screenPos, GetRectInCanvas()); if (arrow) arrow.eulerAngles = GetArrowEuler(screenPos);
这一步的实现完全是实现思路的复制,放在FixUpdate 或者Update都行。
先看图:
向右旋转后粉色的提示箭头跳到了右上角。这个是项目上测试给我反馈的bug。
目前没找到问题,如果有知道的也可以指点、探讨一下。
不过我感觉,应该是镜头旋转后提示位置的正常变化。
可以在每个提示框上添加按钮组件,点击后利用DOTween插件移动摄像头,快速聚焦目标对象。
编写点击脚本:
public void ClickPink() { Camera.main.transform.DOMove(new Vector3(-19.999157f, 2.20351362f, -0.876300693f), 1); Camera.main.transform.DORotate(new Vector3(32.8f, 0.9f, 0), 1); } public void ClickGreen() { Camera.main.transform.DOMove(new Vector3(0.366873235f, 3.28463149f, -1.07905042f), 1); Camera.main.transform.DORotate(new Vector3(33.6f, 1.1f, 0), 1); }
绑定按钮函数后,点击效果:
https://download.csdn.net/download/qq_33789001/79832111
如果无法打开,可能审核未通过。