[ARW Game] A Ruthless World #5

in Game Development3 years ago

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