Sound
TypeSpriteJS has support for sound effects and background music.
Init Audio
To setup the audio engine we use the AudioManager
component:
[!music]
@AudioManager:typesprite
This component makes sure that the browser initilaizes the sound early on. It is also the component to control global volume and mute.
// in a component
this.world.sendMessage("GlobalMute", true); // make sure the world contains the AudioManager
this.world.sendMessage("GlobalGain", 0.5); // 0 = silent, 1 = full volume
NOTE User interaction required
HTML5/WebAudio in modern browsers prevent websites to play music or sound effects per default. To enable that you must bring the player to, at least once, click into the game. You might also turn off the silent switch on iOS devices.
Play Background Music
The AudioManager
component takes care of playing one channel of background-music:
export class PlayMusicController extends Component {
changeMusic() {
this.world.sendMessage("PlayMusic", "assets/bgm/some-long-track.mp3");
}
stopMusic() {
this.world.sendMessage("StopMusic");
}
}
export class PlayMusicController extends Component {
@link('AudioManager')
private audio:AudioManager
changeMusic() {
this.audio.playMusic("assets/bgm/some-long-track.mp3")
}
stopMusic() {
this.audio.stopMusic();
}
}
Play Sound Effects (SFX)
Playing sound effects in TypeSpriteJS is mainly done by using the SoundFxBag
component. It honors the global gain and mute option of the AudioManager
and has basic support for mixing.
Here we load a single sound effect:
# world.edf
[!Player]
@PlayerController
@SoundFxBag
sounds = {"jump": "assets/sfx/jump.mp3"}
To play this we use:
export class PlayerController extends Component {
onJump() {
this.entity.sendMessage("PlaySound", "jump");
}
}
export class PlayerController extends Component {
@cmp('SoundFxBag')
private sfx: SoundFxBag;
onJump() {
this.sfx.playSimple("jump")
}
}
As the bag part of the name SoundFxBag
already suggests it supports a list of sound effects:
[!Player]
@PlayerController
@SoundFxBag
sounds "{
"jump": "assets/sfx/jump.mp3",
"stop": "assets/sfx/stop.mp3",
"accel": "assets/sfx/accel.mp3"
}"
Here the Player
entity can play jump
, stop
and accel
.
NOTE
Here we use JSON within an EDF file. Unfortunately this really has to be proper JSON. Things like trailing commas will be an issue here.
To make things more interesting we can even mix multiple sounds together:
[!Player]
@PlayerController
@SoundFxBag
sounds "{
"jump": [
["assets/sfx/jump.mp3", 0.5],
["assets/sfx/woof.mp3", 1, 1, 0.2]
],
"stop": "assets/sfx/stop.mp3",
"accel": "assets/sfx/accel.mp3"
}"
Here jump consists of two sound files and when we invoke jump
they both will be played. Per sound file we can configure:
- gain
- playback rate
- play delay
The parameter format for mixed sounds look like this
[file:string, gain:number=1, rate:number=1, delay:number=0]
Memory Management in SoundFxBag
TypeSpriteJS manages sounds in the same way as it manages other resources. There is no harm to configure your world objects like this:
[!Player]
@SoundFxBag
sounds = {"damage": "assets/sfx/dmg.mp3"}
[!EnemeyTypeA]
@SoundFxBag
sounds = {"hurt": "assets/sfx/dmg.mp3"}
[!EnemeyTypeB]
@SoundFxBag
sounds "{
"explode": [
["assets/sfx/dmg.mp3", 0.2, 1, 0.5],
["assets/sfx/blast.mp3", 0.2]
]
}"
assets/sfx/dmg.mp3
would only be loaded once in memory and even could be shared between multiple worlds.
Sound Compatibility
Playing sounds requires browser vendors to aquire mystical fairy dust from ogranizations, so they can play formats like webm
, mp3
and ogg
. Joke aside: not all sound formats are supported on all operating systems and in all browsers. However, in recent times there seems to be good support for audio/webm
.
Hopefully in a later stage TypeSpriteJS can offer more ways to work around this issue.
Use HowlerJS directly (advanced)
In it`s current implementation the audio support is based on howlerjs. For advanced customization you can use the classes directly under the following names:
Howler Class | Access in TypeSpriteJS |
---|---|
Howl | import {AudioHowl as Howl} from 'typesprite' |
Howler | import {AudioHowlerGlobal as Howler} from 'typesprite' |
Sound | import {AudioHowlerSound as Sound} from 'typesprite' |
To manage the resources for an Howl
object you can use the sound
resource type. That way there is no need for manually load and unload sound objects.
import {res, Component, AudioHowl as Howl} from 'typesprite'
export class HowlSoundExample extends Component {
@res('sound', 'assets/sfx/blast.mp3')
private blast:any; // sorry, no proper typemapping for now
onUpdate() {
this.blast.play(); // see Howlerjs docs for all the options here
}
}
NOTE
At some point TypeSpriteJS might switch to a custom implementation. In that case the Howler-Classes might be removed.