Asteroid clone in less than 100 events

4 - Audio System

Audio

..° The user can choose if he wants sounds or not (turn it on/off)

..° Music in the background, changing each wave

..° Sounds on some actions (asteroid hit, asteroid destroyed, asteroid in collision with ship, wave end, ship movement, the player presses "return" in the "menus")

The audio system is spread accross the project.

It heavily relies on the "Audio" plugin. (be sure to read the manual entry, as well as the entry about sound and music. You can also find elements in the how do I FAQ under the section "Audio")

This kind of plugin (like Keyboard) is automaticly available in the whole project.

The sounds used in the project are "stocked" in the "Audio" and "Music" folders in the "Project bar".

Be sure to check "Adding sound - A beginner's guide" to learn how to add sounds and musics in C2 that can be used with the "Audio" object.

Remember that sounds can be preloaded and should be small/quick files. They are downloaded like sprites.

Background musics are streamed from where your project is hosted and must be imported in the music folder.

..° The user can choose if he wants sounds or not (turn it on/off)

This is achieved by a "simple" trick.

A global variable "Sound" (in "esScore") is either of value 0 or 1.

When it is 1 it means that sound/music is on, when it is 0 music/sound is off.

And so, anywhere in the code that an audio action is needed, you might already have noticed a condition "System: Sound = 1" is used (often as sub event).

For example, in "esGame" event 4. When the player presses on the "UP" key and that the global variable "Sound" is equal to 1, a sound is played.

Moreover, in this very example, the condition "System: Trigger once" allows to play the sound only one time, and not every tick that the key is down (which would result in multiple samples being played on top of each other and ultimately a saturating cacophony).

The switching between sound on/off is done in the Score layout, event 15 in "esScore".

The player presses "S" and either the sound is turned to on (if the global variable "Sound" was 0) or off (if "Sound" was 1).

As in the previous systems, sub events 16 and 17 are tested when "S" is being pressed (pressed mean that the "S" key was pushed down and then released).

Event 16 testes if the global variable "Sound" is equal to 0. If it is, it means that the player wants to turn sound on.

Let's look at the actions that do this :

    Audio: Play "UI1" not looping (tag "UI")

To notify the player that sound is turned on, this action plays a sound. The sound's name is "UI1".

Notice the sound here doesn't loop as it is just a "one shoot" sound (it needs to be played on the player's input, but no longer).

Since the top event is a trigger "on key pressed", the current sub event will only execute once and so only one "instance" of the sound will be played.

I gave a tag here, but I don't really use it in the project.

    Audio: Play "MattOglesby - 2" looping (tag "BackgroundMusic")

This action is to play the background music. For the "Splash" and "Score" layouts, only this "MattOglesby - 2" song is played.

The music piece is set to be looping (as it is background music going on and on).

The fact of tagging the music here will allow to stop the song whenever needed (more on this later). The tag would also allow to control the volume for the sound, but in this project I didn't handled the volume as the sounds/musics are nicely produced and don't make the speakers saturate when played along.

    System: Set "Sound" to 1

As the player wants to turn sound on, this is the moment to change the value of this global variable.

    txtSound: Set to "(S)ound: On"

The text object "txtSound" is there to give some feedback to the user and also indicate that pressing the key "S" allows to switch the sound on or off.

    Local Storage: Set item "AsteroidSound" to 1

As with the scores, the status of the sound (is it on or off) is to be saved in the Local Storage and loaded on "initialisation" of the game in the "Splash" layout.

    Audio: Preload "NewAchievement1"
    Audio: Preload "SFX1"
    Audio: Preload "Lazer Fire 1"
    Audio: Preload "Explosion 3"

The "Preload" action downloads the sound files. Those sound files are used in the "Game" layout, so preloading them here allow th help make sure the files will already be downloaded when played and so will prevent delay between the "Play" action and the moment the sound actually does play.

Event 17 is a "Else" condition. So it will execute if "Sound" is equal to 1, so that the player wants to turn the sound off.

    Audio: Stop "BackgroundMusic"

This action stops the sound being played using the tag "BackgroundMusic".

The rest of the actions is like in the previous event, except the values are set to reflect that the sound is turned off.

I was talking earlier about the "initialisation" of the game.

Let's look back at event 3 in "esSplash", the event in which stored values in the Local Storage are loaded.

It's kind of the "player's preferences" for the game.

    Event 5 - Local Storage: Set "Sound" to LocalStorage.ItemValue

The value stored in the Local Storage key "AsteroidSound" is set to the global variable "Sound".

This is why there's a need on "sound switch" to save the value of the Sound global variable.

That's also why in event 2 in "esSplash", where the default values for the score are set, a default value for the sound is also set. (and by default, the sound is playing)

..° Music in the background, changing each wave

The change of music for each wave happens in the Wave system.

Let's go back to event 27 and 29 in the group "WaveSystem" in "esGame".

Event 27 happens once all "Asteroid" have been destroyed.

    System: Sound = 1

Having a sub event testing that the value of the global variable "Sound" is 1 (meaning that sound is on).

Any time there's a need in the project for some audio action, it is done in a sub event testing this value.

    System: Trigger once

As the top event (event 26) is not a trigger and can be true several ticks in a row, this condition allows to make sure that the actions will only be executed once.

As for the actions:

    Audio: Stop "BackgroundMusic"

This action stops the sound being played using the tag "BackgroundMusic".

I just wanted the music to be stopped to clearly notify the player that the state of the game has changed since he completed the wave.

    Audio: Play "NewAchievement1" not looping (tag "EndWave")

This action plays the audio sound that notifies the player that he's completed the current wave.

Event 29 works in the same fashion, testing the value of the global variable "Sound" and executing the action only when the sound is turned on.

As seen earlier, the "UI1" sound is played (this sound is there on player's action in the "menus" as well as in between the waves ingame).

The last action of the event is a bit specific. It is the "Audio: Play (by name)" action, which allows to name the file to be played as a string, and thus allows to concatenate the string with variables and expressions.

    Audio: Play "MattOglseby - " & floor(random(0,3)) looping from "Music" (tag "BackgroundMusic")

The "Play (by name)" action takes several parameters: the name of the file (as a text field in which you can add variables and expressions), the folder the file is supposed to be in (either "Sounds" or "Music"; here it is the "Music" folder) and a tag, as the "regular" "Play" action.

The tag here is still "BackgroundMusic", so the file can be stopped at the next wave's end.

The music files in this project are named "MattOglesby - X" where X is a number from 0 to 2.

The use of the expressions " & floor(random(0,3))" allows to concatenate (add to the string) a random number between 0 and 2 to the string "MattOglesby - " (notice the spaces).

This allows to play a random song each wave, in the limits of the available songs.

..° Sounds on some actions (asteroid hit, asteroid destroyed, asteroid in collision with ship, wave end, ship movement, the player presses "return" in the "menus")

Some of these actions, we've already seen (UI1 being played in the "menus", "NewAchievement1" being played on wave's end).

As mentioned earlier, the process is pretty much the same all the time, in a sub event that checks if the global variable "Sound" is equal to 1 (sound is turned on).

Then the "Audio: Play" action is used with the according sound name.

Check in "esGame" the events 22 and 24 in the "AsteroidHandling" group which correspond to the asteroid hit and asteroid destroyed sounds.

Nothing much to add there in regards to the previous explanations.

Event 14 is the sound played on collision between an "Asteroid" and the player's ship.

Finaly, the sounds on ship movement happens in the group "PlayerMovement".

The same sound is played for thrust and brakes, but is tagged differently.

As you can see event 4, the condition "System: Trigger once" is there again to only play one sound as long as the "UP" key is held down (top event 3).

The sound is "JetLoop1" which is not a short sound. Still no need to loop it.

The sound is tagged "Thrust" as the "UP" key makes the ship moving forward/thrusting.

Event 5 happens when the key "UP" is released.

You can notice the action "Audio: Stop "Thrust"".

The sound is stopped since the ship is thrusting no longer.

The same logic happens in event 7 and 8 but for the tag "Brake".

That's it for the Audio System in this project. In your own projects you can act on the volumes and playrate of your sound, in the same way you stop a sound, by naming its tag.

You can give the same tag to several sounds playing and apply the same volume/action to them all at once by simply naming the tag.

5 - A life bar implementation

It is a subject often asked, and also an interesting feedback for the player.

A lifebar is a visual representation of the health/energy left in some object of the game.

In this project, I chose to only represent the ship's health with a lifebar, as the "Asteroid" are a single hit and their size determines wether they split or get destroyed.

The health itself is handled in the group "PlayerHandling" in "esGame". We've already discussed about it in the Basic Mechanics.

The lifebar is just there to visually represent this health.

The lifebar is in the layout "Game" and is composed by two objects:

+ A sprite "LifeBarBorder", which is the white fixed border.

+ A tiled background "LifeBar", which is the gradient from red to green texture.

The useful difference between a tiledbackground and a sprite there is that when you change the size (width and/or height) of a tiledbackground, it simply displays more or less of the texture, whereas a sprite displays the whole texture and stretch it to its size.

This is why tweaking the width value of "LifeBar" will allow to give the lifebar impression to the player and represent closely the current health status of the ship.

"LifeBar"'s width is 128 (at full, like the max amount of health of "Player").

"LifeBarBorder" is strictly visual and never meant to be modified.

Those two textures I made myself using the GIMP. You can reuse those two assets in your own projects if you feel like it, but to be honest, if I can do such assets, you can yourself too, and possibly do better ones.

From a code's perspective there's only one action required for this implementation.

In event 34 in "esGame", the "Every tick" event :

    Lifebar: Set width to Player.Health 

As mentioned earlier, the full width of "Lifebar" is the same as the full amount of "Player.Health": 128.

So setting "Lifebar"'s width to the current "Player.Health" makes sure that the lifebar displays the correct amount of health.

  • 0 Comments

  • Order by
Want to leave a comment? Login or Register an account!