I’m trying to make the game randomly pick one from five elements inside a Enum list. Then when the event is fired again, it will check if that element was already picked in previous attempt.
If the element was picked, it would try again, a continue until it finds one it hasn’t picked yet.
This is what I tried.
This is inside a widget blueprint.
On launch, it would randomly pick an Enemy Element from the Enum list. Then check the Contains if EnemyElementUsed array has the same value as Enemy Element. The array is empty by default. If False, it would add the to the EnemyElementUsed array.
On second launch, it sets a new random element, checks the Contain. Now if what was added from the previous launch matches the EnemyElementUsed array, it’s supposed to loop.
But it’s not really working out.
Some other notes, if it helps error checking:
The game compares Enemy and Player Elements using the same Enum list, but from different blueprints and Variable set ups. This hasn’t caused any changes into player selected element, but I don’t know if it plays a role.
I’m trying to make the game randomly
pick one from five elements inside a
Enum list. Then when the event is
fired again, it will check if that
element was already picked in previous
attempt.
If the element was picked, it would try again, a continue until it finds one it hasn’t picked yet.
Depending on how complex the final system is supposed to be, I’d lean towards the following solution as it’s not prone to indexing errors and there’s no need for any iteration or looping whatsoever:
create an All Enums array
pick one element and add it to the Final Array
remove the picked element from All Enums
rinse and repeat
That’s pretty much it, it’s like having 2 buckets and pouring contents from one into another.
Some other elements that may be useful here, again depends how deep the rabbit hole goes:
Add Unique node: it automatically checks whether the array already contains the value and does not add it if True, and it’s kind enough to return a bool
Sets: the keys on the list must be unique so it’s a perfect container for what you’re doing
I added a Set Enumerator, since I needed the reference.
As far as I understood it. It looks like I’m trying to check if the EnemyElementList is not 0. And if True, it would pick a random index, and add it to the UsedElement Enum Array, then remove that index from EnemyElementList.
I have also set that index as EnemyElement Enum, which seems to work just fine, during testing.
It should work in theory, but it does’t look like it even removed the index to begin with.
Removing index means taking it out of the list, making it impossible to pick it again from that list, yes?
What I didn’t quite understand was the part of adding an element to the FinalArray, and removing it from EnemyElementList. Wouldn’t that ensure that one element would never be picked on the first turn?
How does your Enemy Element List array look like? It has to have unique items, have a look at my pic, the array is fully visible there.
Also, where you Print, it does not really show you that it has been used, it just shows that you’ve emptied the array and there’s nothing more to add. Not important here but you may need this info.
I gave it another go and the script I posted works flawlessly. Used AddUnique instead and added an element to the FinalArray just to replicate your workflow.
What is the duplicate that you’re seeing?
Here’s a log; 9 iterations and the final array contains 9 elements, all unique, and the initial element 0 is also accounted for. Each iteration adds something unique at the end.
Say, on turn 1, the game picks Fire
element. The next turn, the event is
fired again, Fire element is disabled
until I restart the game.
So it’s even much simpler then:
Check if the All Enums array Contains what you’re looking for, if it does, remove it. Next time you check with Contains, it either will have it (has not been used) or will not have it (has been used)
Ah yes, this works quite simply. And I also now understand why my previous attempts weren’t working.
As mentioned, the code is inside a widget with “Yes” prompt. It looks like every time I hide the widget and recalls it, the array is resets, and the list is filled again. So it would always be able to pick used elements.
Yup, this will create a brand new widget and cause a memory leak, too: you create an object, hide it, then you create another one, hide it, then another… You get the idea.
These are separate instances of the widget, each with their own variables and functionality. Since you want yours to hold and handle persistent data, you need to use the same widget again.
Instead, right click the the Return Value of the Create Widget node and promote it to variable. This is your widget reference. Next time you want to do something with a widget, use its reference. You can even automate widget creation like so:
If you run this for the first time, the reference is Invalid, so it will create a new widget, fill the reference, and add the widget to the viewport. If you run it again, the reference IS Valid so you can show / hide the widget it points at.
This method is useful when you switch levels (which wipes the widgets) and you do not always want to remember to manually recreate all widgets.
To put it it simply, it’s a system that removes objects from memory when they are no longer in use. It’s mostly fully automatic and you generally do not need to do anything about it; for example - when you call Destroy on the object. The memory it used to occupy will be (eventually) freed up.
You were adding widgets and hiding them without referencing; when you created another new widget, the old one was already being eaten by the GC (best case scenario) since it had no valid reference. Technically, that’s a good thing! But you were unable to access the old widget anymore.