Unity3d C# realizes the function of arrow indicating the position of 3D map object on UGUI (including source code)

Posted by SmoshySmosh on Fri, 11 Feb 2022 04:07:17 +0100


We did it before“ UGUI panel follow annotation 3D model function ”The effect is as follows:

It is found that if the objects are moved out of the field of view, the prompt will disappear. On the objects that need key prompt, the effect will be better if there is no indication in the field of view. Therefore, the functions realized in this paper are very necessary. The effects are as follows:

Realization idea

To realize the dynamic prompt on the screen, only two important steps need to be realized:
1 calculate the position of the prompt UI in the screen space;
2 calculate the direction of the arrow.

The flow chart is as follows:

Implementation process

This case is developed on the basis of these two articles:
Unity3d C# realizes the function of UGUI panel following and labeling 3D model (including source code)

Unity3d C# realizes the smooth control of the scene with a pure mouse, and the camera (camera) realizes the functions of free rotation, movement and rotation around nodes (including source code Engineering)

If you don't understand something, you can go and have a look.

According to the above implementation ideas, we begin to implement.

UI construction

The UI is relatively simple. There is an arrow image on the Internet and a new node as shown in the following figure is added:

Variable definition

[Header("Target point")]
    public Transform target;
    [Header("UI canvas")]
    public Canvas canvas;
    [Header("Arrow node (up)")]
    public RectTransform arrow;  //Wrong direction of modulation required

The nodes shown in the figure above need to be configured respectively. Just drag them in.
Note that the direction of the arrow in the picture of the arrow should be upward. If the direction is different, change the getarroweeuler function yourself.

Is it in view

        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;
            return false;

Get prompt display location

   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;

Get arrow angle

    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 detection

        if (!target)
        if (IsInScreen()) {
            transform.localScale = Vector3.zero;
        transform.localScale = Vector3.one;

        var screenPos = RectTransformUtility.WorldToScreenPoint(Camera.main, target.position);

        TipTrans.position = GetTipPosInRect(screenPos, GetRectInCanvas());

        if (arrow)
            arrow.eulerAngles = GetArrowEuler(screenPos);

The realization of this step is completely the replication of ideas, which can be placed in FixUpdate or Update.


Look at the picture first:

After rotating to the right, the pink prompt arrow jumps to the upper right corner. This is the bug that the test gave me feedback on the project.

I haven't found any problems at present. If I know something, I can give advice and discuss it.

But I think it should be the normal change of the prompt position after the lens rotates.


Button components can be added to each prompt box. After clicking, use the DOTween plug-in to move the camera and quickly focus on the target object.

Write click script:

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

After binding the button function, click the effect:

Engineering source code

If it cannot be opened, it may not pass the audit.

Topics: Unity3d