Orbiting Sound Actors

This is a little system I put together to orbit sound nodes around the player. I was thinking about ways to place ambient sound sources in order to achieve a wide and randomised spread of ambient sound.

The basic idea is to use trigonometry to move AmbientSoundMovable actors in elliptical orbits at different speeds and directions, and for these actors to play back soundcues containing arrays of randomized ambient sounds. Potential uses for this are survival horror (where you might want to increase tension using creepy off-screen sounds that originate from unexpected sources), open world adventure (e.g. a forest scenario filled with small animal movements, leaves dropping, branches brushing against each other etc.). And indeed any scenario that requires 360 degrees of moving sound.

First off, you need to gather your sounds. I’ve used 3 ambient sounds for this demo, which takes place in a dark cavernous space: little water droplets, monster sounds and critter movements and sounds. I set up the soundcues in roughly the same way for each – here’s how I did the monsters:

There’s a looping node in the cue so that the sounds play constantly, and I’ve added some delay nodes to put space between each sound. For the monsters, there’s a random delay of 5-10 seconds between each sound playing. The critters trigger more frequently, and the water droplets most frequently. (The mixer’s just there to tweak the levels on some of the sounds).

Once you’ve got your soundcues set up, add them to your level somewhere as AmbientSoundMovable actors so you can reference them in Kismet. It doesn’t matter where you put them, in my demo I’ve placed them off the edge of my map, out of earshot since I’m not setting up any stop/start sequences for now, and the sounds will start playing on level load.

Once the soundcues are set up and the actors are in the level, it’s time to look at the Kismet. The principle is fairly straightforward, I’m using the Set Actor Location node to place each sound actor at a point on the circumference of a circle, where the player is the centrepoint. I’m looping this routine and each loop increments the angle between the player and the sound actors by a small amount, which effectively moves them round the player like stop-frame animation.

The maths to find points x and y on the circumference of the circle (for placing the sound actors) is governed by this parametric equation:

x = cx + r \* cos(a)
y = cy + r \* sin(a)

Where cx and cy are the origin (player x,y co-ords in this case) and ‘a’ is the angle between player and sound actor.

There aren’t any trigonometric functions exposed in Kismet, so I wrote some custom actions which you can download here. Put them in the /development/src/engine/classes directory in your UDK installation and they should show up in the Math section of your Kismet actions.

To get cx and cy, use the GetActorLocation node to get the player location as x and y co-ordinates. You can’t get the location of the player itself, so you need to make a very small DynamicTriggerVolume using the builder brush and place it over the PlayerStart actor in your level. You can then attach the DynamicTriggerVolume to the player in Kismet, and get its location using GetActorLocation, to effectively get the player location.

‘r’ will determine the radius of each circle – ie. the distance between player and sounds.

‘a’ will determine the rate at which the actors move round the player – big values = bigger angles = faster movement.

Here’s a screen grab of the Kismet sequence:

You can download it as text here. Just paste it into Kismet.

You can watch a video of the system in action here. The first half of the clip is a basic demo showing where the sound actors are when in orbit, (without sound) the second half shows a potential use for the system (with sound).

Thanks for reading, post in the comments if you have any questions or tutorial requests!


Leave a Reply

Your email address will not be published. Required fields are marked *