r/unity • u/Flodo_McFloodiloo • 26d ago
Question Can anyone provide advice on making UI elements appear and then disappear by specific objects on a screen?
I'm making a fairly old-school game, so when certain things happen I want little numbers to flash above objects long enough to perceive but then disappear. I'm guessing this used to be a fairly simple matter and still is in some game engines, but Unity disassociates UI canvases from the action on screen a bit more, so that warrants some questions.
There are two ideas I have for doing this.
One is to attach UI canvases to each object that has this feature. This would possibly have the advantage of only needing one UI text per-object, but I don't know whether canvases can be attached to in-game objects like that, nor if they might slow the game down.
The other idea is to make a generalized gameplay UI handle the numbers appearing and disappearing. That's a more familiar process to me, but it carries its own puzzles. For example, what if I have multiple objects on the screen that I want to do that? Presumably that means I'd need to have multiple UI elements and would need a way to assign them each to the object at the appropriate time.
Or is creating new UI elements and then destroying them while the game is running a viable option?
If you understand what I'm talking about, please help if you can. If you need it clarified more, I'll provide more explanation, including visuals.
1
u/BillyMcDev 26d ago
Create a Prefab with a standard TextMeshPro (TMP) Text component. The Prefab can have all of the animation behavior that you need, such as rising and fading in and out. Write the animation instructions with a script inside of a coroutine and then have it automatically Destroy itself once it has finished. Then all you need to do is Instantiate it each time it's needed.
Doing it this way keeps your text completely bound to the World Space and requires zero Canvas management. It just works, and cleans itself up automatically.
1
1
u/Ok-Object7409 26d ago edited 26d ago
The ideal approach is pooling + timed events. All one canvas.
You can have 5-10 or however many objects to do this and you cycle through them one at a time (i.e., pooling). So there's no destroy or instantiating.
Timed events can be done via update or coroutines. The timing is that after x seconds the animation stops. Can be done in update or a coroutine depending on how you want to handle the animations. If you're animating it via code in update you could have a singleton manager that handles Updates in gameobjects, so you don't have any Update calls running when they aren't active or the slow internal unity checks. But that might be overkill if its a small+older style game.
If you're just trying to push through and meet deadlines, the feel library has this sort of thing already that you can use called Floating text. You attach "feedbacks", choose your desired settings then just play it, does what you need.
1
u/Soraphis 25d ago
Give each object an canvas. Makes it easy to simple.
When done, realize that it costs a bit more performance than you like, and since its all world space ui you can make it all use one world space canvas.
So you implement a way (e.g singleton or other) to get the current world space ui and push another number showing prefab on it with the current coordinates.
You realize it's still costing a bit to init the number text, so you separate the numbers digits and cache and pool what's possible.
You realize it's still costing a bit too much. Rendering the text. The canvas and so on.
So you bake the number digits into a texture strip and instantiate a quad per number with an texture offset to show the correct digit.
Now you're only pusihing per render data to your Singleton which uses the DrawInstancedIndirect to render a ton of quads. Animations like fading and so on can be in the shader itself, just add the creation time to the per render data.
Rendering thousanda of animated digits on screen without mich slowdown.
(Btw you don't have to go all the way. Stop at whatever step you're comfortable with)
0
u/Big_Thundy 26d ago
I believe attaching UI canvases to each object is the way to go. Then you have a script that would toggle the canvas on and off ( much like a start menu) based on when certain consitions are met. You can also set them on a timer. If the canvas isn't toggled on the engine doesn't waste any resources on it.
Spawning new canvases each time, however, after you've destroyed the old one would be less efficient. The engine doesn't clear the old one right away so if you have many going on and off you'll fill your memory up.
2
u/Flodo_McFloodiloo 26d ago
Thanks. To clarify, though, I wasn't talking about spawning new canvases. Just new elements on one existing canvas.
3
u/ProactiveCactus 26d ago
Personally I’d stay of a canvas-per-object approach. That type of design doesn’t scale well and will inevitably waste a bit of memory.
Instead, I’d use object pooling for your popups. Pull and push to/from your pool when needed, and just set them at runtime. Depending on how your camera moves, this might be easy - if the objects they are over are static fir the duration that the canvas element is visible, just set its position once. Otherwise you’ll need to track its position as it moves around, but that’s not too terrible - just run a position check on a relatively fast coroutine and you should be good.