Is there a way to optimize widget components for floating damage numbers?

I’ve finally got all this implemented and testing it against a large group of AI for AOE damage it performs horrendously. As in 100 fps stable tanking to 40 fps with floating damage numbers using widget components. I thought it was the animations causing this so turned off the render opacity and transform animations and still performs just as poorly.

Is there a better way to be doing floating damage numbers that doesn’t perform so poorly?

  • In what way are you making the numbers appear? ()
  • Is the source of the numbers 1 widget?
  • is it in screen space or world space?

Here is a really good talk on umg optimizations from the team at Rocksteady

I add widget components on damage received. So if they get hit 3 times that’s 3 widgets.

No, each hit on each enemy is a new widget component.

Screen.

Try using 1 widget and perhaps spawning the numbers in screen space. That way no matter how many numbers pop up it will only have 1 canvas and only x images depending on damage numbers. Logic can also be narrowed down to 1 class.

I have no idea how to do that. I need the numbers to individually float up and fade away as well. I also need them to remain where they spawned and not move with my character, which was an issue I ran into attaching widgets to viewport instead of using widget components.

I’ll see if I can do a prototype. I’ll post a project if I have the time today.

I think I might understand. So I’d attach 1 widget component and in that widget have an event to add text nodes, play the animation, and detach them when animation completes. Then in my actor on damage I’d call that widget event. Is that kinda the base concept there?

Pretty much. You will also have to get the passed actor’s world position and convert it to screen position to get it to appear where where character was when it was damaged.

Also I’d just add the widget to the screen and not make it follow a specific character.

I tried adding it to the screen, but when my character moves so do the damage numbers. I can spawn them in the correct location just fine doing this, but the problem is them moving with my screen. I’m not sure how to stop them from doing that. As for the widget component usage it’s just a component on my AI actors.

Ok, switched it to a single static widget component on each AI actor. I then added an event in the widget component that calls and event on the widget itself. The event in the widget adds a new child to a named widget node. I haven’t added the animation back in, but success! I have ZERO FPS impact doing it this way. Even hitting 60 enemies at once causes no problem.

I really appreciate your help! You got me on the right track for a much better solution!

Edit: Using a Overlay instead so they stack. Now just need to figure out how to animate the added child widgets.

Just give the child widget an animation (create one in the “number” widget) and in it’s construct call play animation and pass in it’s fade animation, after that add a delay node with the length of the animation and add a remove from parent node (should clean up)

Edit: I made a prototype with just 1 widget for all actors no matter the amount

Right click on actors to spawn damage numbers

Ah, I see. I was creating the text widget dynamically. Will create a separate widget for it and that’ll solve it like what you’re doing. I don’t have any issues with having a widget component on each AI though as that doesn’t seam to incur any performance cost (it’s not ticking or anything anyway).

Well do a comparison and see which of the positioning vs component methods works best :slight_smile:

Both seam to have the same bottleneck. The animation. If I hit for example 30 enemies at once the 30 damage numbers animating tanks performance. If they’re not animated it performs fine though with minimal drop (1-5 FPS) compared to animated (40 FPS).

Only optimization that i could think of is maybe pooling the widgets and reusing them instead of spawning/ despawning them.
Maybe a particle solution could also work?

Yeah, was thinking a Niagara based solution, but seams pretty complicated. Below is a tutorial for this.

I believe Lyra demo uses Niagara based damage number solution as well. Will give it a shot when I have time as this widget solution is a no-go. Just too much performance loss for my type of game, but would be perfectly fine if you weren’t fighting 30+ enemies at once lol.

Out of curiosity have you tried launching the game in dx 11 mode?

When the RHI is set to 12 it seems to tank performance for some reason on many widgets (could be something unoptimized in 5.1).
Getting locked 60 fps on dx 11.

I have not.

I’m on 5.0.

I was able to optimize the animation a bit more though. Instead of having the individual damage numbers animate I put the animation on the damage number container. That cut the FPS loss in half. I setup a loop that checks if the container has children, if it does play animation, when animation finishes remove all children, then retry loop. If a child is added it will also retry the loop if not looping. This gives all the removal and animation control to the container.

Also check if the number animation has default keyframes for other areas like
rotation
position X
scale
shear
etc.
delete all keyframes where there are no changes (including first). It should spare some calculations.

Letting the container control the animation seams to been the solution when using widgets. Looks to be performing well enough. Will explore doing this with Niagara in the coming weeks and see if that’s a better solution, but it very likely is just given it’ll be entirely pushed onto the GPU instead of CPU.