How do I keep this function from overwriting its own reference?

I have one function that takes an FString as input, throws it into a random text block in my UMG widget, sets the overlay panel that text is in to visible, and returns a reference to the overlay panel. I then have a second function which just takes an overlay panel as an input, and sets it to hidden. By combining them with a relay node in the event, I effectively have a system that displays a bubble for an arbitrary period of time, then hides it again:

This works if bubbles appear slowly, but if numerous bubbles attempt to spawn one after the other, whenever SaySomething assigns new text to a bubble that’s already visible (and thus, waiting to be hidden), that bubble remains visible.

Is there a simple way I can prevent this behavior? Since a reference to the panel I want to show/hide is being passed each time text is assigned, I didn’t expect this to freeze a panel in the visible position to begin with, so at the very least I would really appreciate some help spotting where my mistake is that’s causing things to remain stuck with visibility set to true.

Hi,

in your function “Say something” create local variable and store value here, then return it’s value, in this case every call of this function will make own variable and return it’s value preventing override

p.s. don’t forget mark question as answered with little gray circle button under any answer (not comment, but whole answer) when problem solved, so anyone else later can have same question and may find solution faster, if you find solution on your own, don’t forget write it too

You mean like this, right? I’m afraid making the return a local variable instead of a direct object reference has no effect… making a bunch of calls to the event in a short period still jams some of the bubbles open.

you have a manager controlling all the widgets like puppets, but if you want the widgets to die after a while, they should keep track of their own lifetime.

After doing some research I found that apparently UMG can’t destroy widgets, but either way I’m probably better off collapsing, not destroying, since they have minimal overhead when disabled and I’d likely lose more performance from GC than I’d gain from wiping them out entirely.

The reason I’m managing the visibility from the event chain, and not inside the widget, is because when the system is more mature, the delay between appearing and disappearing will change based on the length of text, so it’s easiest to make my SaySomething function output a float that feeds the delay node.

I’m still baffled as to why activating this twice in quick succession keeps the first text block from being hidden, though- since the function that determines which block is hidden is local in scope to SaySomething, shouldn’t running that function twice result in two instances of the variable that both run through the delay node and get to HideUI?

when you call the function twice within a second, SaySomething is overwriting its output reference with the new bubble, so after the delay, it is only turning off the newest bubble. to process all of the bubbles that are in use, you would need to make an array of active bubbles, and remove the first element from that buffer after the delay.

but that still might cause problems if you remove elements at the same time.

i would recommend telling the widget what to say, and how long to say it (or let it calculate how long to say it), and pass the widget a reference to the HUD that spawned it, so when its time is up, it can tell the HUD to remove it, or it can mark itself as empty so a new message can reset it.

Hmm alright… if the widget is curating itself, where does that logic actually live, inside SaySomething itself? I should clarify, this isn’t multiple UserWidgets: this is a single UserWidget which contains five Overlays, each of which contains a text-image pair.

in this case you can do in your player controller:

  1. make variable to store widget’s reference, actually you can create widget from here on event “begin play”
  2. make structure to represent 1 item of assosiated array, in this structure you probably need 2 variables - float (when it become 0, Overlay should die) and any other that can hold reference to your Overlays
  3. make array of this structure
  4. when you need create speech bubble you can simply get current player controller anywhere and after creating Overlay just add to array of structs new item, set float value of struck to so many seconds as you need and put in second value of struck Overlay reference
  5. in tick event iterate over array of these strucks and extrack delti time (it’s uotput pin of this event) from each float dead time and then check - if any float goes below 0, then you can remove needed Overlay by holded reference and don’t forget remove this struct item from array as well! i don’t remember right function to remove item from array, but there should be one that shift element down, for example

your array like

  1. elem1 - 5.0,overlay1_ref
  2. elem2 - 0.1,overlay1_ref
  3. elem3 - 5.0,overlay1_ref

right function for removing would make next result

  1. elem1 - 4.9,overlay1_ref
  2. elem2 - 4.9,overlay1_ref

wrone one this

  1. elem1 - 5.0,overlay1_ref
  2. elem2 - 0.0,null value
  3. elem3 - 5.0,overlay1_ref

those “text-image pairs” can be separate widgets owned by the main widget, that way they can keep track of their own logic in their event graph.

Since UMG widgets can’t be destroyed, I’m assuming each sub-widget would set itself to collapsed, not destroy itself, but if that’s the case where would you put the logic which allows it to curate itself? I can’t put it in the constructor, because that will only fire once.

UMG widgets can be removed from parent, and they should get garbage collected eventually. try this:

i tested this by creating 10000 popup widgets, each containing a “lorem Ipsum” text that is 4500 words long. then using get all widgets of class, i counted how many existed, and it was about 3500, but it seems that using get all widgets of class causes them to not be garbage collected.

so if you create 50 widgets, then get all actors of class to count how many there are, then create 500 more widgets and wait a minute, get all widgets of class should only count 51.

That works completely- thank you very much for your patience, it took a while for this to sink in :slight_smile: