Progress update day 5
Let there be sound! Goal for the day was to create a class for howler.js to be able to add sounds to the game. Like yesterday I spent too much time writing the code and not enough to make the actual sounds!
It has been a while since I last used howler and I remembered that howler was great, but had one thing I did not like. It was how you handle instances of a sound, that you have to play it to get the instance ID and then can use that ID to manipulate the sound. I wanted to get away from this so I spent some time creating a wrapper that gives you an object that references itself and takes care of the ID.
Example (exaggerated) of using it:
// I have preloaded all the sounds in the audio class. Getting an instance of a sound here.
let fireball = GAME.audio.get("fireball_1");
// Play the sound and directly chain it to modify how it sounds.
// If wanting to do something more advanced, there is access to the original
// howl object. In this case used to listen to the event for when the sound ends.
fireball.play().loop(true).rate(2).fade(0, 0.5, 2000).howl.on("end", () => {
// On each loop, apply a bunch of random modifications.
// Not chaining this time to make it more readable.
fireball.rate(1 + Math.random() * 4);
fireball.stereo(Math.random() > 0.5 ? Math.random() * 1 : Math.random() * -1);
fireball.volume(0.25 + Math.random() * 0.5);
}, fireball.id);
For the curious, this is how the wrapper method looks:
// Get uses a type generated from the JSON of audio resources and suggest the possible
// audio keys to use.
get(key: AudioRes) {
// Get howl from map of howls.
const howl = this.howls.get(key);
// Wrap a method into checking ID, executing method and returning the magic howl object.
function methodWrapper(method: any, isPlay = false, generateIDNoPlay = false) {
if (!isPlay && magicHowl.id == undefined) {
console.info("No audio id, this will change all sounds in group.");
}
if (isPlay && magicHowl.id == undefined) {
magicHowl.id = howl.play();
if (generateIDNoPlay) howl.stop(magicHowl.id);
}
else if (isPlay && !howl.playing(magicHowl.id) && !generateIDNoPlay) {
howl.play(magicHowl.id);
}
// Execute wrapped method
method;
return magicHowl;
}
// Play howl without having to handle id.
const magicHowl = {
play: () => methodWrapper(() => { }, true),
pause: () => methodWrapper(howl.pause(magicHowl.id)),
stop: () => methodWrapper(howl.stop(magicHowl.id)),
mute: (onOff: boolean) => methodWrapper(howl.mute(onOff, magicHowl.id)),
volume: (volume: number) => methodWrapper(howl.volume(volume, magicHowl.id)),
fade: (from: number, to: number, duration: number) => {
return methodWrapper(howl.fade(from, to, duration, magicHowl.id))
},
loop: (onOff: boolean) => methodWrapper(howl.loop(onOff, magicHowl.id)),
rate: (rate: number) => methodWrapper(howl.rate(rate, magicHowl.id)),
seek: (seek: number) => methodWrapper(howl.seek(seek, magicHowl.id)),
stereo: (stereo: number) => methodWrapper(howl.stereo(stereo, magicHowl.id)),
duration: () => howl.duration(magicHowl.id),
playing: () => howl.playing(magicHowl.id),
genID: () => methodWrapper(() => { }, true, true),
howl: howl,
id: undefined
}
return magicHowl;
}
That's enough code. As an ending note, did some more work on particles and created a death sequence for the player. Try it out by jumping into the lava.
Spelmakare is game development using web technologies.
Spelmakare.se
Discord
GitHub
Test ARW
Test TMoS
Play Hive P v. S