Saturday, May 16, 2020

Making Pent Up Anger Part 3 of 5

Making Pent Up Anger part 3 of 5 - Head to Head version of the Game



This is the third part of a five part series on building Pent Up Anger using AnimateCC. The game can be found at http://spelchan.com/games/y2018/PentUpAnger.php .

Preparing the Pieces

The first thing we are going to need to do to get a head-to-head (hot seat) game going is to have more than a single piece on the board. This means that all the pieces for all five potential players will need to be tracked. An array to hold this information is easy enough to build. The big question is where should this information live? It could be a good idea to keep the board separate from the game state and instead have a separate class that manages the game play. This would have the advantage that you would be able to have different variants of the game and that controller would handle the game logic. This is going a bit too overboard and is something that could be done through refactoring at a later point if such a thing ended up being desired so we will follow the principle of only writing the code that we actually need to accomplish our task and put the game logic into the board class.

This means adding a bit of code to the board initialization class to set up the 25 game pieces that are necessary. While I don't like getting ahead of myself, we know that we are going to need to be able to click on the pieces and that this will require a listener so we will set up the click listener right now even though we won't be implementing it until later. The handler for clicking is going to be called choosePiece and we will need. A dummy version of the choosePiece method should be created with a simple console log warning you that the method has not yet been implemented.

As I stated earlier, to use a method as a callback function, you need to bind the method to the class being used. This has a rather strange behavior of being considered a different function call each time it is created which means that while you can add event listeners, removing those listeners is not possible unless you keep a copy of the originally bound function. This information is stored in the pieceListeners field and is used as the event listener.


this.boardMovie = movie;
this.pieces = [
 [movie.p1, movie.p2, movie.p3, movie.p4, movie.p5],
 [movie.r1, movie.r2, movie.r3, movie.r4, movie.r5],
 [movie.y1, movie.y2, movie.y3, movie.y4, movie.y5],
 [movie.g1, movie.g2, movie.g3, movie.g4, movie.g5],
 [movie.b1, movie.b2, movie.b3, movie.b4, movie.b5]
];
this.pieceListeners = [];
this.player = 23;
for (var cntrPlayer = 0; cntrPlayer < 5; ++cntrPlayer) {
this.pieceListeners[cntrPlayer] = [];
for (var cntr = 0; cntr < 5; ++cntr) {
this.pieces[cntrPlayer][cntr].playerID.text = ""+(cntr+1);
this.pieces[cntrPlayer][cntr].useHighlight.visible = false;
this.pieces[cntrPlayer][cntr].playerID = cntrPlayer;
this.pieces[cntrPlayer][cntr].pieceID = cntr;
this.pieceListeners[cntrPlayer][cntr] = this.choosePiece.bind(this, cntrPlayer, cntr);
this.pieces[cntrPlayer][cntr].addEventListener("click", this.pieceListeners[cntrPlayer][cntr]);
}
this.pieces[cntrPlayer][cntrPlayer].useHighlight.visible = true;
}

At the end of initialization, the pieces used by the player exist in a two dimensional array named pieces. This holds the pieces and relevant information about the pieces but does not set up the pieces. This needs to be done to start the game, and as we want to let the player play the game more than once without having to reload the game it makes sense to have a separate method for setting up the starting board. This we will call layoutPieces. This simply loops through the players and their pieces  and then places those pieces on the board in the appropriate starting location. It then loops through all the locations on the board and makes sure that the piece currently assigned to that location is null. This is important as only one piece is allowed on each board location so tracking the piece on a location is required to determine if a piece is going to be sent home.

spelchan.Board.prototype.layoutPieces = function() {
var temp;
for (var cntrcol = 0; cntrcol < 5; ++cntrcol)
{
for (var cntr = 0; cntr < 5; ++cntr)
{
temp = this.BOARD_LAYOUT[cntrcol][this.BOARD_START_INDEX] + cntr;
this.pieces[cntrcol][cntr].x = this.layout_x[temp];
this.pieces[cntrcol][cntr].y = this.layout_y[temp];
this.pieces[cntrcol][cntr].location = temp;
console.log("placing piece on " + temp);
}
}
for (cntr = 0; cntr < 105; ++cntr)
this.layout_piece[cntr] = null;
}

Now that we have the pieces able to appear on the board, the next step is to actually handle the player's turn.


Turn Handling

With the player pieces laid out on the board, we are ready to get the game under way. But for the players to do anything they need to be able to move. This requires a way for the player to roll the die. This can be combined with our solution for determining which players’ turn it is by simply having a roll button for each player. This means that we need to create a roll button for each of the five players. Instead of creating five buttons, we can ``cheat'' by only create one grayscale version of the play button and tint it. The states for this button can be seen in the image below. In addition to the roll button, we will need a skip button for skipping your turn which is set up the same as the roll button.

To make use of this button, it actually has on the screen. This is done in animate by adding the buttons to the Only the player who currently is playing can use this button, only the roll button for the current player needs to be on the screen. This is done by manually positioning the components on the game screen symbol as shown in the image below. Note that this screen shot is from later in development so there are messages and a button that would not normally be on the screen at this time.



This, in my opinion, is user interface related and is kept in the main Pent class.  This is set up allows us to set up in the startGameScreen which is the method we use for initializing the main game screen when the game is being set up. This simply sets up the pieces of the board and then sets up all of the roll and skip buttons.

spelchan.Pent.prototype.startGameScreen = function(movie) {
this.gameMovie = movie;
this.currentPlayer = 0;
this.board = new spelchan.Board(movie.board_movie);
this.board.layoutPieces();
this.die = new spelchan.Die(movie.die_movie);
movie.stop();
this.rollBtns = [movie.proll_btn, movie.rroll_btn, movie.yroll_btn, movie.groll_btn, movie.broll_btn];
this.skipBtns = [movie.pskip_btn, movie.rskip_btn, movie.yskip_btn, movie.gskip_btn, movie.bskip_btn];
this.rollHandler = this.startRoll.bind(this);
this.skipHandler = this.skip.bind(this);
for (var cntr = 0; cntr < 5; ++cntr) {
this.rollBtns[cntr].addEventListener("click", this.rollHandler);
this.rollBtns[cntr].addEventListener("mousedown", spelchan.tintedButtonEvent);
this.rollBtns[cntr].addEventListener("pressup", spelchan.tintedButtonEvent);
this.rollBtns[cntr].addEventListener("rollover", spelchan.tintedButtonEvent);
this.rollBtns[cntr].addEventListener("rollout", spelchan.tintedButtonEvent);
this.skipBtns[cntr].addEventListener("click", this.skipHandler);
this.skipBtns[cntr].addEventListener("mousedown", spelchan.tintedButtonEvent);
this.skipBtns[cntr].addEventListener("pressup", spelchan.tintedButtonEvent);
this.skipBtns[cntr].addEventListener("rollover", spelchan.tintedButtonEvent);
this.skipBtns[cntr].addEventListener("rollout", spelchan.tintedButtonEvent);
}
this.winText = movie.win_txt;
this.continueHandler = this.endGame.bind(this);
this.continueBtn = movie.continue_btn;
this.continueBtn.addEventListener("click", this.continueHandler);
this.UI_ROLL = 0;
this.UI_SKIP = 1;
this.UI_WIN = 2;
this.UI_HIDE = 3;
this.ROLL_TIME = 50;
this.PLAYER_LABELS = ["Purple", "Red", "Yellow", "Green", "Blue"];
this.PLAYER_COLORS = [0xFF8800AA", 0xFFAA0000", 0xFFAAAA00", 0xFF00AA00", 0xFF0000AA"];
this.updateGameUI(0, this.UI_ROLL);
}

As you can see by looking at the code, when the player's button is visible, clicking on the button calls the rollHandler function which is the startRoll method bound to the class instance. It simply sets up the roll and then updates the user interface using our updateGameUP which is called whenever the system needs to update the UI with the caller providing the current player and the state the game is in. Note that we defined four states as follows:

  • UI_ROLL Waits for player to start rolling the dice.
  • UI_SKIP Waiting for user to make move or skips the rest of their turn.
  • UI_WIN Indicates that the game has been won.
  • UI_HIDE Turns off all the user interface.

spelchan.Pent.prototype.updateGameUI = function(player, state) {
// hide all buttons
for (var cntr = 0; cntr < 5; ++cntr) {
this.rollBtns[cntr].visible = false;
this.skipBtns[cntr].visible = false;
}
// reveal stuff based on state
switch (state) {
case this.UI_ROLL:
this.rollBtns[player].visible = true;
break;
case this.UI_SKIP:
this.skipBtns[player].visible = true;
break;
}
}

spelchan.Pent.prototype.startRoll = function() {
this.die.startRoll(this, this.ROLL_TIME);
this.updateGameUI(this.currentPlayer, this.UI_HIDE);
}

The roll function calls the roll result method once the roll is finished. This method makes use of the board class to determine which pieces that the player can move based on the results of the roll.

spelchan.Pent.prototype.rollResult = function(n) {
this.updateGameUI(this.currentPlayer, this.UI_SKIP);
console.log("the roll was " + n);
this.board.prepareMove(this.currentPlayer, n, this);
}


The prepareMove function is a bit more complicated task so I am going to break the function up into several sections and comment on each section. The first thing this function does is determine where the relevant board locations for that player are. This is a simple lookup in our BOARD\_LAYOUT array.

spelchan.Board.prototype.prepareMove = function(player, roll, listener) {
var moveCount, cntr, loc, zonedist;
this.lastRoll = roll;
this.clearActions();
this.move_listener = listener;
var home = this.BOARD_LAYOUT[player][this.BOARD_HOME_INDEX];
var start = this.BOARD_LAYOUT[player][this.BOARD_START_INDEX];
var end = this.BOARD_LAYOUT[player][this.BOARD_END_INDEX];
this.player = player;
movecount = 0;

Next we loop through the five pieces that belong to the player. We then determine how far from home that particular piece is. The board is circular (sort of) which means that we have the extra complexity of dealing with the possibility that the target home location is actually less than the actual location. As this will result in a negative distance from home, we simply need to add the size of the board (55 locations) to this value to get the correct distance.

Knowing how far the piece has to travel to get to the home location is the way we determine if the piece is located in the loading zone. It is also going to prove to be a very useful bit of information when we get around to writing the AI next chapter.

for (cntr = 0; cntr < 5; ++cntr)
{
this.pieces[player][cntr].weight = 0;
loc = this.pieces[player][cntr].location;
console.log("piece " + cntr + "is at " + loc);
zonedist = home - loc;
if (zonedist <= 0)
zonedist += 55;
console.log ("piece " + cntr + " is " + zonedist + " from reaching home");

As you have probably already realized, not all pieces are going to be on the board.  In fact, some of the pieces will be in the starting gates. It is important that those pieces be able to move, otherwise we won’t have a game at all since there would never be any pieces on the board. To start a piece on the board, the roll must match that piece. Likewise, to remove the piece the roll must match the piece. This is simply enough to check. If the piece matches the roll, we then see if the piece is in the loading zone or in the starting gate. If the piece is in one of these area’s then the piece is movable.

// see if piece can be launched or finished
if ((cntr+1) == roll)
{
if ( (loc == (start+cntr)) || (zonedist < 5) )
{
console.log("Piece is launchable/exitable");
this.pieces[player][cntr].useHighlight.visible = true;
++movecount;
}
}

We then see if the piece is on the board and can move without going past the loading zone. We know the board starts at location 50, so that check is simply a location check.  The distance from home can be used to see if the roll will take you past home, as if the distance is less than the roll of the die, then the move will take you past the starting position!

if ( (loc >= 50) && (zonedist > roll) )
{
console.log("piece movable on board");
this.pieces[player][cntr].useHighlight.visible = true;
var targetloc = loc + roll;
if (targetloc > 104)
targetloc -= 55;
++movecount;
}
}

Finally, we see if there is actually a move available for the player. As all the moves are counted above, we simply see if there are moves. If not, we are done the move!

if (movecount == 0)
listener.doneMove();
}


When the player chooses a piece by clicking on it, the choosePiece function gets called. 
The choosePiece function will start the animation so it will be covered next.

Moving the Piece

The choosePiece function within the board movie is called when a piece is clicked. The first thing the function does is determine if the piece that was selected belongs to the player and if not simply returns. It then figures out where the piece is going to be moving to. If the piece is waiting to be put on the board, the target location is the player's starting spot on the board. If the piece is already on the board, it moves it the die roll's number of slots. This is not as easy as it sounds as the board is a circle but in memory is treated as a line. To make the board act circular, if a piece goes of the end of the line, it wraps to the beginning of the line.  Finally, it sets up the movingPiece, movingTargetX and movingTargetY variables so the updateMove method will know that it has a piece to move and where to move that piece to.

spelchan.Board.prototype.choosePiece = function(player, piece) {
console.log("***choosePiece called***");
if (player != this.player) {
console.log("Piece does not belong to player! " + player + "!=" + this.player);
console.log("speed = " + this.SPEED);
return;
}
console.log ("Piece was selected to be moved: " + player + "," + piece);
var loc = this.pieces[player][piece].location;
console.log ("Piece was on " + loc);
this.clearActions();
if (loc == (this.BOARD_LAYOUT[player][this.BOARD_START_INDEX]+piece) )
this.movingTargetLoc = this.BOARD_LAYOUT[player][this.BOARD_HOME_INDEX];
else if ( (loc >= this.BOARD_LAYOUT[player][this.BOARD_LOADING_START]) &&
(loc <= this.BOARD_LAYOUT[player][this.BOARD_LOADING_END]) &&
(this.lastRoll == (piece+1)) )
this.movingTargetLoc = this.BOARD_LAYOUT[player][this.BOARD_END_INDEX]+piece;
else
{
this.movingTargetLoc = loc + this.lastRoll;
if (this.movingTargetLoc > 104)
this.movingTargetLoc -= 55;
}
this.movingPiece = this.pieces[player][piece];
this.movingTargetX = this.layout_x[this.movingTargetLoc];
this.movingTargetY = this.layout_y[this.movingTargetLoc];
this.layout_piece[loc] = null;
console.log("Moving from " + loc + " to " + this.movingTargetLoc);
// onEnterFrame = updateMove;
}

The updateMove function is called every frame whether there is something to be animated or not. It knows that it has work to do if the movingPiece variable is not null. The first thing the function does is figures out if the current frame of motion will be the last frame of motion. This is simply a check of the distance from the current position to the ending position. If the distance remaining to move is less than the speed then we obviously are on the last frame of animation. Or at least the last frame of that pieces’ animation.

If the piece has reached the target location we need to determine if there is already a piece on the target location. If there is, we determine the original start-block location for that piece and create a new animation moving that piece back to start. If there is not a piece on the target location we call the doneMove handler assigned to the board which is used for managing what happens once the animation is finished. This handler will be written shortly.

If the piece being animated has not reached the end of it's animation, then we simply move towards the target location by applying the time adjusted movement speed to the piece.

spelchan.Board.prototype.updateMove = function() {
if (this.movingPiece == null)
return;
console.log("moving piece...");
var curX = this.movingPiece.x;
var curY = this.movingPiece.y;
var deltaX = this.movingTargetX - curX;
var deltaY = this.movingTargetY - curY;
var distance = Math.abs(deltaX) + Math.abs(deltaY);
if (distance <= this.SPEED)

this.movingPiece.x = this.movingTargetX;
this.movingPiece.y = this.movingTargetY;
// movingPiece.changeState(0);
this.movingPiece.location = this.movingTargetLoc;
if (this.layout_piece[this.movingTargetLoc] != null)
{
var temp = this.layout_piece[this.movingTargetLoc];
this.layout_piece[this.movingTargetLoc] = this.movingPiece;
this.movingTargetLoc = this.BOARD_LAYOUT[temp.playerID][this.BOARD_START_INDEX]+temp.pieceID;
this.movingTargetX = this.layout_x[this.movingTargetLoc];
this.movingTargetY = this.layout_y[this.movingTargetLoc];
this.movingPiece = temp;
}
else
{
this.layout_piece[this.movingTargetLoc] = this.movingPiece;
this.movingPiece = null;
// onEnterFrame = null;
this.move_listener.doneMove();
}
}
else

var moveX = deltaX * this.SPEED / distance;
var moveY = deltaY * this.SPEED / distance;
this.movingPiece.x += moveX;
this.movingPiece.y += moveY;
}
}

We are finished with the board movie for the moment, so the last thing we need to do is in the main movie. This task is simply a function to handle the game once the move is done. This function simply checks to see if the game has been won and if so ends the game. If the game is not over it goes to the next player.

spelchan.Pent.prototype.doneMove = function() {
if (this.board.checkWin(this.currentPlayer) == true) {
this.updateGameUI(this.currentPlayer, this.UI_WIN);
return;
}
this.currentPlayer = (this.currentPlayer + 1) % 5;
this.updateGameUI(this.currentPlayer, this.UI_ROLL);
}

The method for determining if the game has been won will be developed in the next section.

Winning the Game

As shown last section, whenever a player finishes a move, we need to determine if the game has been won. This is a fairly simple function as we simply need to check to see if all the pieces are in their end positions. A simple function in the board movie can handle this.

spelchan.Board.prototype.checkWin = function(player) {
var cntr, result = true;
var end = this.BOARD_LAYOUT[player][this.BOARD_END_INDEX];
for (cntr = 0; cntr < 5; ++cntr)
{
if (this.pieces[player][cntr].location != (end + cntr))
{
result = false;
break;
}
}
return result;
}

If the player has won, however, the state for showing the win message has not been handled. To do this we are going to need to create a continue button to add to the screen as well as a large text message that displays the win message. The continue button is a simple gray button with the states as shown in the image below.


The Pent class updateGameUI now needs to be updated to handle the win message and showing the win button. At the top of this method add the following:

this.winText.visible = false;
this.continueBtn.visible = false;

The actual code within the switch statement add the case for the UI\_WIN state as follows:

case this.UI_WIN:
    this.winText.color = this.PLAYER_COLORS[this.currentPlayer];
    this.winText.text = this.PLAYER_LABELS[this.currentPlayer] + "\nPlayer\nWINS!";
    this.winText.visible = true;
    this.continueBtn.visible = true;
    break;

Now the game is playable in hotseat, but it would be sure nice to be able to control the number of players, and be able to play against the computer. To do that we are going to need to delve into the world of Artificial Intelligence, at least as it applies to games. See you next month!


Saturday, April 18, 2020

Making Pent Up Anger part 2 of 5

Pieces of the Game


This is the second part of a five part series on building Pent Up Anger using AnimateCC. The game can be found at http://spelchan.com/games/y2018/PentUpAnger.php .

Building the Board


A hexagon board. Sounds complicated, but building it really isn't. First, we want 12 squares per side, with the corner square shared so we need to figure out how big to make a square. Whatever length we decide, needs to be divisible by 12. Making squares 25x25 would make a line that was 300 pixels long. If we draw a horizontal line 300 pixels long and then rotate it 72 degrees and rotate another 300 pixel horizontal line 144 degrees, we see that the combined lines go outside our 640x480 boundaries, but barely. If we use 288 pixel lines, the lines fit within the area of the screen. This means that 24x24 boxes will work.

I draw a 24x24 box. I then copy the box a couple of times and join them together. I then copy the three boxes and past the copy together. One final copy and past and we end up with a row of 12 boxes. Copy that row and rotate it 72 degrees. Join at the corner. Next past the copied boxes again and rotate 144 and place at the second corner. Again at 228 and 288 and you end up with a completed pentagon board.

Do a bit of colouring so the starting points and the exit zones are distinct. Then grab a 5 block chunk of boxes and create the inside exit zones by rotating the box as you did above.
Finally create starting zones. Turn the whole group into a movie clip.


Building the Player


Building a piece sounds simple, but there is a bit of a logistics problem. First, we need to know if the piece is movable and if it is the current piece selected. This means that a piece is going to have three states associated with it. Next, we are going to have to have a number on the piece indicating which of the five pieces the piece is. Three states with five pieces is 15. There are also five colors. fifteen times five is 75. Drawing 75 pieces is not a pleasant task so we are going to have to come up with a better solution.

In Animate CC, buttons are a special case of a movie clip which simply contain four frames. There is nothing stopping you from using multiple layers on a movie clip, and you can programmatically control objects. By using multiple layers on a button, we can one highlight silhouette indicating which pieces can be moved, a selected silhouette for each color and a piece for each color reduces this down to just 11 shapes which really are just 2 shapes that are colored differently.

Tinting could be used to get different coloring. Create.js does behave a bit strangely with tinting but there is an easy fix for that. We will use tinting with our buttons later to demonstrate this. I chose to do multiple versions of the pieces as this gives you a bit more control over the colors and I really didn’t like the tinted version in my original Flash version of this game. For this reason I have gone with the button technique.


As you can see by looking at the figure above, the button has 4 layers in it. The ``ID'' layer holds a textfield which will allow the changing of the label assigned to that player. This easily allows us to change the number of the piece meaning that we only need to have one piece per color. This is set when the board is initialized, which we will be covering later.

The ``base'' is the actual image for the player. It is second from the top so that it remains clearly visible even when there is indication that the piece is select-able or the piece is highlighted. Each color has their own image which has color choices made to make the piece look nice for that particular color.

The third layer is the ``use'' layer of the button and is simply a movie clip of a white silhouette of the game piece. This movie clip is used by all five variations of the player button. The purpose of this layer is to give the user an indication as to which pieces they are able to move. By having this as a movie clip, you can simply set the visibility of the movie clip to false if the piece is not usable and set it to true when it is usable. This will be done when we implement the game play portion of the game later.

The final layer is not in the button's up state as it is used as a highlight for when the player moves their mouse over the piece. This is shown in the figure below.


Building the Die


This game uses an eight sided die. For those of you unfamiliar with such a die, the die looks sort of like a diamond. You use it like you would a normal six sided die, but it has eight possible results instead of six. The primary reason for going with an eight sided die instead of the standard die was three-fold. First it adds something unique to the game. Second, it speeds up the game as the average roll will be 4.5 as opposed to 3.5 for a six sided die. Finally, they are cool.

Building the die movie is fairly simple. First we start with an image of the die in a finished position. On a separate layer we have text for the eight different values (labelled r1 to r8). We also have mid-roll die images. Figure \ref{fig:die}  shows the frames that make up the die.

This is the minimal die animation approach. A more ambitious approach would have numbers on the between frames with the values shown. This would require many more frames of animation as you would have the 8 result frames and would need 18 additional between frames for 26 frames.  Granted, the animation would look better so if you have the artist time to do this then it may be a good option. 

As with our other movies, we treat the die movie as a class. To handle the rolling of the die we will need some functions, but first we will initialize the die. This simply sets the value of the die to 8 and resets the listener and roll variables, which we will explain shortly.

spelchan.Die = function(movie) {
this.dieMovie = movie;
this.cutoff = 300;
this.frameListener = this.handleTick.bind(this);
this.clickListener = this.handleClick.bind(this);
this.dieMovie.addEventListener("tick", this.frameListener);
this.dieMovie.addEventListener("click", this.clickListener);
this.rolling = false;
this.value = 0;
this.rollListener = null;
}

Rolling the die presents us with a bit of a problem. We want the roll to be animated but if the roll is animated, then it can’t return a value right away. To solve this problem we have the startRoll function to get the die rolling and then once the animation is finished we will have the die class call the handleClick function to stop the movie. The end of roll handler is called handleClick as it is handling the result from the player clicking on a roll button, though this is a poor name but at the time of development it seemed to make sense. This is why code reviews are a good thing to have.

The actual die roll will consist of 5 to 20 spins (the number determined at random) with a spin consisting of an in between shape (the three shapes at the bottom of figure 4) followed by a number. To start the roll the number of spins is determined followed by a call to the handleTick function.

spelchan.Die.prototype.startRoll = function(listener, cutoff) {
this.rollListener = listener;
this.rolling = true;
this.cutoff = cutoff;
}

The handleTick function gets called every frame. It simply looks to see if the die is being rolled and if it is selects a new frame to be displayed. When the die is being rolled, there is a cutoff variable that determines when we are ready to end the roll at which point we call the clickListener function which handles the results of the click on the roll button.

spelchan.Die.prototype.handleTick = function(e) {
if (this.rolling) {
this.dieMovie.gotoAndPlay(Math.floor(Math.random()*17)+1);
--this.cutoff;
if (this.cutoff <= 0)
this.clickListener(null);
}
}

Once the roll is finished, the handleClick function makes sure that the die is actually in the process of being rolled and if so will pick the final value, setting the movie clip to that particular frame. It then makes a call to the roll listener that is currently attached to the die. The roll listener is set by the game as appropriate using a setRollListener method that simply specifies the function to call when the roll is finished.

spelchan.Die.prototype.handleClick = function(e) {
if (this.rolling) {
this.rolling = false;
this.value = Math.floor(Math.random()*8)+1;
this.dieMovie.gotoAndStop(this.value);
if (this.rollListener != null)
this.rollListener.rollResult(this.value);
}
}
spelchan.Die.prototype.setRollLister = function(listener) {
this.rollListener = listener;
}

Board Layout


We already have a board but the player pieces need to be placed on the board. We need to know the coordinates of every square that the player can land on so we can place the pieces on the proper screen locations.  We could create a table by hand that contains all the coordinates of the locations. This is time consuming and very prone to errors but could be simplified by writing a utility to help do this. Such a utility would only need to display the board and then record all the clicks on the board that the user made and storing them in a table that can be saved. For board games that have complex layouts, this may be required. As our board is laid out in a fairly linear and has a regular pattern to it so we should be able to algorithmically create the table.

We still need some coordinates, which lead to a strange problem. Despite dragging an instance of the piece movie to the desired starting locations and using those coordinates, Animate seems to shift the location. After a little investigation, I found out that the properties panel is actually giving you the top-left location of the object, not the location of the anchor. This is something you will need to keep in mind when using coordinates provided to you by Animate.

All the pieces and code to handle the pieces are going to be placed in our board movie. To handle this, a couple additional layers are going to be needed. The layers are “code,” “pieces,” and our original layer which we will name “back.” On the pieces label we drag a copy of our piece movie which we will name “piece\_movie.”

The board initialization will be done in the constructor which is also where we set up all of our ``constants''.  When you think about it, the board really can be broken into three sections for each of the five colors. Every color has a side of the board starting at their starting gate, they also have an ending block of squares where the pieces go when they have finished. Finally, there is the starting - or home - block. All of these things can have simple coordinates attached to them and then, if we know the angle, we can determine the location of the other locations within that group. For the game, we are going to also need the board id’s of these locations as well as the starting and ending ids for the loading zone.

All of this information results in seventy different pieces of information. To handle all of this information without having too many variables to worry about, I have created an array of five arrays with the five arrays containing the fourteen items we are interested in. Each of the items is assigned an index value within the array, with a constant being created so in the future I don’t need to remember the particular index value.

Once this array is created, two layout arrays are created to hold the x and y positions of all of the locations on the board.  Some simple trigonometry is used to generate all the positions within that array. A lot of work, but all this initialization will make developing the rest of the game a bit easier.

var degree = Math.PI / 180;
// set up constants for array indexes
this.BOARD_START_INDEX = 0;
this.BOARD_START_X_INDEX = 1;
this.BOARD_START_Y_INDEX = 2;
this.BOARD_START_ANGLE_INDEX = 3;
this.BOARD_END_INDEX = 4;
this.BOARD_END_X_INDEX = 5;
this.BOARD_END_Y_INDEX = 6;
this.BOARD_END_ANGLE_INDEX = 7;
this.BOARD_HOME_INDEX = 8;
this.BOARD_HOME_X_INDEX = 9;
this.BOARD_HOME_Y_INDEX = 10;
this.BOARD_HOME_ANGLE_INDEX = 11;
this.BOARD_LOADING_START = 12;
this.BOARD_LOADING_END = 13;
this.BOARD_LAYOUT = [
//si,  sx,  sy, sa, ei,  ex,  ey, ea, hi,  hx,  hy, ha, ls, le
[  0, -39,-236,180,  5, -11,-179,270, 50,  -9,-219,324,101,104],
[ 10, 231, -84, 90, 15, 169, -48,198, 61, 205, -58,252, 57, 60],
[ 20, 151, 212,  0, 25, 101, 162,126, 72, 121, 198,180, 68, 71],
[ 30,-175, 212,180, 35,-123, 161, 54, 83,-145, 192,108, 79, 82],
[ 40,-254, -42,270, 45,-185, -48,342, 94,-227, -64, 36, 90, 93] 
];
this.layout_x = new Array(105);
this.layout_y = new Array(105);
this.layout_piece = new Array(105);
for (var cntrcol = 0; cntrcol < 5; ++cntrcol)
{
for (var cntr = 0; cntr < 5; ++cntr)
{
this.layout_x[this.BOARD_LAYOUT[cntrcol][this.BOARD_START_INDEX]+cntr] =
24 * cntr * Math.cos(this.BOARD_LAYOUT[cntrcol][this.BOARD_START_ANGLE_INDEX] * degree) +
this.BOARD_LAYOUT[cntrcol][this.BOARD_START_X_INDEX];
this.layout_y[this.BOARD_LAYOUT[cntrcol][this.BOARD_START_INDEX]+cntr] =
24 * cntr * -Math.sin(this.BOARD_LAYOUT[cntrcol][this.BOARD_START_ANGLE_INDEX] * degree) +
this.BOARD_LAYOUT[cntrcol][this.BOARD_START_Y_INDEX];
this.layout_x[this.BOARD_LAYOUT[cntrcol][this.BOARD_END_INDEX]+cntr] =
24 * cntr * Math.cos(this.BOARD_LAYOUT[cntrcol][this.BOARD_END_ANGLE_INDEX] * degree) +
this.BOARD_LAYOUT[cntrcol][this.BOARD_END_X_INDEX];
this.layout_y[this.BOARD_LAYOUT[cntrcol][this.BOARD_END_INDEX]+cntr] =
24 * cntr * -Math.sin(this.BOARD_LAYOUT[cntrcol][this.BOARD_END_ANGLE_INDEX] * degree) +
this.BOARD_LAYOUT[cntrcol][this.BOARD_END_Y_INDEX];
}
}
for (cntrcol = 0; cntrcol < 5; ++cntrcol)
{
for (cntr = 0; cntr < 11; ++cntr)
{
this.layout_x[this.BOARD_LAYOUT[cntrcol][this.BOARD_HOME_INDEX]+cntr] =
24 * cntr * Math.cos(this.BOARD_LAYOUT[cntrcol][this.BOARD_HOME_ANGLE_INDEX] * degree) +
this.BOARD_LAYOUT[cntrcol][this.BOARD_HOME_X_INDEX];
this.layout_y[this.BOARD_LAYOUT[cntrcol][this.BOARD_HOME_INDEX]+cntr] =
24 * cntr * -Math.sin(this.BOARD_LAYOUT[cntrcol][this.BOARD_HOME_ANGLE_INDEX] * degree) +
this.BOARD_LAYOUT[cntrcol][this.BOARD_HOME_Y_INDEX];
}
}

For testing, we create a copy of our applet specifically for testing the board positions. It will do this by using a loop where a piece goes through every location on the board. This is done in two frames. In the frame we label “Test” we place the following code:

this.test_movie._x = this.layout_x[test_spot]; 
this.test_movie._y = this.layout_y[test_spot]; 

and ten to fifteen frames after the label (so we have time to see the position) we place this code:

++this.test_spot; 
if (this.test_spot >= 105) 
this.test_spot = 0; 
this.gotoAndPlay("Test");

So now we have a board that the players can place pieces on. The next task is to get a head-to-head version of the game working which is what we will be starting on next.


Sunday, March 15, 2020

Making Pent Up Anger Part 1 of 5

Introduction to Board Game

Pent Up Anger is a rather large project so the making of this game will be broken down into 5 different parts (two in the ebook). The game can be found in the Spelchan.com archives at http://spelchan.com/games/y2018/PentUpAnger.php with the source code eventually planned to be posted as part of my https://github.com/BillySpelchan/BlazingPorts repository.

This part will be an overview of board games, why you would want to create a digital version of them, and what the game Pent Up Anger is. This will be followed by Part 2 where we put together the components that make up the game. In part 3 we assemble the parts to create a head to head version of the game. As we want to play the game without other people around, part 4 takes a look at AI and prepares a rudimentary AI opponent. Finally, part 5 builds the user interface components necessary to select the players and whether they are AI or Human players.

I will be releasing a part each month so those of you who are not patient may simply wish to come back after all the parts have been posted, but each part is fairly large so it may be best to follow along as the parts are posted.

Why Digitize Board Games?

Board games are games that are played on a board. There are a huge variety of board games. While card games could be placed in this category, I have placed them in the previous part of the book. In this part of the book we will be looking at games that have some type of playing board.

Some board games are strictly based on luck. These tend to be the track based board games where the goal is to reach an end point by following a track. Players move along the track by rolling a die or dice and moving the amount they rolled along the boards path. Sometimes points on the track will have actions associated with them, such as move back three places. Some may even have spots that require the player to pick up a card, with the card having instructions on it.

Another way luck based games try to make it look like there is more than luck involved in winning is by having points or cash determine the winner. Essentially these types of games are the same as the track game but add some type of points to the game. Points are awarded or lost by entering a specific location or by getting a certain card.

On the opposite end are games that are won strictly by skill. These games start the players off on an even playing field and through the rules of the game determine the winner. The best examples of this type of game is chess, with checkers and go being other good examples.

My favourite category of game is the game that fits in between the two. These are games that have some type of playing field and turn rules as with the skill game, but also deploy some type of random element. The best example of this type of game is backgammon.

Why is the middle ground my favourite? Simply put it allows two players of different skill levels to have fun while still allowing the less skilled player a chance at winning the game. Why is this important? Most people hate losing. What is the point of playing a game if I know I am always going to lose?

One question that a lot of people have is why even bother to create a computer version of a board game when you can just play the game using the board? There are five main reasons that I would do a computerized version of a board game.

The simple answer is ``Convenience''. Let's face it, when you want to play a board game you have to dig out the board, then sort out all the pieces and set up the board before you can even start playing. With the computer, all you have to do is run the software. All the setup work is done for you. For an online game, you have the additional task of going to the website that the game is on, but that is easily book marked.

No lost pieces. Losing a games piece is a fairly common occurrence. I am sure that most people have played a board game using coins or some other non-game object to represent missing pieces. In computer versions, all the pieces are created by the computer and therefore can never be lost.

Fair Referee. Cheating in board games is more common than it should be. Even if no one does cheat, arguments over the rules still happen. On the computer, the rules are coded into the game so there can be no arguments over fair play. Likewise, because the computer controls all the movement of the pieces and exchange of money, no one has to worry about someone ``miscounting'' or making ``adding mistakes''.

Solo Play. It is not always possible to find someone to play a game with. Computers have the ability to take the roll of missing people. While the computer may not be as fun as playing against a real human, it can still be an enjoyable time. More to the point, if you are not familiar with the rules to a particular game, playing a computer version of that game can teach you how to play that game without looking dumb in front of your friends.

Enhancements. In some ways, computers can do things that are not possible with normal board games. Animated sequences are one example. Handling complex rules with ease is another. Strategy board games in particular can benefit by being converted into computer games as most of those games have really complicated rules.

What is Pent Up Anger

Pent up Anger is an original board game that I designed which is loosely based on other board games that I have seen. The figure below shows the game in progress. This game is a traditional track based board game, but with a bit of a twist. First, the players each have five pieces, with the ability to move any piece in a given turn. Second, the game uses an eight sided die. The game's board is pentagon shaped. Each point of the pentagon is a player's starting location. Each player is assigned a different color and has five playing pieces numbered one through five. Their starting gate also has the numbers one through five on it. . The goal is to get all of your pieces from their starting location to their ending location. 



Turns revolve clockwise around the board. Players start their turn by rolling an eight sided dice. Before the player can move, they need to get one of their pieces out of the starting gate. This is done by rolling the number that is assigned to the piece. Players can only move or start once piece a turn. Any piece that is on the board can be moved as long as the move will not take the piece past the player's loading zone. By giving the player control over multiple pieces and adding the ability to send opponents back to the start a bit of skill is added to the game. If the player lands on an opponent's piece, the opponent's piece gets taken back to that player's starting gate.

The loading zone is a special four square line on the board that starts just before the players starting point. Once the player's piece has landed in the loading zone, the piece is able to leave the board. To leave the board, the number of the piece must be rolled.

Players win the game once all their pieces have been removed from the board.

Next month I will take al look at how to build the different pieces that make up the game.

Saturday, February 15, 2020

Leap Year Leap Postmortem

My post last month somehow ended up on the wrong blog (probably too much of a rush and I didn't pay attention when posting). The link to part 2 of making video poker is at http://blazinggames.blogspot.com/2020/01/video-poker-part-2.html.

The source code for Leap Year Leap is at https://github.com/BillySpelchan/BlazingPorts if anybody is interested. I am planning on slowly adding code of the other games I port to that repository.

Leap Year Leap is a leap year game that I originally released back in 2008 (on February 29th), and then released as open source in 2012. This is a Flash game using the really old version of ActionScript but this was not necessarily a bad thing.  The game used an old-school technique for faking 3D. Namely taking advantage of sprite scaling to draw sprites larger as they approach you.
For the HTML5 port I decided that I would do the game using my own library. Interesting, the BGLayers library I wrote was written in 2010 so if I would have had a bit more foresight, I could have done the HTML5 version way back in 2012. Granted, back then HTML5 was not a completed standard so support for the canvas tag and API was limited.

I was expecting the port to only take a few hours, but it ended up taking about twice as long as I anticipated. This may be partially due to not having that much free time to work on the game so one quickly loses track of things when there is long periods of time between work sessions.

What Went Right - Software 3D code ported easily.


While a large amount of the game was re-written from scratch, the main scaling logic and the jumping logic for the game was pretty much ported verbatim.  This allowed me to get the game up and running quickly and the development time would have been substantially longer without this tiny amount of code.

 The 3D logic is somewhat correct with the scale of the object being determined based on how far away from the player it is. The jump logic is physics based using momentum and gravity to simulate the jump. Interestingly, the code breaks the physics into micro-intervals and performs many calculations to keep the jump as consistent as possible even with delta-based timing. The idea here is that the physics is calculated independently of the image so the time between the last physics event and the current one result in several discrete steps that the program processes. By having physics in intervals, you get a bit more consistency with the motion. While the number of steps I used was probably way more than necessary, it is interesting that more modern engines use a similar approach to physics.

What Went Wrong - No bi-linear or Tri-linear filtering

The Flash player did a surprisingly good job of scaling images, though this probably had more to do with use of vector-based images than the actual image scaling. As I am using images and scaling them using the canvas default scaling methods, the results are not as good. The canvas scaling results in images that tend to flicker in the distance as different scanlines of the image are drawn at different scales. This use to be a big problem for 3D graphics cards, with the solution being bi-linear and tri-linear filtering. The idea behind these rendering approaches is that instead of having a single image, you have multiple images at different distances. Finding the appropriate image and swapping it in results in much better scaling. Of course, you can’t have every possible size of image unless you want to use a lot of storage space for the many versions of the image that would be needed so instead you rely on filtering techniques. These take samples of the images that are near the correct size and set the color of each pixel of the scaled image based on the average of these samples.

Software filtering is certainly possible but would take far too long to do.  A better solution, which I will likely implement in the 2024 version of the game, is to use the 3D card to do the scaling work for you. While I have done some work with OpenGL and Direct-3D, I have not really done much with WebGL. I suspect that it would be fairly like the work that I have already done but simply don’t have the time to learn a new graphics API. This is something that I will be doing eventually, when I actually start having more free time.

Mixed Blessings – BGLayers

While I certainly could have used Create.js for the library, for such a simple game it is way too much overkill. Using software libraries that are multiple times the size of the project when you are only using a tiny fraction of the libraries features seems wasteful. More to the point, I like writing my own code and still want to develop my own engine so why not use my own library. The advantage is that it is significantly smaller than the Create.js libraries and I have total control of everything. The disadvantage is that it was written back in 2012 when ECMAScript 6 was non-existent. 

While there are clunky aspects to my BGLayers library, it works surprisingly good for its size. When I have the time, I am going to have to re-write this library using the proper class syntax that ECMAScript 6 uses to make for working with the library and development of games much nicer. I would probably divide this into a canvas and a WebGL version.

Conclusion - Plans for 2024

Overall, this is not too bad of a port for the game. As mentioned above, for the next leap year, I will want to do an even better version of the game. At a minimum, this would switch to a more modern version of JavaScript so rewriting, or more likely a re-imagining, will be in order. It would also probably use the WebGL API so that I can properly handle 3D elements and be able to take advantage of the filtering options to result in smoother looking results. A lot more background objects, and possibly a road that goes from a dirt trail to a modern highway as you advance through the years would be nice but that is probably pushing it unless those things happen to be developed in a different project.

Sunday, December 15, 2019

Video Poker part 1

This is the first half of Chapter 8 of my "Creating HTML5 Games Using AnimateCC" eBook that I was releasing on my Blazing Games Development Blog but am now going to be posting here as I am now just going to have a single blog. For earlier posts in the series, visit the other blog. Unlike earlier posts, I want longer form posts so will be posting the first half of the chapter this month and next month will be posting the second half (instead of having 8 sections spread out).

Chapter 8 - Video Poker (part 1)

Game Layout

Video Poker is a simulation of a video-based gambling game found at many casinos. As such, it makes sense to have a background that reflects this fact by making the game display look like a cabinet with a monitor in it. This is done in two layers. The “Screenback” layer holds the screen and the “Console” layer holds the console (outer part of the machine). The figures below shows the “Screenback” layer and the “Console” layer.


The screen background layer (“Screenback”) is a radial gradient filled rectangle using shades of green to give the impression of older CRT displays. Perhaps this aesthetic reflects my age as pretty much any casino that you go into today will have more modern LCD or better displays. I like the older look, but that could be a reflection of your age. Choose the aesthetic that you, or better yet your target audience, would prefer.



The games are housed in a cabinet which I originally called a console thinking of the term for video game systems not the proper term for the physical machines but I only realized the mistake well after the game was finished so am leaving the incorrect terminology in the code. If in the future I was going to alter the code, a refactoring step to properly rename the layer may be worth the effort.

In order to actually play the game, we are going to need a few more layers. The layers used in the movie are “Code,” “Info,” “Bet,” “Console,” “FRCard,” “RCard,” “CCard,” “LCard,” “FLCard,” and “Screenback.” The combination of these layers results in our final layout as can be seen in figure below.



The Code layer is where we place our code and labels. The “Console” and “Screenback” layers were described above. The “FRCard” layer holds the card on the far right. The “RCard” layer holds the card on the right. And so on. We simply place a card object on each of the layers. The card instances are named, “FLCard\_movie,” “LCard\_movie,” “CCard\_movie,” “Rcard\_movie,” and “FRCard\_movie.” To make sure the cards are aligned vertically and spaced evenly, you can use the align submenu under the modify menu. To use this, select the objects you want to align by clicking on them while the shift key is down and then choose the alignment option of your choice.

Now, the info layer is going to contains a line of text that gives players instructions and results. Quite simply, we create this layer by creating a dynamic text object using a red 50 point “\_sans” font and naming the instance “results\_txt.” We also create dynamic text objects for the bet, last win and current balance. These will be created using a green 20 point “\_sans” font. The instances will be named “bet\_text,” “win\_txt,” and “balance\_txt.” Later on we will be adding Draw movies to this layer.

The bet layer is mostly blank. It only appears when the bet buttons are active. The rest of the time the player will only see the non-functioning buttons that are part of the console image.

We want to make sure that we import our deck class. This is done by going to the actions panel. Within that panel you can specify which scripts you wish to add to the project. Selecting the script option lets you add scripts to the game. The order of the scripts is important as it determines the loading order of the scripts so if one script depends on another script you may need to make sure the depended-on script is loaded first.

This leads to the problem of where to place the code. As with the NIM game, we are opting to write the code in the provided script section which has the advantage of keeping all the game logic within the .fla file but as we are loading an external file for the card library, some of you may be wondering if it would be possible to keep the code outside of flash. The answer to this is yes, and it is something that we will be doing with some of the other projects in this book.

Betting


Video poker, and poker in general for that matter, is a casino game. This means that betting is an important aspect of the game. In a casino, the video poker games I have seen are based around a unit of currency. That unit, be it nickles, quarters, or dollars is the amount of a bet. Most machines allow for more than one unit be bet at a time. I have decided that my virtual machine will allow for 1 to 5 units to be used.

As you seen last chapter, the background console already has buttons drawn. These are not usable. What we are going to do is create a button class that looks like the console button but lit up. This is a common casino convention to let the player know what options are currently selectable. This lit up button will be placed over top the console image so to the user it will appear as if the console has lit up the button. Figure \ref{fig:betbuttons} shows the four frames that make up one of the buttons.



Placing the buttons over their corresponding console button is simply a matter of zooming in the image and using the cursor keys to finely position the buttons. The button instance names are labeled “bet1\_btn,” “bet2\_btn,” “bet3\_btn,” “bet4\_btn” and “bet5\_btn.” Now we are ready to start adding code.

Within the global script player we start by creating the constructor function for our videoPokerGame class which will have additional functions added to it This code simply sets the players cumulative winnings to 0, the amount of the last win to 0, and creates a deck of cards using the card library that was created in the previous chapter.

// Global Scripts
videoPokerGame = new VideoPokerGame();
function VideoPokerGame()
{
console.log("Created Video Poker Game Instance");
this.cash = 0;
this.lastWin = 0;
this.myDeck = new spelchan.Deck();
}

One issue that I came across when first experimenting with Adobe Animate CC was when trying to access the stage variable so I could access variables in the movie clip that is currently active.  There may be a better way of doing this, but my quick solution is to simply pass the MovieClip instance to the initGame function whenever a game is being initialized.

The initGame function sets up base game variables, resets the current instructional message for the game, then sets up the cards and the listeners for the cards. The card values are stored in a hand array registering the appropriate MovieClip representation of the card. Each card has a draw message tied to it as well to let the player know which cards are going to be drawn. These are stored in the drawMovies array. .

VideoPokerGame.prototype.initGame = function(vpMovie) 
{
this.vpMovie = vpMovie;
this.selecting = false;
this.bet = 0;
this.message = "?";
this.hand = new Array(
new spelchan.Card(vpMovie.FLCard_movie),
new spelchan.Card(vpMovie.LCard_movie), 
new spelchan.Card(vpMovie.CCard_movie), 
new spelchan.Card(vpMovie.RCard_movie), 
new spelchan.Card(vpMovie.FRCard_movie)
);
this.drawMovie = new Array(vpMovie.draw1_movie, vpMovie.draw2_movie, vpMovie.draw3_movie,
vpMovie.draw4_movie, vpMovie.draw5_movie);
for (var cntr = 0; cntr < 5; ++cntr)
{
this.drawMovie[cntr].visible = false;
this.hand[cntr].cardMovie.addEventListener("click", this.handleCardClick.bind(this, cntr));
}
}

The initialization sets the message by calling an updateText function which not only displays the indicated message but also updates the betting, player cash balance, and the last amount that the player has won. This is done by simply setting the text value of the appropriate text objects that were used to make the text.

VideoPokerGame.prototype.updateText = function()
{
this.vpMovie.results_text.text = this.message;
this.vpMovie.bet_text.text = "Betting: " + this.bet;
this.vpMovie.balance_text.text = "Balance: " + this.cash;
this.vpMovie.win_text.text = "Last Win: " + this.lastWin;
}

The card MovieClips have an event listener attached to them. This simply sees if we are in a part of the game where you can select cards for the card draw and if so toggles whether that card should be drawn.

VideoPokerGame.prototype.handleCardClick = function(n, event) {
if (this.selecting != true)
return;
console.log("Should be toggling draw for slot " + n);
this.drawMovie[n].visible = !this.drawMovie[n].visible;
}

The code to call the game initialization needs to be added to the second frame of the games’ timeline on the Code layer. The easiest way of doing this is to right-click on the frame in the timeline and add a blank keyframe if one does not exist then right-click on that blank keyframe and select actions which should open the code editor for that frame. Once you have code on a frame, simply selecting it from the list of code segments on the left of the action window will let you quickly select the frame for which you wish to edit code. The code on this frame is simply a call to the global videoPokerGame game calling the initGame function that we created above.

videoPokerGame.initGame(this);

The third frame of the code layer we label “BetWait.” This will be the location the movie moves to whenever the player is required to make another bet. To handle the betting the frame calls a method in the global VideoPokerGame instance. The code to place on frame 4 is a simple function call.

videoPokerGame.startWaitForBets();


This function doesn’t exist in our VideoPokerGame class so we need to create it. The first thing the function needs to do is set up the message to a "Please make a bet..." message. We then make sure that none of the draw labels are visible by loping through them and turning off their visibility. The movie playback is stopped so that this frame will be shown until a bet has been made. This is where things get rather interesting. JavaScript handles scope a bit different from other object-oriented languages and as a result a call to a method within a class will be called with the wrong value for the this variable. To correct for this, we need to bind the correct reference to use. This information needs to be saved so that when we remove the event listener we are removing the proper listener.

The fact that we are binding things to the event call actually makes things a bit easier than they were In ActionScript as you are then able to add additional parameters to the function call so that the same handler can more easily handle multiple events. In our case we are going to have a handleBet event handler which will take the amount of the bet as it’s parameter.

Once the bindings are created, we simply add a “click” event listener to each of the five buttons using the boundedBet tied to that button.

VideoPokerGame.prototype.startWaitForBets = function(){
this.message = "Please make a bet...";
this.updateText();
for (var cntr = 0; cntr < 5; ++cntr)
{
this.drawMovie[cntr].visible = false;
}
this.vpMovie.stop();
// create bindings for bets
this.boundBet1 = this.handleBet.bind(this, 1);
this.boundBet2 = this.handleBet.bind(this, 2);
this.boundBet3 = this.handleBet.bind(this, 3);
this.boundBet4 = this.handleBet.bind(this, 4);
this.boundBet5 = this.handleBet.bind(this, 5);
// listen for bets
this.vpMovie.bet1_btn.addEventListener("click", this.boundBet1);
this.vpMovie.bet2_btn.addEventListener("click", this.boundBet2); 
this.vpMovie.bet3_btn.addEventListener("click", this.boundBet3);
this.vpMovie.bet4_btn.addEventListener("click", this.boundBet4);
this.vpMovie.bet5_btn.addEventListener("click", this.boundBet5);
}

When a bet has been made, the handleBet function get called with the amount of the bet. It simply records the amount of the bet, removes the event listeners from the bet buttons, clears the message, adjusts the player’s cash balance, then starts the game timeline which will advance into the ClearCards section of the game movie.

VideoPokerGame.prototype.handleBet = function(bet, event) {
this.bet = bet;
console.log("Made a bet of " + this.bet);
this.vpMovie.bet1_btn.removeEventListener("click", this.boundBet1);
this.vpMovie.bet2_btn.removeEventListener("click", this.boundBet2); 
this.vpMovie.bet3_btn.removeEventListener("click", this.boundBet3);
this.vpMovie.bet4_btn.removeEventListener("click", this.boundBet4);
this.vpMovie.bet5_btn.removeEventListener("click", this.boundBet5);
this.message = " ";
this.cash -= bet;
this.updateText();
this.vpMovie.play();
}


Revealing the Hand


The revealing of the initial drawing of cards is done in three phases. The first phase the cards are removed from the game play field. This is simply a matter of moving the cards, each card separated by a few frames, from it's current position to a position along the top of the screen while changing the size of the card to 20\%. This is done in the movie section labeled “ClearCards.” I placed the moves in frames 5, 8, 11, 14, and 17. A shuffle sound is added to the “Sound” layer to play a shuffling sound whle the cards are being removed. The figure below shows the timeline for the dealing phase of the game.



On frame 20 of the code layer we create a keyframe labeled “Deal.” In frame 20 we also call our video poker game instance to deal the cards. We also need to add a draw sound on frame 20, 25, 30, 35, and 40. The code on frame 20 is simply a call to our deal method.

videoPokerGame.deal();

The code for handling the dealing is in the global script.  The deal function simply makes use of the card library we created in the previous chapter to shuffle the deck then grabs the first five cards off the deck. The card is set to show the face just in case the face wasn’t showing.

VideoPokerGame.prototype.deal = function()
{
var cntr;
this.myDeck.shuffle();
for (cntr = 0; cntr < 5; ++cntr)
{
this.hand[cntr].setCard(this.myDeck.draw());
this.hand[cntr].showFace();
}
}

Finally we animate the cards going from their top position to their proper final locations. What I do is stagger the starting frame of the reveal animation by five frames, yet have the reveal animation take 10 frames. In other words, we have starting frames of 20, 25, 30, 35 and 40. Each card moves from the hidden spot at the top to it’s proper position and at the same time returns to it’s normal size. This is a simple motion tween for all five of the cards.

Next half of the chapter will be released next month where we implement the selection and scoring of hands.