ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Unity3d C#实现UGUI上箭头指示3D地图物体位置功能(含源码)

2022-02-09 13:58:50  阅读:327  来源: 互联网

标签:Unity3d Camera C# Vector3 transform 源码 arrow main rect


前言

之前我们实现了“UGUI面板跟随标注3D模型功能”,效果如下图:
在这里插入图片描述

发现要是物体都移出视野外后提示都会消失,在需要重点提示的对象上,如果不在视野内有指示效果会更好,于是本文的实现的功能就很有必要,效果如下:

在这里插入图片描述

实现思路

要实现在屏幕内的动态提示,只需要实现两个重要步骤:
1计算出提示UI在屏幕空间内的位置;
2计算出箭头指向的方向。

流程图如下:
在这里插入图片描述

实现过程

本案例是在这两篇文章的基础上开发的:
Unity3d C# 实现UGUI面板跟随标注3D模型功能(含源码)

Unity3d C# 实现纯鼠标平滑控制场景摄像头(相机)实现自由旋转、移动和围绕节点移动旋转等功能(含源码工程)

如果有不明白的地方可以过去瞅一眼。

按如上的实现思路我们开始着手实现。

UI搭建

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);
}

Update检测

        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
如果无法打开,可能审核未通过。

标签:Unity3d,Camera,C#,Vector3,transform,源码,arrow,main,rect
来源: https://blog.csdn.net/qq_33789001/article/details/122837978

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有