Thunderjack! HTML5 Game Update: Adding Sound Effects (Yeah!)

Hey there.

Well! At this point, the game play is all done. Woot! 👍🏿

Now, you’ll add sound effects to your game. You should add some sound effects to the game to make it more engaging. In this game, sound effects do not affect the game play itself, which is why we’ve deferred adding them until now. However, this does not mean that the sound effects should be an afterthought. When designing your game, you should have an idea of which events that happen in the game will produce sounds, and what those sounds should be.

That said, we’re going to do a little bit of design work here. First, we want to determine which events will produce sounds. Based on the elements in this game, here are some events that could make sense for adding to this game:

  • Button clicks
  • Player wins (at the end of each round, player won more credits than they spent)
  • Player bust
  • Player gets a Blackjack
  • Player gets a Blitz
  • Player gets a Thunderjack
  • Player doubles down
  • Player splits
  • Player surrenders
  • Dealer busts
  • Player or dealer hits
  • Player or dealer stands
  • Shuffling cards
  • Card is dealt
  • Player adds bet
  • Player clears bet

Note: You can use any sound effects you like for these events. You can also come up with your own events to add sound effects for. This article will not cover adding an event for every single event mentioned above. Once you know who to do it for a few events, you’ll have plenty of opportunities to practice adding sounds for the other events.

In this article, I’ll be assigning sounds only to the following events:

  • Player wins
  • Player busts
  • Player gets a Blackjack
  • Player gets a Thunderjack
  • Dealer busts

After adding a few sounds, you’ll get the gist of how to add sounds to your game.

Well, let’s get started!

Adding Sound Effects To Your Project

After you’ve decided which events that will play sounds, you need to add the sound files to your project. Phaser Editor can handle this. ⭐

Phaser Editor uses an asset pack manifest file that defines all the assets and the keys that Phaser uses to reference them. Instead of writing the code to load each asset, only this asset pack file needs to be loaded. It is a JSON file, and if you’d like to know more about assets management, visit this topic.

For this project, I have a manifest file called pack.json. After you have a pack file added to your project, this line of code is how Phaser loads the pack file:

phaserGame.load.pack('preload', 'assets/pack.json');

You’ll probably want to add that line to the preload function of your preloading game state.

Next, let’s add the sounds to the pack file using the following steps:

  1. Open the pack file in the project explorer by double-clicking on it.
  2. From the Assets window, select the preload folder (or a different section if you’d like to add the assets under a different one).
  3. Press the Add Asset button.
  4. On the Asset Type dialog, button, select audio from the list, then press OK.
  5. In the Audio Selected dialog, select the sounds you want to add to the pack file under the section you selected, then press OK.
  6. Save the pack file.

Note: After adding sounds by default, the key that Phaser Editor assigns to each sound is the name of the sound file. The key is how you will reference the sound in your code so you can play it. If you want, you can change the key of any sound by editing the key text field. If you do, make sure the key is unique to all the other keys.

Finally, if you need to later, you can add more sounds to the audio group later on, or remove sounds that you will not be using.

Now that the sound files have been added to the asset pack file, let’s start using them for some events in the game.

Add the Player Wins Sound

First, we’ll add a sound that plays when you win. “Winning” is defined as winning more credits that you spent during the round.

We’ll return to the endRound function that we last saw here. Make the following edits to it:

endRound
GamePlay.prototype._endRound = function() {
  if (this._dealerData.isBust) {
    this._presentPlayersWinViaDealerBust();
  } else {
    this._compareCards();
  }
  
  this._showBetUi();
  this._playWinSound();
};
playWinSound
GamePlay.prototype._playWinSound = function() {
  if (this._playerData.credits > this._startingCredits) {
    this.game.sound.play("snd_win01_12");
  }
};

The Phaser game object contains a sound property, which is a reference to SoundManager object. The SoundManager has a play function on it, and the first parameter is the asset key for the sound that was loaded.

Note: The snd_win01_12 string is the key of the win sound I used when loading the win sound in to the asset pack file. The key of your win sound will likely be different.

We’ve seen PlayerData.getTotalBet before, but what’s this this._startingCredits property? Hmm… 🤔

Well, we want to compare the number of credits the player has at the end of the round to the number of credits they had at the beginning of the round. The this._startingCredits property will track how many credits they had, just before they started the round (before having their credits deducted).

So, we can define this._startingCredits in our onBetButtonPressed function with this modification:

onBetButtonPressed
GamePlay.prototype._onBetButtonPressed = function() {
  if (!this._canAffordBet()) {
    //can't afford the bet - cancel the bet placing method, and don't start the game.
    return;
  }
  
  this._startingCredits = this._playerData.credits;
  this._payRoundCost();
  this._hideBetUi();
  this._beginRound();
};

That should do it for the win sound. Let’s see how it looks (and sounds like!) so far. The win sound should only play when you’ve won more credits than you spent:

Add The Player And Dealer Busts Sounds

Next, we’ll add a sound that plays each time a player or the dealer busts.

We’ll revisit the beginPlayerBust function, and make the following mods:

GamePlay.prototype._beginPlayerBust(player) {
  player.isBust = true;
  if (this._isPlayerId(s_playerId)) {
    this.game.sound.play("snd_bust");
  } else {
    var as_dealerBustSoundKeys = [ "snd_dealer_bust1", "snd_dealer_bust2" ];
    var s_dealerBustSoundKey = Phaser.ArrayUtils.getRandomItem(as_dealerBustSoundKeys);
    var dealerBustSound = this.game.sound.play(s_dealerBustSoundKey);
    if (dealerBustSound) {
      var f_onSoundStop = function(sound, marker) {
        this._setNextTurnPlayer();
      };
      
      dealerBustSound.onStop.addOnce(f_onSoundStop, this);
      return;
    } else {
      this._setNextTurnPlayer();
    }
  }
};

Added quite a bit to this one! 😅 If the player busts, we just play one sound. But if the DEEEEELUR busts, well, let’s get just a little fancy here. 😎

We’re doing two things here:

First, we’re choosing one of two sounds to play randomly (the dealer will have different busts sounds, just for the hell of it, and we want to stick it to the dealer when they lose).

Second, we want to wait until the sound has finish playing before we continue. Say the dealer busts, and the dealer bust sound plays. Also, say the player also won this game. What would happen is both sounds would be playing together – the dealer bust sound, and the player won sound. This isn’t what we want. So, we’ll wait until the dealer bust sound has completed playing before proceeding.

It’s worth pointing out that the f_onSoundStop variable is a function setup as a callback for the bust sound’s onStop Signal. We register the callback by calling the signal’s addOnce function, and specifying the callback as the first parameter. When the sound finishes playing, the Phaser will automatically call the f_onSoundStop function.

And here are the player and dealer bust sounds in action:

Add Blackjack and Thunderjack Sounds

Next, we’re adding sound effects that play every time a player wins with a Blackjack or a Thunderjack.

Let’s start with the Blackjack first.

Once again, we’ll be revisiting some code. In particular this pseudo code from this article will now be updated to:

var playerWithThunderjack = checkIfPlayerHasThunderjack();
var playersWithBlackjack = checkIfPlayersHaveBlackjacks();
var doesDealerHaveBlackjack = hasBlackjack(dealer);
if playerWithThunderjack {
  handleThunderjack(playerWithThunderjack);
  endRound();
} else {
  if doesDealerHaveBlackjack {
    handleDealerBlackjack();
    endRound();
  } else {
    if at least one player has blackjack {
      //play the blackjack sound here
    }
    setFirstTurnPlayer();
  }
}

The checkIfPlayersHaveBlackjacks will function return an array of all the players who have blackjack, so if this array has at least one player in it, we’re good.

Next, we’ll tackle playing a sound if a player has a Thunderjack.

Coming from the code above, we’ll modify the handleThunderjack function:

handleThunderjack
function handleThunderjack(player) {
  player.handData.hasThunderjack = true;
  //play the thunderjack sound here
}

That’s it for adding the Thunderjack sound! 👍🏿 And here are the sounds in play:

Most of the events are just finding the place in your code where it would seem most appropriate to add a playing sound. Only in special cases would you need to wait for a sound to complete playing before proceeding.

We’ll finish this article here. If you have any questions for me about anything I’ve discussed so far, feel free to ask in the comments below. If you’d like to add more sounds to more events, by all means have at it.

Or, if you’re looking to hire a coder to build your next card game (and add all your desired sounds into the game as well!), get in touch with me by e-mailing me at cartrell@gameplaycoder.com, or filling out my contact form.

Thanks guys, talk to you later. Take care,

– C. out.

Thunderjack!

Hey guys,

As I mentioned earlier, I recently completed the Android Basics Nanodegree program offered by Udacity. During the course, I decided to create a side project, completely independent of the course material. The project not only uses some of the concepts from the course, but also expands on concepts beyond the scope of the course. This is where the real fun is, because these are uncharted waters that present unique challenges.

This project I’m working on – besides Brickout, which is an HTML5 game using Phaser – is a called Thunderjack. It’s Blackjack, but with my own spins on it, mostly just some over-the-top theatrics, and playing around with some of the rules. (:

The awesome Thunderjack!

I’ve been working on this for a few months now, reinforcing my knowledge of Android Studio, Java, and Android development. One caveat I’ve found is, Android Studio is not the most ideal IDE for building an Android game, at least not one that fits well into your typical layout schemes such as Linear, Relative, or Constraint. For the record though, I went with the Constraint layout, mainly because of it’s guides functionality, which can use percentages of the screen, which makes designing a responsive app much easier.

One problem I ran into was trying to fit all the blackjack elements on the display. They include:

1). Three lower player hands
2). Three upper player hands. Each hand can split, so you can play up to six hands at a time
3). Positioning the cards so they cascade atop each other, but still able to see what the cards are
3). Betting chips
4). Dealer’s hand
5). Results (bust, win, etc.)
6). Text for displaying credits, and score of each hand
7). Action buttons (hit, stand, etc)
8). Turn indicator arrows (whose turn it currently is)

As you see imagine, the underlying constraint layout is quite massive! And it’s Landscape orientation only; ain-no way in the hell all this was gonna fit on a Portrait orientation, and still be easy to see, especially on phones.

A peculiar issue I faced was a performance issue that took me a while to track down. It was due to rendering of TextView objects inside the TextView, probably because of all the re-calculating that goes on under the hood. This presented a big problem, because it meant that I would have to scrap the entire Constraint layout! But the constraints allow me to establish that responsiveness across various device sizes! Sigh… shit. Time to get creative…

I didn’t scrap the Constraint layout. Not exactly. What I did was:
1). Start again with a blank constraint layout.
2). Examined each visual element (text, button, image, etc), and cloned it
3). Placed the clone element on the blank layout in the same position of the original element
4). Deleted the constraint layout
5). The blank layout becomes the official layout that is shown.

While this created a lot more work, it also allowed me to re-created the layout with all the responsiveness, but without all performance hit of the constraints. I believe I can get away with this, because of its static nature. Other than the cards, which all move to predetermined positions on the layout, there aren’t any dynamic elements on here. In other words, nothing needs resizing or repositioning.

Another challenge is use of sound effects.

The Android Basics course does talk about use of the MediaPlayer.

As you know, games often play multiple sounds at once, and it seems that MediaPlayer can only play one sound at a time.

So, I found a class called SoundPool class that allows you to load up several sounds, and is designed for smaller sounds. This seemed to be exactly what I was looking for, until I found that it has no notification callback support for when a sound has finished playing, which is also a functionality I need. MediaPlayer however, does have this.

So, the approach I’m taking is a hybrid one. Basically, I’m using SoundPool for all the sounds I can play and forget about, while the MediaPlayer can play those sounds where I need to be notified when they complete, so I can take appropriate actions.

However, SoundPool doesn’t come without its caveats either. You need to specify a max number of sounds it can play at once by loading them into the SoundPool, and if you need to play a sound that isn’t loaded, one of the other sounds must get discarded. I’m currently working on a way around this, because my first implementation introduces a bit of lag when loading some sounds. But, I’m confident I’ll have an unorthodox solution for this. 😉

That’s it for now. I’ll keep you guys updated on the progress of this one. I should have it done and into the Google Play Store later this year.

Thanks!

– C. out.

Sound Effects

What’s up, guys.

Brickout now has the sound effects added! I also snuck some of my jazzy musical skills into many of the sound effects.

A short video with the sounds is below. Things got a bit crazy around the 1:00 mark in the video! I think I’ma keep this aspect of the game design, though. Then it got really boring, trying to hit that LAST brick… dammit!  >:D

But, I’m happy that with 41 sound effects added, most of them are done now. (:

Playing sounds using Phaser and its SoundManager class was easier than I thought! I still need to implement callback notifications when a sound has finished playing, because I will need that functionality a little later.

After watching the video, share your opinions in the comments below. I’m curious to know. Thanks!

– C. out.

Tools I Use

Hey.

I want to fill you in on the tools and resources I use when I’m coding games. This is not an exhaustive list.

Coding Editors/IDEs

  • FlashDevelop
    My current go-to IDE for all things ActionScript 3. I also like how it can download and configure updates of the Adobe AIR and Flex SDKs.
  • Adobe Flash CS/Animate
    I don’t use this for coding, but for managing assets. While I’m not an artist, graphic designer, game designer, I find its visual editor very easy to use and mostly intuitive.
  • Brackets
    Been using this free editor for a little while. I use it for JavaScript when coding HTML5 games using Phaser.

Programming Languages/Engines/SDKs/Runtimes

  • Adobe AIR
    Despite Flash being retired soon, Adobe AIR is still at large. AIR is not the same thing as Flash – they both happen to use ActionScript 3 and many of the same APIs (with AIR having access to many more of them, partly due to it being able to target desktops). Plus, Adobe AIR can be used to target mobile (Android and IOs) from the same code with minor changes.
  • Adobe Flash
    Yes, I know Flash will no longer be updated or distributed by end of 2020, but until then, hey, it’s still being used.
  • Phaser
    I only care enough about HTML5 and JavaScript because of Phaser and it’s capabilities for game making. I don’t give a damn about web development.
  • Unity
    While I haven’t used Unity to make any games yet, I found a good course on Udemy for it.

Graphics

  • Paint.NET
    I use this for editing of bitmap files. Another simple and intuitive tool to use.

Project Management

  • Trello
    A free online tool for keeping track of my progress, especially when working on larger projects. I use it in a Kanban style, and I’ll have three major categories for tasks: Backlog; Work In Progress; and Ready for Testing. Once the client has tested the latest updates and all’s well, I will archive all the tasks in the Ready for Testing category, and start anew.

Source Control

  • GitHub
    Using Git as the version control system.
    You can find me here, hint, hint.
  • Bitbucket
    I also use Git here, but have tried Mercurial.

Audio

  • Wavosaur
    Simple tool for editing audio files.
  • Audacity
    Not as easy to use as Wavosaur, but it has more functions, particularly in terms of effects you can apple to sounds.

Music

 

So, that’s pretty much the jist of what I use. If you have any questions about anything here, let me know in the comments!

– C. out.