Random Without Replacement in a BP

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…

So, you want to spawn a sound at random locations..?

Spawning sounds at random locations is a useful technique (especially when combined with random variations within the sounds themselves) as it can help reduce any sense of repetition and help to bring an environment to life. This is the first of a short series of posts that deal with this topic and will cover a few of the techniques involved, starting with the ability to randomly choose locations

As with any technique, there are multiple ways of achieving the same thing… You could do this:

But then you’d have to set up a system to define your x/y/z min/max values to appropriate ranges so that the sounds played back within the correct area of your level.

A better way might be this, as you can define specific locations by placing actors at the various points within your area:

Or this, using AmbientSound actors placed within the level:

Either approach produces the same end result, but it depends whether you want to have your sounds appear to come from specific actors within your level or from ‘unseen’ empty AmbientSound actors that you’ve placed appropriately.

These methods work fine, and there are probably more variations on this theme, but the problem comes if you want to add more possible locations within your level. You’d have to modify your BP to accommodate these changes by adding in more actor references, and extending the Select node.

Instead we can make our controlling Blueprint dynamically find all of our locations and store them in an array. We can then use a similar method, as illustrated above, to generate random numbers and select from the contents of the array – if we’re cunning about how we do this, we only need to build one system and we can add/remove locations as much we want without having to make any changes.

Firstly we need to ‘find’ all of our locations.

The Get All Actors Of Class does exactly what you would expect – it finds all of the actors within a level of a specified class and generates an array containing all found references. You can use whatever type of actor you want for your sound locations (as discussed above), but for this method it does make a bit of sense to create your own custom actor class so that you can be sure that the Get All node only finds those actors you specifically want to use as location markers.

Creating your own actor class is pretty simple – within your Content Browser, use Add New – Blueprint Class.

Then you can choose to base your custom actor off any class you like – I’ve chosen to use AmbientSound as this means I could use it’s available functionality to change how the sound is played in the future if I want.

Once you’ve got your Get All node configured, you can easily create a variable to store your generated array, by right clicking the ‘Out Actors’ outlet and selecting ‘Promote to Variable’. It would be useful to know how many actors are stored within the array – so that we can generate an appropriate random number, so we use the Length node and create an int variable to store the output.

Because the BP finds all of the specific actors within our level, and creates the array for us, we can add and remove actors and not have to worry about modifying the BP – which is nice!

The next step is to create the system that will select one of the locations at random and then play the sound from that location.

We subtract ‘1’ from the length of the array, and use this as the maximum of our random integer range, as the references within the array are stored at indices that start at ‘0’. So the first slot is ‘0’, the second is ‘1’, and so on…

We then use the Get node to access the reference stored at our random index and store that as a variable – we do this to ensure that any future use of this randomly generated reference remains consistent (if we just used the output of the Get node, then the Set Sound node would produce one random reference, and the Play node would produce another – they will likely be different!).

We then simply set the sound to be played by the actor and start it playing.

If at this point, you’ve been building and are testing your system, you may well notice that sometimes a currently playing sound location is retriggered – this is the beauty of ‘random’; the same thing can happen twice in a row (or more…). Ideally we would check to see if the randomly chosen location is playing, and if so generate another random number and try again.

This is pretty simple:

We can use the IsPlaying variable from the Audio Component to control a Branch node (this is one of the reasons I chose to base my custom actor off the AmbientSound class). If the randomly chosen location is not currently playing (ie. False) then we set and play the sound. If the chosen location is playing (ie. True) we just call the PlaySound function again and restart the system.

That’s the basics of playing back sounds at random locations. There will likely be other ways, this is just the way I’ve found works for me.

There are a number of improvements we could make to the system, the biggest one being the ability to generate random numbers without repetition (similarly to how the Random node within a SoundCue works), so the next blog post will deal with that.

OSC Utility

So recently I’ve been working with some colleagues to produce some utilities for UE4 to create an electro-acoustic composition – there’ll more details about these in the near future… But suffice to say they involved spatialization of sounds, movement following pre-defined patterns and some serialism stuff.

As well as the various methods of playing back soundfiles, we also needed real time control / triggering of sounds using OSC data so that the project could be controlled by two performers using iPads. We used the excellent OSC Plugin created by Monsieurgustav and available here, and while it does work well and is easy to setup it didn’t quite offer the functionality that we needed – Namely the ability to save the OSC addresses used as control data, recall these between sessions and set up easily managed routing of the different incoming OSC data within the project.

So, I built something that did…

I produced a BP actor that can be dropped into the level and will sit there receiving any incoming OSC data and parsing it according to some user defined settings so that individual addresses can be used to control functions within the project.

The saving and recalling of OSC addresses was relatively simple and made use of the SaveGame class to create a data file that the OSC addresses could be written to (this is saved within the ‘Saved’ folder of your project). This is handled using the [Event BeginPlay] to check for an existing data file (one is created if not already in existence) and any saved data is recalled and stored in a temporary variable.

sshot-1

I added an OscReceiver component (part of the OSC plugin) to the BP actor so that it could receive OSC data.

sshot-3

If the actor is set to ‘Learn’ mode then the address of any incoming OSC data is stored in an array and saved – the addresses are checked against the contents of the array to ensure that there no repetitions.

sshot-4

If the actor is not set to ‘Learn’ mode then incoming OSC data causes an event dispatcher to be called so that the OSC data can be received in any BP within the project (eg. Level BP).

You can easily control systems within the project using individual OSC adresses through the use of a [Switch on Int] node – you can use the index of the current OSC address within the wider array of stored OSC addresses to control the [Switch on Int] node.

sshot-5

I’ve made the OSC Utility available here along with a copy of the OSC plugin, a demo project which illustrates how the actor functions and a .pdf detailing the systems in use.

3rd Person Camera – Audio Listener Position

When you create a 3rd person game in UE4, the Audio Listener is set by default to the position of the camera, which works fine for some scenarios but not for others. It can cause problems depending on the position of the camera relative to the player character (eg. hearing things that the character cannot actually see).
I was asked about this by one of our Masters students who needed to be able to set the position of the Audio Listener to somewhere in-between the camera and the player character in order to solve just this kind of problem.

This is my solution – it does not need to be in a separate BP, but by doing so it makes it easy to distribute and means it can simply by dropped into a project.

Within the BP, the Audio Listener is set to the position of the actor, which in turn has it’s position constantly updated so that it is always relative to both the player character and the player camera.

sshot-1

On every frame update the location of the player camera and character are obtained as well as the forward vector of the camera and it’s rotation. These positions are used to calculate the position of the actor.

The forward vector of the camera tells us the direction the camera is facing.
The distance between the player camera and the character is obtained and is scaled by a user-definable variable to determine how far along a line between the camera and character the actor should be placed.
This value is then used to scale the forward vector of the camera to move the actor along the axis of the camera towards the player character.

Finally I added in a [VInterp To] node to apply some level of interpolation on the actor’s location so that there is some degree of ‘inertia’ on the listener position’s movements – this smooths out any jumpy movements introduced by the camera.

The actor’s properties allow you to set:
–  The Listener Distance (where 0 = at the position of the player character, and 1 = at the position of the player camera)
– The Interp Speed (where 100 = very fast movement / no inertia, and 1 = very slow movement / high degree of inertia)

sshot-2

You can toggle the actor’s Hidden in Game state using the L key (obviously you can change this key event if you wish) so that you can visualize the listener position if needs be.

The actor can be downloaded from here: click me

If you find this useful and have any thoughts / suggestions / ideas for developing it further so that it can be of more use, I’d be interesting in hearing from you…

 

Visualising LPF Radii

So, this idea came about after a question on gameaudio.slack about whether there was a console command to enable debugging of LPF radii similar to that for volume attenuation radii using the ‘stat sounds -debug’ command.
Unfortunately there isn’t!

But, it got me thinking… it can’t be that hard to knock up a quick and dirty solution…
turns out it isn’t! So I thought I’d make the solution available in case anyone else finds it useful.

I created a placeable actor, using BluePrints, that can dropped into a map and then when a specific key is pressed it draws the LPF min and max radii for every AmbientSound within the level.
Here’s a screenshot of it doing it’s stuff ingame:

visualise_lpf_radii_ingame_sshot

The actual BP system is pretty simple…
When the key is pressed an array containing all of the AmbientSounds within the level is created. This is then looped through, and for each actor within the array the actor location, LPF radius min and LPF radius max are obtained. These values are then used to draw some debug spheres within the world.
Here’s a screenshot of the actor BP:

visualise_lpf_radii_actorbp_sshot
(The connection to the input of the [Get All Actors of Class] node is coming from a keypress event – it wouldn’t fit on the screen!)

As you can see, this is a very simple system!

Obviously this could just as easily be done within the Level BP, but making an actor made it easy to distribute the solution.

The actor can be downloaded from here: click me

If you find this useful and have any thoughts / suggestions / ideas for developing it further so that it can be of more use, I’d be interesting in hearing from you…

Musical Shooter – Different Rhythms

In order to make the differences between the different firing rhythms and enemies more obvious I’ve changed the timings of the weapon and pulsing of the enemies. These are now at 1/4, 1/8 & 1/16 beats. This has helped with the feel of the game, but has highlighted a problem with the windowing system I was using to ensure the enemies dies on a musical interval.

Because the firing rates are now slower it can often take a long time for all the elements of the windowing system to align. This can make it feel like you’re having to shoot some enemies a lot more than others.
A possible solution to this would be to visually flag the enemy as dying as soon as the damage threshold has been reached (not quite sure how this would work yet…) and then ‘kill’ it on the interval.

I’ve also tweaked the appearance of the enemies slightly and things are looking a bit nicer.

Here’s a vid:

 

I cut the ‘action’ short as the windowing problem means the game can sometimes take a while to complete.

Musical Shooter – some more changes

I”ve been working on the mechanics of the game a bit more over the weekend.

I’ve set up different classes of the enemies, each with different colours, sizes and speeds. Each class responds to a different rhythm of shooting (which can be scrolled through using the right shoulder button of the gamepad). As the player changes firing rhythms, they change colour to match the mode – this corresponds to the colour of the enemies. In order to provide a bit info/FB to the player the enemies pulse in the tempo of the firing rhythm.

I’ve also setup the firing modes to deplete their ammo count (which is displayed in the top right of the screen). When each firing mode is out of ammo a pickup appears (coloured to match – obviously!) which returns the ammo for that mode back to full.

Here’s a video of how it looks now:

 

Now the mechanics are getting there I need to make it look a bit nicer and sort the sounds out. I also need to check how the game handles different gamepads.
I’ll also be trying to streamline the code to make it as effecient as possible and also to remedy the fact that as I’ve been tweaking things recently and adding new features I’ve been a bit slack in using ‘proper’ coding practices.

Musical Shooter – A Few Tweaks

As the various features within the game get put in, I’m finding myself playing it more and looking for minor tweaks that can be made. This post will describe a few of these that I’ve made recently as well as, more importantly, fixing the bullet removal issues I’ve been having.

Prior to this update, if I enabled the removal of bullets when the collide with an enemy then there it seemed the system was getting stuck at the point where the bullet was removed and if you kept firing in the same direction no bullet would get past the ‘removal location’, until the player moves. I spent a while scouring the code for references for the player location being used in the removal of the bullets, but there was none… It turns out I was just calling the remove function at the wrong point in the code! We now have ‘proper’ bullet behaviour.

I’ve also been playing around with some of the functions available in the Minim audio library I’m using to handle the playing of the sounds and music. I’ve implemented a basic low pass filter whose cutoff frequency is lowered when the player collides with an enemy and is suffering damage – the idea being that this will provide some audio feedback to the player. I didn’t want to use a sound effect as things are starting to get quite cluttered at times (audio-wise).

The final major tweak I’ve done, is to implement a ‘windowing’ system on the code that checks to see if the enemy has been destroyed. Prior to this, the code was working like this:
if(damage > 15 * dScale && frameCount % 16 == 0 && impactCheck == true)
So, the damage had to be above the threshold, and the frameCount had to be an exact beat, and there had to be an impact. The impact check was put in to ensure that the enemy wouldn’t destroy itself when you’re not actually shooting it as this felt a bit odd.
The problem is that the ‘perfect’ frame count and an impact don’t always align and so it could sometimes take a while to kill a specific enemy which again, didn’t feel right as you were playing.
The windowing code looks like this:
if(impactCheck && frameCount % 4 == 0 || frameCount % 4 == 1 || frameCount % 4 == 3) { if(damage > damageMax * dScale && frameCount % 16 == 0) {
The 2 if statements are nested so the first one is the window and checks the remainder of the modulo operation to see if the frame is 1 either side of the ‘perfect’ frame. If this is true, then the 2nd if statement checks for damage and an impact.
The new system has made the gameplay feel more like it should with enemies dying more reliably, although it’s not quite perfect and needs some more finessing.

I’ve also added in a sound for when the enemy takes damage. Rather than just triggering this sound for every damage instance, I’m checking to ensure that the damage sound only plays at a ‘musical point’. Again, this uses a similar windowing system as the enemy death system and so is not quite perfect yet…

Finally, I’ve implemented a basic game start and end system.

Anyways, here’s a video of how things are looking at this point:

 

Next steps = Creating some kind of scoring system; Looking into reading/writing to files to store the player’s results; Different weapon firing rhythms.

Musical Shooter – Better Aiming

I’ve made a few tweaks to the game so I thought I’d post up what I’ve done with a new video.

I’ve refined the aiming so that instead of moving the player sprite and the target independently and then calculating the angle between them, the aiming system now uses the 2nd stick to create an angle relative to the player sprite which is used as the trajectory for the bullet. Its now much easier to change the direction of shooting and also easier to play as the behaviour is easier to get your head round.
A by-product of this was that if you’re not actually aiming with the 2nd stick (ie. its position is central) the bullet system was producing static bullets with no trajectory/speed. So, the system now only fires when you’re aiming – this worked out quite well as its more obvious when the firing sound comes in and produces a bit more variation in the whole audio output.

I’ve also tried out a different effect to produce a trail that follows the player sprite around – essentially its a series of reducing circles produced by an array that uses the previous locations of the player sprite. Its a bit simpler than the particle system in use previously and I think it fits the overall general aesthetic of the game at this point a little better.

The final tweak is that the size of the enemy also determines how much damage it takes to destroy. The plan is to, at some point, produce different classes of enemies with different movement behaviours and maybe some that shoot back at the player…

I tried removing bullets when they impact with an enemy, but this caused a few problems with some of the collision systems so I’ve taken it back out for now.
I also added in a sound for when the enemy receives damage, but because (at the moment) bullets aren’t removed there was often too much damage going on and the playback of multiple damage samples simultaneously was causing clipping and other volume related problems. This is a shame as it sounds pretty good when it was working properly. Once the bullets issue has been sorted I’ll put the sounds back in again.

Here’s a video of things at this point:

Musical Shooter – Enemies Testing

I spent some time yesterday implementing a class of enemies so that I can spawn a number of them each with random sizes, start poistion, direction and speed. Once the basic behaviours were coded it was then a case of collision checking for:
– the edges of the screen so that they bounce back
– the bullets
– the player sprite

To check for collisions with the edge of the screen is pretty straightforward – you simply compare the enemy’s x,y location with either 0 or the width and height properties to see if they are outside of these bounds. If they are, just invert the velocity property which controls the direction of travel.

To check for bullets is a little trickier as you need to check every enemy against every bullet that is currently being generated. The bullets are created within an array so we can step through each element in the array and compare their respective locations to see if the distance between them falls below a defined threshold. If there is a collision, I’m drawing an ellipse over the enemy location to provide a visual indication to the player.
For every collision, the enemy’s damage variable is incremented and when it reaches a threshold the enemy can be destroyed and a sound is played- this is actually constrained to only occur on a musical interval:

if(damage > 25 && frameCount % 32 == 0 && impactCheck == true)

the impactCheck variable is being used so that the enemy is only destroyed if the player is actually shooting it as without this it felt a little odd.
When the enemy is destroyed the totalDead variable is incremented and when all the enemies have been destroyed, the game is finished.

To check for collisions with the player sprite is pretty straightforward, you just need to take the enemy diameter and player sprite diameter into account. If there is a collision, I’m drawing an ellipse over the player sprite to provide a visual indication.
If there is a collision, the playerHealth variable is reduced, this is used to determine the size of the ‘health’ bar in the top left of the screen – there’s nothing else going on yet, I was just seeing what it would look like.

Here’s a video of what I’ve got so far:

 

The next things on the list are:
– to destroy bullets on collision with an enemy
– to refine the aiming mechanism as its quite clumsy at the moment