In the previous post we looked at how we can play back sounds from random locations as a way of improving the general ambience within an area.
This post will look at a way we can improve things further by allowing us to do ‘random without replacement’ so that the random locations chosen for playback aren’t repeated. This functionality already exists within SoundCues using the Random node.
Unfortunately, there is no standard node for doing this in a BP – so we’re going to have to build it ourselves…
The resulting system is a little large, in terms of BP nodes, so I’m going to create a new Macro and build within there – this will help to keep my BPs tidy and easily ‘readable’, it will also mean the new functionality can be reused across projects easily.
We will cover the creation of the random without replacement macro, but you can download the macro here if you want.
You can create a new macro directly from within a BP using the Add Macro option.
However, this macro would then only be accessible within that BP. If you want to create a macro that you can use across your project, and even share with other projects then you need to create a Macro Library within the Content Browser. Use the Add New – Blueprints – Blueprint Macro Library option.
You’ll then be asked to choose the ‘Parent Class’ for your macro – the advice from Epic is to use ‘Actor’ as this will enable you to do more in terms of accessing variables and functions.
Give your new macro library asset a name, and then open it for editing.
The first step is define the inputs and outputs of your macro. Select the Inputs node, and in the Details window create the following Inputs and Outputs:
The Exec In triggers the macro’s functionality.
The Input Array is the set of items that we want to randomly choose from. We’re using the Wildcard variable type so that the macro isn’t tied to a specific type of asset – the wildcard type changes to match whatever is connected to it.
The Rand Without Replace boolean will allow us to choose whether we want to turn the ‘without replacement’ functionality on or off.
The Exec Out is triggered after the macro has completed it’s task.
The Array Item output passes the randomly selected item.
The first step is generate a random number:
We get the Length of the input array, subtract ‘1’ from it (like we did in the previous blog post) and then use this to set the maximum of our random range – remember, array items are indexed starting with a value ‘0’, so the possible range needs to be 1 less than the length.
We’re using a Local Integer to store this random value, so that we can use it further down the chain.
Next we need to check the status of our ‘Rand Without Replace’ boolean:
And then set up what will happen for each state.
If the bool is set to ‘False’, it’s pretty simple – just use the randomly generated value to Get the appropriate item from the Input Array and pass it to the Output:
The system for ‘True’ is a bit more complex, so we’ll build it in stages…
First, create this:
We’ve create a Local Array of Integers to store the randomly generated value, and we check this array to see if it Contains the current random value already, if it does we simply generate another random value and check again (the Reroute node is useful when you want to loop back on yourself, or to help keep connections readable). If the random value is not present within the local array then we Add it for the next pass through.
Now extend to this:
We need to know when we’ve generated every possible value so that we can reset our system and go back through the whole Input Array again. So we compare the Length of the local array with that of the Input Array and if they are equal to each other (==) then we Clear the local array to empty it and start again. If the two lengths are not equal then there are still some values left and we can go straight to the output. At the output (like we did earlier) we simply Get the item from the Input Array and pass it out.
Now you can Save your macro, and access it from any BP within your project.
Here I’ve incorporated the macro into the random sound location system from the previous blog post.
By passing it out array of sound playback locations we can randomly select one every time we call the function but be sure that we won’t get any repetition of locations until the array has been exhausted.
Next time, we’ll look at a way of extending our random system further by incorporating the option to determine random weightings for each item in the input array…