[C#] How to properly and efficiently display triangles over selected units?

I have a simple system in my 2d game that allows the player to select units, similar many other games.
I decided that the best way for the player to determine what units are selected is to simply draw triangles over each unit.

I decided to have a UI graphic component do the drawing, and it works flawlessly. But especially when you moving the camera, you can notice lag between the position of the unit and the triangle. here’s what i have so far:

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;

public class drawUnitSelections : Graphic{
    public List<Vector2> points;
  
    protected override void OnPopulateMesh(VertexHelper vh){
        Color32 color32 = color;
        vh.Clear();
      
        //remove empties from list
        for(int i=0;i<points.Count;i++){
            vh.AddVert(points[i], color32, new Vector2(0f, 0f));
            vh.AddVert(points[i]+new Vector2(7,10), color32, new Vector2(0f, 1f));
            vh.AddVert(points[i]+new Vector2(-7,10), color32, new Vector2(1f, 1f));
          
            vh.AddTriangle(i*3, i*3+1, i*3+2);
        }
    }
  
    void Update(){
      
        if(Application.isPlaying&&Time.frameCount%1==0){
            points.Clear();
            for(int i=UnitManager.main.selectedUnits.Count-1;i>=0;i--){
                Vector3 point = UnitManager.main.selectedUnits[i].transform.position;
                points.Add(Camera.main.WorldToScreenPoint(point+new Vector3(0,1.2f)));
            }
            SetAllDirty();//causes the mesh to be redrawn a frame or two later, causing the lag
        }
    }
}

OnPopulateMesh doesn’t seem to update on its own, even when i change the points, so i discovered that adding a SetAllDirty() causes OnPopulateMesh to be run again, but a frame too late, which causes lag.

The documentation on graphic doesn’t help at all. In fact it doesn’t even note the existence of OnPopulateMesh, or any other functions that could be useful. Thanks for the source @LeftyRighty

So what should I do? and is doing it like this the right way? (cause looping through all the selected units seems slow to me, but I don’t see any other way of doing this)

I would greatly appreciate any suggestions. thanks.

graphic source: https://bitbucket.org/Unity-Technologies/ui/src/0155c39e05ca5d7dcc97d9974256ef83bc122586/UnityEngine.UI/UI/Core/Graphic.cs?at=5.2&fileviewer=file-view-default :slight_smile:

some additional comments in there

1 Like

Thanks a lot.
I found that UpdateGeometry() directly calls OnPopulateMesh(), so I replaced SetAllDirty() with that, but that still doesn’t fix the lag issue, or answer any of my questions.

Bump?

Couldn’t you just put a little arrow graphic as a child object of the unit and turn it on and off when they’re selected? Seems like it would be much faster than rebuilding a dynamic mesh every frame.

1 Like

Are you sure you’re updating the UI after any camera movement has been done and not after. Just to make sure that’s not where the lagging behind is coming from.

1 Like

Makeswiftwings makes a good point or even instead of a arrow use a triangle would be a lot more efficient than the way you are trying to do it.

1 Like

I just throw on an extra sprite and make it active or inactive as needed.

If you need to upload mesh data instantly you can always use UploadMeshData

1 Like

I don’t have any experience with VertexHelper but isn’t the idea to use FillMesh to fill an actual Mesh object? If that’s the case you can also try using MarkDynamic to improve performance if you’re updating every frame.

1 Like

Sorry for not replying, I’ve been a bit preoccupied by work and sleep.

@makeshiftwings I could but then I have to make an object pool, and I would have to update the position of every arrow to stay above my units.

@ThermalFusion I believe the way my scripts are set up it should update right after the camera, but yeah I’ll try updating it directly.

@tawdry I am using triangles. The Script generates small triangle meshes over every unit.

@Kiwasi I’m not sure about the performance concerns behind that, but I’ll look into it.

@cjdev Thanks, I didn’t know about MarkDynamic. It should help me improve performance a lot. I wouldn’t need a pool of objects, and could simply regenerate my mesh on every update and after the camera moves.

Thanks a lot guys, the Unity community does not disappoint.

Cheers! :slight_smile:

@makeshiftwings I could but then I have to make an object pool, and I would have to update the position of every arrow to stay above my units.

The arrow/triangle would not exactly take up much memory so why would you need a pool. create all units with the object as a child and its position would automatically change when the units does No code required.

My units also rotate and scale, so I would need to have a script update them whichever way i decide to do it.
In the end I don’t think it matters too much what i choose to do now that i’ve scrapped my drawUnitSelections script.

When you make one object a child of another object, it inherits its position, rotation, and scale automatically.

I meant that my units scale and rotate every frame.

It automatically inherits the position, rotation, and scale of its parent when the parent’s values change. That’s what parent and child objects are for. If you make a sword a child of a character, the sword automatically moves with the characters as the character moves/rotates/scales.

Thanks, but I would like triangles the same size and distance over every unit (just like the drawUnitSelections script does). The arrows should stay the same distance above all units, not rotate with them or scale with them as they rotate or scale.

That forces me to update their position every frame. If the triangles were children of each unit, i would have to do some simple math rectifying their rotation and position relative to the unit every frame. Between these two choices the simpler one seems like simply updating each triangle’s position.

You could structure units as:

UnitRoot
– UnitBody

Where UnitRoot has nothing visible and doesn’t rotate/scale, only moves. Then you can attach things to the root or body, depending on the behavior you want.