Anyway, I'll briefly show you the code here too. Let's start with the "sound engine", which looks like this:
function Audio() {
var on = false
var sounds = {}
function loadSound(soundName) {
var audioElement = document.createElement('audio')
audioElement
.setAttribute('src', "audio/" + soundName + ".ogg")
return audioElement
}
function getSound(soundName) {
if (!sounds[soundName]) {
sounds[soundName] = loadSound(soundName)
}
return sounds[soundName]
}
function play(soundName) {
if (on) getSound(soundName).play()
}
return {
// String -> (Unit -> Unit)
playSound : function(soundName) {
return function() { play(soundName) }
},
// Unit -> Unit
toggle : function() { on = !on; }
}
}
The Audio object exposes two methods, one of which is used to toggle sound on/off and the other returning a function that will play a given sound when invoked. The comments above the methods use the Haskell syntax for describing what are the input and output types of the functions.
One funny thing about HTML5 audio is that .ogg format is supported while .mp3 is not. Some patent issues there, I guess. The reason why playSound returns a function instead of playing a sound is that this way it's easier to plug it into RX streams, as in the following piece of code which constitutes the whole of game sound related code in Worzone:
function GameSounds(messageQueue, audio) {
function sequence(delay, count) {
return ticker(delay)
.Scan(1, function(counter) {return counter % count + 1} )
}
sequence(500, 3)
.SkipUntil(messageQueue.ofType("level-started"))
.TakeUntil(messageQueue.ofType("level-finished"))
.Repeat()
.Subscribe( function(counter) {
audio.playSound("move" + counter)()
})
messageQueue.ofType("start")
.Where(function (start) { return start.object.player })
.Select(function(start) { return start.object.player.id })
.Subscribe(function(id) { audio.playSound("join" + id)() })
messageQueue.ofType("fire")
.Subscribe(audio.playSound("fire"))
messageQueue.ofType("hit")
.Subscribe(audio.playSound("explosion"))
messageQueue.ofType("level-starting")
.Subscribe(audio.playSound("intro1"))
}
The messageQueue thing there is an RX Observable that I described in one of my previous postings. It will provide all game events, each containing a message property that can be used for filtering events. The ofType method actually provides an Observable containing only messages of the given type.
The actual sound effects are
- An alternating sequence of move[1..3] sounds played each 500 milliseconds, starting when a game level is started and ending when a level ends. So, no creepy beeping when the monsters aren't moving.
- Two sounds join[1..2] that are when player 1 or 2 starts the game.
- Fire, explosion and intro sounds that are played when somebody fires or dies and when a new game level is about to start.
There seems to be some problem with my formatting. Extra line breaks appear. Not in the editor though. What's up?
This comment has been removed by a blog administrator.
ReplyDeleteproduction engineer role
ReplyDeleteproduction engineering gate syllabus
production environment
production executive
e production miata