Sunday, December 15, 2019
Video Poker Part 1
As I only want to deal with 1 blog, I am posting the first half of chapter 8 of my "Creating HTML5 Games using AnimateCC" eBook at https://homebrewgamejam.blogspot.com/2019/12/video-poker-part-1.html where we cover the creation of my Video Poker game.
Saturday, October 19, 2019
Porting Halloween Liche
My first real post and for some reason it is not showing up on my home page. For those who are interested in learning how I ported Halloween Liche from Flash to HTML5, the link is http://spelchan.ca/?p=10 I will continue fighting with wordpress but if I keep having issues will have to come up with a new plan.
Saturday, October 5, 2019
When Blogs Collide
I have concluded that having two separate blogs is just too big of a pain. I am also thinking that posting chapters one section at a time is not the best approach. If I was to post entire chapters at a time would be more useful to anyone wanting to read my work. This obviously means that I will not be posting the new blog every week but instead will be cutting down to a long post once a month. Chapters from my animate (and possibly create.js) eBook will be posted once every 3 to 4 months, with posts on other subjects in between the chapter posts. The in-between posts will be about Spelchan.com content, game-jam or home-brew content, and articles related to what I am researching with the odd miscellaneous soapbox post appearing related to whatever thing got me angry enough to write a post.
This leads to the next question as to where these posts will appear. While I have nothing against blogger, I would prefer that it was on a site that I control. For that reason I set up WordPress on my Spelchan.ca site so my blog posts will appear on Spelchan.ca while my games appear on Spelchan.com. For the next while, I will probably be posting TLDR summaries on this blog for a while.
The first post will be on Halloween Liche and will be posted in the middle of October.
This leads to the next question as to where these posts will appear. While I have nothing against blogger, I would prefer that it was on a site that I control. For that reason I set up WordPress on my Spelchan.ca site so my blog posts will appear on Spelchan.ca while my games appear on Spelchan.com. For the next while, I will probably be posting TLDR summaries on this blog for a while.
The first post will be on Halloween Liche and will be posted in the middle of October.
Saturday, September 21, 2019
Creating the Deck class
Last section we created tests for building our deck class. Now we are ready to create a deck class. Initially we will create the code within the testDeck.html file but once it is functional move the code into the Deck.js file so it can be used by our various card projects. While it is certainly possible to create the code entirely within the Deck.js file and import that file, for prototyping it is often faster to write the code within the test file and iterate over the code before moving it to the appropriate class as during prototyping the structure of the code may change multiple times so keeping it outside of the main code-base until it is stable can make maintaining the project easier.
This class needs to hold 52 cards in a deck, deal out those cards, and shuffle those cards. First, we are going to need to create the constructor function for this class. This will just create an array for itself to hold the deck and fill that array with in-order values. We also set the index for where we are going to grab cards to the top of the deck.
spelchan.Deck = function()
{
this.cardArray = [];//new Array(52);
for (var cntr = 0; cntr < 52; ++cntr)
this.cardArray[cntr] = cntr + 1;
this.nextCardIndex = 0;
}
This means that we now have a deck of cards but running the test will still fail. While the card ids are in the deck, the deal method is not dealing them out! Dealing out a card is simply the matter of returning the card at the nextCardIndex while increasing the index.
spelchan.Deck.prototype.draw = function()
{
var rv = this.cardArray[this.nextCardIndex];
++this.nextCardIndex;
return rv;
}
Running the tests now show us that we are getting there but the shuffling is not sufficiently random enough to pass our test. This is because we are not shuffling the deck yet. We are going to need a way of shuffling the deck. Think about the different ways to shuffle a deck. There are many ways of shuffling, but most of them are inefficient as far as the computer is concerned. What our goal is, simply stated, is to make the cards in the deck appear in a random order. I realized that taking each card and swapping it at random with another card would be a very good way of shuffling as the computer can do this blindingly fast with really good results. While I came up with this algorithm on my own, my Algorithms teacher did tell me that I was not the first person to think of this and that this is like the technique that shuffling machines use.
spelchan.Deck.prototype.shuffle = function()
{
var cntr, temp, rnd;
for (cntr = 0; cntr < 52; ++cntr)
{
rnd = Math.floor(Math.random() * 52);
temp = this.cardArray[cntr];
this.cardArray[cntr] = this.cardArray[rnd];
this.cardArray[rnd] = temp;
}
this.nextCardIndex = 0;
}
Now when we run the test we see that all the tests have passed. We are now ready to start planning the tests we will be needing for a video poker game. There are other things that we could probably add to this class, but I have discovered over my years that it is easy to refactor and to add things later, especially if you have a testing framework to verify your changes don’t break anything. One tenant of Extreme Programming is to only write the code that you need. We have all that we need for video poker, so next chapter we will start working on a video poker game!
This class needs to hold 52 cards in a deck, deal out those cards, and shuffle those cards. First, we are going to need to create the constructor function for this class. This will just create an array for itself to hold the deck and fill that array with in-order values. We also set the index for where we are going to grab cards to the top of the deck.
spelchan.Deck = function()
{
this.cardArray = [];//new Array(52);
for (var cntr = 0; cntr < 52; ++cntr)
this.cardArray[cntr] = cntr + 1;
this.nextCardIndex = 0;
}
This means that we now have a deck of cards but running the test will still fail. While the card ids are in the deck, the deal method is not dealing them out! Dealing out a card is simply the matter of returning the card at the nextCardIndex while increasing the index.
spelchan.Deck.prototype.draw = function()
{
var rv = this.cardArray[this.nextCardIndex];
++this.nextCardIndex;
return rv;
}
Running the tests now show us that we are getting there but the shuffling is not sufficiently random enough to pass our test. This is because we are not shuffling the deck yet. We are going to need a way of shuffling the deck. Think about the different ways to shuffle a deck. There are many ways of shuffling, but most of them are inefficient as far as the computer is concerned. What our goal is, simply stated, is to make the cards in the deck appear in a random order. I realized that taking each card and swapping it at random with another card would be a very good way of shuffling as the computer can do this blindingly fast with really good results. While I came up with this algorithm on my own, my Algorithms teacher did tell me that I was not the first person to think of this and that this is like the technique that shuffling machines use.
spelchan.Deck.prototype.shuffle = function()
{
var cntr, temp, rnd;
for (cntr = 0; cntr < 52; ++cntr)
{
rnd = Math.floor(Math.random() * 52);
temp = this.cardArray[cntr];
this.cardArray[cntr] = this.cardArray[rnd];
this.cardArray[rnd] = temp;
}
this.nextCardIndex = 0;
}
Now when we run the test we see that all the tests have passed. We are now ready to start planning the tests we will be needing for a video poker game. There are other things that we could probably add to this class, but I have discovered over my years that it is easy to refactor and to add things later, especially if you have a testing framework to verify your changes don’t break anything. One tenant of Extreme Programming is to only write the code that you need. We have all that we need for video poker, so next chapter we will start working on a video poker game!
Saturday, September 7, 2019
Test Driven Deck
While having a plan for testing your code is important, Test Driven Development (TDD) takes this to another level. The idea here is that you write automated tests before you start writing the code. When it is practical to do this, it is an incredibly good way of creating code. Planning tests gets you thinking about the code you are going to write – hopefully with an idea of the fringe cases that you are going to encounter. Writing the tests give you something to check the code against. All tests should initially fail, with a successful test likely indicating either an error with the test or an error with the test plan.
You then write the code and run it against the tests trying to pass one test at a time. Once you have passed all the tests and no missing tests have been discovered, you are finished the code and can start planning the tests for the next piece of code that you need to write. Having automated tests also means that it is easy to have the tests running frequently while you do other things and if something breaks then you know right away and as it is likely what you (or someone on your team) is currently working on, it will be trivial to fix the bug! Remember that in general the quicker you can find a bug, the less it will cost to fix it. This cost is in time, but can also be in money if the bug is in a production version and you have marketing and patching costs in addition to the cost of finding and fixing a bug.
We have a card class that can display any card, so what we need next is a deck of cards. This deck needs to be able to be shuffled and we need to be able to deal cards from the deck. So, how would we test such a beast?
In a sorted deck, the cards should be from 1 to 52 so simply drawing cards from a sorted deck and making sure they are in sequence would solve this problem. A shuffled deck, however, has two issues that we need to check for. First, we want to make sure that all the cards are in the shuffle (that we haven’t duplicated cards losing some cards or other similar problem). Next we want tom make sure the cards are not in order. Simply checking to see the card is different from its position in the deck will not work as we would expect that at least some of the time a randomly shuffled card would end up in the proper deck position. A good shuffle would have at least half the cards in a different position so simply counting how many cards don’t match would suffice most of the time.
As the deck class can be written without the card class, as it uses card IDs and not instances of cards, it is possible to write the deck class in its own html file which I called deckTest. This starts off with your typical html5 boilerplate followed by a simple version of the Deck class with none of the necessary methods implemented.
Deck JavaScript Test
Now some of you may have noticed that there is a lot of test code here. This is the downside to test driven development. You will often end up with test code that is the same size as the code that you are testing, and sometimes even larger. The plus side is that you know your code works within the testing parameters and if you refactor or change code you will be able to check to make sure that nothing you have done is broken. Manual testing could have been done with a lot less code. As always there is a trade-off that must be made. In a solo environment, and possibly a small team, manual testing may be adequate and may be productive enough. As you start to get to larger teams, people inadvertently mucking up other people’s code happens a lot more often than you would expect.
You then write the code and run it against the tests trying to pass one test at a time. Once you have passed all the tests and no missing tests have been discovered, you are finished the code and can start planning the tests for the next piece of code that you need to write. Having automated tests also means that it is easy to have the tests running frequently while you do other things and if something breaks then you know right away and as it is likely what you (or someone on your team) is currently working on, it will be trivial to fix the bug! Remember that in general the quicker you can find a bug, the less it will cost to fix it. This cost is in time, but can also be in money if the bug is in a production version and you have marketing and patching costs in addition to the cost of finding and fixing a bug.
We have a card class that can display any card, so what we need next is a deck of cards. This deck needs to be able to be shuffled and we need to be able to deal cards from the deck. So, how would we test such a beast?
In a sorted deck, the cards should be from 1 to 52 so simply drawing cards from a sorted deck and making sure they are in sequence would solve this problem. A shuffled deck, however, has two issues that we need to check for. First, we want to make sure that all the cards are in the shuffle (that we haven’t duplicated cards losing some cards or other similar problem). Next we want tom make sure the cards are not in order. Simply checking to see the card is different from its position in the deck will not work as we would expect that at least some of the time a randomly shuffled card would end up in the proper deck position. A good shuffle would have at least half the cards in a different position so simply counting how many cards don’t match would suffice most of the time.
As the deck class can be written without the card class, as it uses card IDs and not instances of cards, it is possible to write the deck class in its own html file which I called deckTest. This starts off with your typical html5 boilerplate followed by a simple version of the Deck class with none of the necessary methods implemented.
test results go here
Now some of you may have noticed that there is a lot of test code here. This is the downside to test driven development. You will often end up with test code that is the same size as the code that you are testing, and sometimes even larger. The plus side is that you know your code works within the testing parameters and if you refactor or change code you will be able to check to make sure that nothing you have done is broken. Manual testing could have been done with a lot less code. As always there is a trade-off that must be made. In a solo environment, and possibly a small team, manual testing may be adequate and may be productive enough. As you start to get to larger teams, people inadvertently mucking up other people’s code happens a lot more often than you would expect.
Saturday, August 24, 2019
The Importance of Testing
Before you write any code you should have a way in your mind to test the code in order to make sure that the code does what you want. There are many types of tests but when you get right down to it, all tests are either manual or automated. Manual tests tend to be the easiest to implement as they just require some code that can be observed to be doing the correct thing. As games tend to be dynamic in nature, manual testing is very common in game development as coming up with automated tests is not always practical. Automated tests, however, are always preferable when possible to do so due to the simple fact that people do not have the time to go through hours of manual testing just to make a minor change. This means that most manual tests will only be run on rare occasions so that something may be broken for months before it is discovered making finding out why it broke difficult.
Due to the visual nature of the cards, automatic testing is not really that practical so we will resort to manual testing. More to the point, as the cards are poignant to the game, any problems with the card class will be detected immediately so manually testing them is not much of a risk. A very simple test program can be created to make sure that the card class works the way it is supposed to.
Create a new “CardTest” movie for holding the test. Copy the Card movie clip into this movie. This can be done by having a file with that movie open in another tab then in the library tab selecting that file and dragging the Card movie onto the stage. Make sure that the layer holding the card extends to the second frame. Add a layer for holding code and in the second frame create a blank keyframe in the code layer. Right-click and chose add actions to bring up the code editor for editing JavaScript on that frame. Here is the test code:
var firstCard = new spelchan.Card(this.firstCardMovie);
firstCard.setCard(1);
this.firstCardMovie.addEventListener("click", nextCard);
this.stop();
function nextCard(e) {
if (firstCard.faceShowing)
firstCard.setCard(firstCard.cardID + 1);
else
firstCard.showFace();
console.log("face: " + firstCard.getFaceValue() +
" suit: " + firstCard.getSuit());
}
While in the actions editor, make sure to add the Deck.js file to the includes by expanding the global list of scripts then selecting the include option and clicking on the + to add a script. Browse to find the script.
You can now simply click on the card to show the first card in the deck and keep clicking on the cards to loop through all the cards that make up a deck. This is a very simple test but one that confirms that the Card class is working as expected. Proponents of the technique known as test driven development would start with the test code and then write the actual code as we will see when creating the deck class that deals with handling a deck of cards.
Due to the visual nature of the cards, automatic testing is not really that practical so we will resort to manual testing. More to the point, as the cards are poignant to the game, any problems with the card class will be detected immediately so manually testing them is not much of a risk. A very simple test program can be created to make sure that the card class works the way it is supposed to.
Create a new “CardTest” movie for holding the test. Copy the Card movie clip into this movie. This can be done by having a file with that movie open in another tab then in the library tab selecting that file and dragging the Card movie onto the stage. Make sure that the layer holding the card extends to the second frame. Add a layer for holding code and in the second frame create a blank keyframe in the code layer. Right-click and chose add actions to bring up the code editor for editing JavaScript on that frame. Here is the test code:
var firstCard = new spelchan.Card(this.firstCardMovie);
firstCard.setCard(1);
this.firstCardMovie.addEventListener("click", nextCard);
this.stop();
function nextCard(e) {
if (firstCard.faceShowing)
firstCard.setCard(firstCard.cardID + 1);
else
firstCard.showFace();
console.log("face: " + firstCard.getFaceValue() +
" suit: " + firstCard.getSuit());
}
While in the actions editor, make sure to add the Deck.js file to the includes by expanding the global list of scripts then selecting the include option and clicking on the + to add a script. Browse to find the script.
You can now simply click on the card to show the first card in the deck and keep clicking on the cards to loop through all the cards that make up a deck. This is a very simple test but one that confirms that the Card class is working as expected. Proponents of the technique known as test driven development would start with the test code and then write the actual code as we will see when creating the deck class that deals with handling a deck of cards.
Saturday, August 10, 2019
Creating the Card Class
We will place all the code for the Card movie in an external JavaScript file. For some strange reason, Animate CC 2017 does not let you edit external JavaScript files (hopefully an over-site that will be fixed in future versions) so another editor will have to be used for editing the JavaScript file. There are numerous editors available that support JavaScript, with Notepad++ being the editor of choice for me when I am using a windows machine.
Before we can create the card class, however, we are going to want to create a separate namespace for holding our classes so that there are no conflicts with any other code that we are using. The easiest way of creating a namespace is simply to create a root object with the name of the namespace we wish to use. This can be done as follows:
spelchan = spelchan | {};
You should already be familiar with the new operator, which is used for creating instances of a class. The format for this is
new constructor([param1,...,paramn]);
What is happening is the new operator is trying to find a constructor function named whatever name was provided with the number of parameters indicated. Some constructor functions, such as Array, are built right in to JavaScript. It is, however, possible to create new Constructor functions by simply having a function named whatever it is you want to call the constructor. Convention has it that you start constructor functions with a capital letter. This is a good idea as it distinguishes them from other functions.
Constructors can have no parameters, or as many parameters as you desire. Here is the constructor function for our card class. Notice that it takes a reference to the movie clip that it will be controlling. We could have had the class create the movie clip but by passing the movie clip we make it easier to attach objects from the Animate CC editor to our class.
spelchan.Card = function(cardMovie) {
this.cardMovie = cardMovie;
this.cardID = 0;
this.faceShowing = false;
this.cardMovie.gotoAndStop(9+this.cardID);
}
As a class consists of data and the methods used to manipulate the data, the above constructor sets up a holder for the card movie, the id of the card, and a Boolean flag that indicates if the card is being shown. By default, the card is blank and is not being shown to the user. To set the card and show the card, we need to have some methods. This is where JavaScript gets kind of weird.
All classes are given a prototype object that holds functions and other variables that are available to any instance of that class. To add a function to a class, you need to add the function to the prototype object. This can be done two ways. First, you can create the function directly in the constructor by assigning the function name to the code for a function. The other way is to assign a function to the prototype, by using classname.prototype.functionname = function(...) { ... };
Let us implement the setCard and getCard methods. When the card’s value is changed, the card has to go to the proper frame of the movie and stop. However, if the card’s face is not showing, we show the back image instead. Getting the card value is simply the matter of returning the cardID variable.
// n is the cardID for the card
spelchan.Card.prototype.setCard = function(n)
{
if ((n < 1) || (n > 52))
this.cardID = 0;
else
this.cardID = n;
if ((this.cardID == 0) || (this.faceShowing == false))
this.cardMovie.gotoAndStop(1);
else
this.cardMovie.gotoAndStop(9+this.cardID);
}
// returns the cardID for the card
spelchan.Card.prototype.getCard = function()
{
return this.cardID;
}
We now have the ability to change the card but as the face is not being shown, we have no way of verifying this. Showing a card is simply a matter of setting the faceShowing variable to true and going to the appropriate frame. The only complication is the fact that we need to handle a card that has yet been assigned a value. Hiding the face is even easier as we set faceShowing to false then stop on the blank card frame.
// shows the face side of the card
spelchan.Card.prototype.showFace = function()
{
this.faceShowing = true;
if (this.cardID == 0)
this.cardMovie.gotoAndStop(1);
else
this.cardMovie.gotoAndStop(9+cardID);
}
// shows the back of the card
spelchan.Card.prototype.hideFace = function()
{
this.faceShowing = false;
this.cardMovie.gotoAndStop(1);
}
This is all that is needed for a card class, but creating a couple of utility methods for getting the face of the card and the suit of the card is easy enough to do. This is done using math. The modulus function, which uses the % operator, gives you the remainder of a division. Had we started counting from 0, this would work great, but as we didn’t subtracting one from the card id lets us use modulus to get the face value from 0 to 12 and adding 1 corrects this. A similar technique can be used to determine which of the four suits are being used by seeing which group of 13 the card falls into.
Before we can create the card class, however, we are going to want to create a separate namespace for holding our classes so that there are no conflicts with any other code that we are using. The easiest way of creating a namespace is simply to create a root object with the name of the namespace we wish to use. This can be done as follows:
spelchan = spelchan | {};
You should already be familiar with the new operator, which is used for creating instances of a class. The format for this is
new constructor([param1,...,paramn]);
What is happening is the new operator is trying to find a constructor function named whatever name was provided with the number of parameters indicated. Some constructor functions, such as Array, are built right in to JavaScript. It is, however, possible to create new Constructor functions by simply having a function named whatever it is you want to call the constructor. Convention has it that you start constructor functions with a capital letter. This is a good idea as it distinguishes them from other functions.
Constructors can have no parameters, or as many parameters as you desire. Here is the constructor function for our card class. Notice that it takes a reference to the movie clip that it will be controlling. We could have had the class create the movie clip but by passing the movie clip we make it easier to attach objects from the Animate CC editor to our class.
spelchan.Card = function(cardMovie) {
this.cardMovie = cardMovie;
this.cardID = 0;
this.faceShowing = false;
this.cardMovie.gotoAndStop(9+this.cardID);
}
As a class consists of data and the methods used to manipulate the data, the above constructor sets up a holder for the card movie, the id of the card, and a Boolean flag that indicates if the card is being shown. By default, the card is blank and is not being shown to the user. To set the card and show the card, we need to have some methods. This is where JavaScript gets kind of weird.
All classes are given a prototype object that holds functions and other variables that are available to any instance of that class. To add a function to a class, you need to add the function to the prototype object. This can be done two ways. First, you can create the function directly in the constructor by assigning the function name to the code for a function. The other way is to assign a function to the prototype, by using classname.prototype.functionname = function(...) { ... };
Let us implement the setCard and getCard methods. When the card’s value is changed, the card has to go to the proper frame of the movie and stop. However, if the card’s face is not showing, we show the back image instead. Getting the card value is simply the matter of returning the cardID variable.
// n is the cardID for the card
spelchan.Card.prototype.setCard = function(n)
{
if ((n < 1) || (n > 52))
this.cardID = 0;
else
this.cardID = n;
if ((this.cardID == 0) || (this.faceShowing == false))
this.cardMovie.gotoAndStop(1);
else
this.cardMovie.gotoAndStop(9+this.cardID);
}
// returns the cardID for the card
spelchan.Card.prototype.getCard = function()
{
return this.cardID;
}
We now have the ability to change the card but as the face is not being shown, we have no way of verifying this. Showing a card is simply a matter of setting the faceShowing variable to true and going to the appropriate frame. The only complication is the fact that we need to handle a card that has yet been assigned a value. Hiding the face is even easier as we set faceShowing to false then stop on the blank card frame.
// shows the face side of the card
spelchan.Card.prototype.showFace = function()
{
this.faceShowing = true;
if (this.cardID == 0)
this.cardMovie.gotoAndStop(1);
else
this.cardMovie.gotoAndStop(9+cardID);
}
// shows the back of the card
spelchan.Card.prototype.hideFace = function()
{
this.faceShowing = false;
this.cardMovie.gotoAndStop(1);
}
This is all that is needed for a card class, but creating a couple of utility methods for getting the face of the card and the suit of the card is easy enough to do. This is done using math. The modulus function, which uses the % operator, gives you the remainder of a division. Had we started counting from 0, this would work great, but as we didn’t subtracting one from the card id lets us use modulus to get the face value from 0 to 12 and adding 1 corrects this. A similar technique can be used to determine which of the four suits are being used by seeing which group of 13 the card falls into.
Saturday, July 27, 2019
7-1 Creating the Card Movie
As you already know, a deck of cards consists of 52 cards (54 if you count the two jokers, but for now we won’t worry about those). Obviously, this means that we are going to need 52 images. In addition to the images for every card, we are also going to need an image for the back of the cards.
There are two ways we can create images for the cards. One way, if you already have a set of bitmaps for the cards, is to simply import the 52 bitmap images. The advantage of this is speed. The disadvantage is that the resulting images are not vectors and will not scale well. One way to get around the vector problem would be to convert every card into a vector image. This only takes a slight bit more time and you end up with better scalability.
The other way is to build the cards in Animate CC (or a vector drawing program that lets you export images to Animate CC). This can potentially reduce the overall size of the deck by a fair amount. Having the cards being proper vector images also enables very good scalability. If you don’t already have a set of bitmap card images, then creating the cards in Adobe Animate CC will take just as long as it would to create them in a bitmap based paint program.
For this book, we are going to build all the cards in Adobe Animate CC. One way would be to simply create 53 graphic images. This works, but when you look at a deck of cards you will quickly notice that the cards are only made up of a small subset of images. If we create a series of symbols for the components that make up a card, we will easily be able to create the entire deck by assembling our components. This helps reduce both the time it takes to build the deck of cards and the amount of memory required for the cards at the cost of taking a bit more time to draw the cards but as card games are not fast-paced games this is not a huge concern.
When you think about it, a set of cards can be broken into 34 components. Making this even better, most of these are small components that only take a few curves to represent. The components used in this are shown in figure below.
Now, the top line consists of “Blank Card”, “Jack”, “Queen”, King. The Blank Card symbol is the background symbol. Notice that we surround the card with a hairline box. The card is 100 by 140 as that is the resolution I had in the bitmap deck that I created for my Java card games. The cards could be any size you desired, and because they are vectors the cards will look good scaled up or down.
The second line Consists of the suits, named “Spade,” “Heart,” “Club,” and “Diamond”. The third and fourth lines consist of the card face value text. There are two versions, one for black cards and one for red cards. The symbols are named, “Blk A,” “Blk 2,” “Blk 3,” “Blk 4,” “Blk 5,” “Blk 6,” “Blk 7,” “Blk 8,” “Blk 9,” “Blk 10,” “Blk J,” “Blk Q,” “Blk K,” “Red A,” “Red 2,” “Red 3,” “Red 4,” “Red 5,” “Red 6,” “Red 7,” “Red 8,” “Red 9,” “Red 10,” “Red J,” “Red Q,” and “Red K.”
Once we have created the components, we are going to need to create a card movie. The purpose of this movie is to hold the images for all the cards and go to the appropriate image based on what value is assigned to the card. I have decided to give each card a numerical ID, which is as follows. The ID of 0 represents no visible value (in other words the card back is shown). cards are then given ID in numerical order, with Aces being the first card and kings being the last. We go through the suits in alphabetical order, so we have the Clubs, Diamonds, Hearts, then Spades.
As the ID can be simply calculated based on the value of the card (Aces being valued as 1, Jacks valued as 11, Queens valued as 12 and Kings valued as 13), it makes sense to take advantage of this fact. We do this by mathematically determining the position of the card. How? Every card is a single frame. We have the card back on frame one and start the first card on frame 11. We then simply need to add 10 to the ID to find the correct frame for the card face. Note that Create.js uses 0 based indexing instead of the 1 based indexing that non-canvas animations use. This will mean that the frame numbers will be off by one so care needs to be taken when writing the JavaScript for going to specific frames using the frame number.
Now, a bit of code is going to be in order. We are going to need to get and set the ID of the card. We also want to be able to show the back or the front of a card. While neither of the games in this part of the book use this feature, it is simple enough to implement and will be of obvious use with many other card games. This will be covered next fortnight.
There are two ways we can create images for the cards. One way, if you already have a set of bitmaps for the cards, is to simply import the 52 bitmap images. The advantage of this is speed. The disadvantage is that the resulting images are not vectors and will not scale well. One way to get around the vector problem would be to convert every card into a vector image. This only takes a slight bit more time and you end up with better scalability.
The other way is to build the cards in Animate CC (or a vector drawing program that lets you export images to Animate CC). This can potentially reduce the overall size of the deck by a fair amount. Having the cards being proper vector images also enables very good scalability. If you don’t already have a set of bitmap card images, then creating the cards in Adobe Animate CC will take just as long as it would to create them in a bitmap based paint program.
For this book, we are going to build all the cards in Adobe Animate CC. One way would be to simply create 53 graphic images. This works, but when you look at a deck of cards you will quickly notice that the cards are only made up of a small subset of images. If we create a series of symbols for the components that make up a card, we will easily be able to create the entire deck by assembling our components. This helps reduce both the time it takes to build the deck of cards and the amount of memory required for the cards at the cost of taking a bit more time to draw the cards but as card games are not fast-paced games this is not a huge concern.
When you think about it, a set of cards can be broken into 34 components. Making this even better, most of these are small components that only take a few curves to represent. The components used in this are shown in figure below.
Now, the top line consists of “Blank Card”, “Jack”, “Queen”, King. The Blank Card symbol is the background symbol. Notice that we surround the card with a hairline box. The card is 100 by 140 as that is the resolution I had in the bitmap deck that I created for my Java card games. The cards could be any size you desired, and because they are vectors the cards will look good scaled up or down.
The second line Consists of the suits, named “Spade,” “Heart,” “Club,” and “Diamond”. The third and fourth lines consist of the card face value text. There are two versions, one for black cards and one for red cards. The symbols are named, “Blk A,” “Blk 2,” “Blk 3,” “Blk 4,” “Blk 5,” “Blk 6,” “Blk 7,” “Blk 8,” “Blk 9,” “Blk 10,” “Blk J,” “Blk Q,” “Blk K,” “Red A,” “Red 2,” “Red 3,” “Red 4,” “Red 5,” “Red 6,” “Red 7,” “Red 8,” “Red 9,” “Red 10,” “Red J,” “Red Q,” and “Red K.”
Once we have created the components, we are going to need to create a card movie. The purpose of this movie is to hold the images for all the cards and go to the appropriate image based on what value is assigned to the card. I have decided to give each card a numerical ID, which is as follows. The ID of 0 represents no visible value (in other words the card back is shown). cards are then given ID in numerical order, with Aces being the first card and kings being the last. We go through the suits in alphabetical order, so we have the Clubs, Diamonds, Hearts, then Spades.
As the ID can be simply calculated based on the value of the card (Aces being valued as 1, Jacks valued as 11, Queens valued as 12 and Kings valued as 13), it makes sense to take advantage of this fact. We do this by mathematically determining the position of the card. How? Every card is a single frame. We have the card back on frame one and start the first card on frame 11. We then simply need to add 10 to the ID to find the correct frame for the card face. Note that Create.js uses 0 based indexing instead of the 1 based indexing that non-canvas animations use. This will mean that the frame numbers will be off by one so care needs to be taken when writing the JavaScript for going to specific frames using the frame number.
Now, a bit of code is going to be in order. We are going to need to get and set the ID of the card. We also want to be able to show the back or the front of a card. While neither of the games in this part of the book use this feature, it is simple enough to implement and will be of obvious use with many other card games. This will be covered next fortnight.
Saturday, July 6, 2019
Chapter 7 Overview
One nice feature of card games, is that once you have created a card game you are able to take advantage of existing assets and code to handle the cards so that creating other card games in the future is easier. In this chapter we are going to take advantage of this in two ways.
First, in ``Creating the Card Movie'' we are going to create a card movie. This movie will have frames for all the cards in a deck and will be able to display any specified card. While fairly simple to build, creating a deck of cards is a time-consuming process. Thankfully, we only need to do it once. After the card movie has been created, you simply need to drag it into the new Animate CC project to use it in other card games. You could also place it into a common library.
Next we are going to create some JavaScript classes. For the most compatibility, which probably is not that big of a deal as most browsers in use support ECMAScript 6 JavaScript code, we are going to use the older and most compatible way of creating classes. In ``Creating the Card Class'' we create the class for handling the cards while in ``The Importance of Testing'' we test this class.
Test driven development, which is a very common practice now, does things the opposite way so in ``Test Driven Deck'' we create the tests for a deck class and with the tests ready to go actually create the deck class in ``Creating the Deck Class''
Once we have these classes created we will be able to build our Video Poker game.
First, in ``Creating the Card Movie'' we are going to create a card movie. This movie will have frames for all the cards in a deck and will be able to display any specified card. While fairly simple to build, creating a deck of cards is a time-consuming process. Thankfully, we only need to do it once. After the card movie has been created, you simply need to drag it into the new Animate CC project to use it in other card games. You could also place it into a common library.
Next we are going to create some JavaScript classes. For the most compatibility, which probably is not that big of a deal as most browsers in use support ECMAScript 6 JavaScript code, we are going to use the older and most compatible way of creating classes. In ``Creating the Card Class'' we create the class for handling the cards while in ``The Importance of Testing'' we test this class.
Test driven development, which is a very common practice now, does things the opposite way so in ``Test Driven Deck'' we create the tests for a deck class and with the tests ready to go actually create the deck class in ``Creating the Deck Class''
Once we have these classes created we will be able to build our Video Poker game.
Saturday, June 29, 2019
Spelchan.com Summer 2019
Blazing Games has been closed, at least the home page has. For the moment I am leaving the other pages up so if you know the link to a game then you can still go to the page. This will be eventually changing but I'm in no rush here. I produced a lot of Games so there is a huge amount of porting work to do. I have reviewed the results of the poll and as a result have made changes to my release plans for this year.
Coffee Quest was released a month early. My holiday games seem to be slightly more popular than I expected. For this reason I am going to make sure that I have holiday games ported as appropriate. This decision has me in the process of porting my Canada Day flag game for release this Canada Day (July 1st for non-Canadian visitors). Next year I will release my Independence Day game for my American friends.
I have decided that, in memory of my Mother, I am going to only release Color Collapse episodes on Mother's Day but do plan on creating related games once the remaining two episodes have been released.
I noticed that the voting list of games missed some of the games that were already in HTML5 so those will become filler for when I am too busy to finish porting other games. The first of these will be Sudoku which will be released in August as my card and dice collection are very low in popularity. A beta of Coffee Quest 2 will hopefully be released this September with a Halloween game for October. November’s release is not yet determined yet and will be dependent on my time in September and October and I plan on creating a unique Christmas game this year.
I am not going to have any official release schedule for 2020 (other than a game every month) but do plan on showcasing the games I am working on in whatever game I am going to release in January. Hint, it will not be an updated Calendar NIM game this time.
So hopefully you will enjoy the site. Next fortnight I will start the next chapter of my Creating HTML 5 Games with Animate eBook so hope you continue reading.
Saturday, June 15, 2019
Final Touches
As is quite often the case with my games, the last part of the game that is created is the title screen. The first part of the title screen is the game's logo. My One of the Weeks logo is not really appropriate, even though this game is part of that series, so to make this a stand-alone game I created a new logo. For the start button, I opted for a door as that is emblematic of the game play. As always, the code to control the button is very straight forward.
spelchan.Nightmare.prototype.startTitle = function() {
this.playButtonHandler = this.playButtonClicked.bind(this);
this.stage.playBtn.addEventListener("click", this.playButtonHandler);
this.stage.stop();
}
spelchan.Nightmare.prototype.playButtonClicked = function(e) {
console.log("Play Button Clicked!");
this.stage.playBtn.removeEventListener("click", this.playButtonHandler);
this.stage.gotoAndPlay("Intro");
}
One problem that I had with the game at this point was the fact that someone who started playing the game without reading the instructions would be totally confused by what was going on. While confusion may actually add to the story, it can also turn a lot of people off the game. As this is the first episode of a series, one thing I don't want is to turn people off the game.
While I would like to think that people read the instruction pages that I put a some effort into creating, the reality is that a lot people just start playing the game.
One solution would be to have a link to the instructions on the game's title screen. The problem with doing this is that the people who skip over the instructions page are likely to not bother clicking on the instructions button either. This means that I would end up putting more time into creating the instruction pages - which is more time consuming then writing an instruction page - which few people are going to read. This is obviously not a good solution.
The solution I did for this episode is to incorporate the background portion of the instructions into the game by starting the player at an explanation screen. This is simply a looped animation of the text bubble growing then shrinking. The code for handling the button is also very simple.
spelchan.Nightmare.prototype.setIntroButton = function(e) {
this.introButtonHandler = this.introButtonClicked.bind(this);
this.stage.con_btn.addEventListener("click", this.introButtonHandler);
}
spelchan.Nightmare.prototype.introButtonClicked = function(e) {
console.log("Intro Button Clicked!");
this.stage.con_btn.removeEventListener("click", this.introButtonHandler);
this.stage.gotoAndPlay("enterRed");
}
And that is all there is to the game. Next fortnight we will look at changes to my Blazing Games porting plans and next month we will start chapter 7 which sets the foundation for the creation of video poker.
spelchan.Nightmare.prototype.startTitle = function() {
this.playButtonHandler = this.playButtonClicked.bind(this);
this.stage.playBtn.addEventListener("click", this.playButtonHandler);
this.stage.stop();
}
spelchan.Nightmare.prototype.playButtonClicked = function(e) {
console.log("Play Button Clicked!");
this.stage.playBtn.removeEventListener("click", this.playButtonHandler);
this.stage.gotoAndPlay("Intro");
}
One problem that I had with the game at this point was the fact that someone who started playing the game without reading the instructions would be totally confused by what was going on. While confusion may actually add to the story, it can also turn a lot of people off the game. As this is the first episode of a series, one thing I don't want is to turn people off the game.
While I would like to think that people read the instruction pages that I put a some effort into creating, the reality is that a lot people just start playing the game.
One solution would be to have a link to the instructions on the game's title screen. The problem with doing this is that the people who skip over the instructions page are likely to not bother clicking on the instructions button either. This means that I would end up putting more time into creating the instruction pages - which is more time consuming then writing an instruction page - which few people are going to read. This is obviously not a good solution.
The solution I did for this episode is to incorporate the background portion of the instructions into the game by starting the player at an explanation screen. This is simply a looped animation of the text bubble growing then shrinking. The code for handling the button is also very simple.
spelchan.Nightmare.prototype.setIntroButton = function(e) {
this.introButtonHandler = this.introButtonClicked.bind(this);
this.stage.con_btn.addEventListener("click", this.introButtonHandler);
}
spelchan.Nightmare.prototype.introButtonClicked = function(e) {
console.log("Intro Button Clicked!");
this.stage.con_btn.removeEventListener("click", this.introButtonHandler);
this.stage.gotoAndPlay("enterRed");
}
And that is all there is to the game. Next fortnight we will look at changes to my Blazing Games porting plans and next month we will start chapter 7 which sets the foundation for the creation of video poker.
Saturday, June 1, 2019
Losing and Winning
In the previous section we introduced the BSoD. This leads to the problem of what to do when the player loses the game. My first thought was to have the BSoD claw the player to death. This would reflect the feeling you get when you have an hours worth of unsaved work and the real blue screen of death shows up. Not that I’ve ever had that happen to me as I always save my work frequently. Mind you, the reason I always save my work frequently is because of learning what losing hours of work because of a computer crashing feels like.
Having someone being clawed to death is not really appropriate for a family friendly game so instead, I decided to have a bit of fun and generate a nice error message.
There is a button on the screen which returns the user to the title screen that we will be creating in the next section. To have the button do something we have a method in our Nightmare class for dealing with returning to the title screen. This method is called using nightmare.registerTitleButton(this.losecon_btn);
spelchan.Nightmare.prototype.registerTitleButton = function(btn) {
console.log("registering toTitle called! " + btn);
this.toTitleButton = btn;
this.toTitleHandler = this.toTitle.bind(this);
this.toTitleButton.addEventListener("click", this.toTitleHandler);
}
spelchan.Nightmare.prototype.toTitle = function(e) {
console.log("toTitle called!");
this.toTitleButton.removeEventListener("click", this.toTitleHandler);
this.stage.gotoAndPlay("Title");
}
This code simply sets up a button that is passed to it to call an event handler that simply returns the game to the title sequence. To remove an event listener, however, you need a link to the event that is to be removed. Binding objects end up creating something new so to properly remove the event handler we need to keep a reference to the binded version of the handler. The actual handler code simply uses this binded reference to properly remove the event handling reference and then goes to the title sreen frame.
Now that it is possible to lose the game, perhaps it would be nice to allow the player to win the game. The winning scene was designed with two purposes in mind. First, as a distinct way of showing the player that they have completed the game. Second, to preview the next episode of the game. The number 666 has certain significance with my upbringing and to this day I still consider that number to be a bad omen. As you can't have that number on a clock, at least not legitimately, I opted for 6:36 for the time. The code for handling the “To be Continued...” button, as with the lose screen, is simply a call to nightmare.registerTitleButton(this.wincon\_btn);
Now we just need the title and intro screens and we are finished.These will be completed next fortnight which will conclude this chapter.
Having someone being clawed to death is not really appropriate for a family friendly game so instead, I decided to have a bit of fun and generate a nice error message.
There is a button on the screen which returns the user to the title screen that we will be creating in the next section. To have the button do something we have a method in our Nightmare class for dealing with returning to the title screen. This method is called using nightmare.registerTitleButton(this.losecon_btn);
spelchan.Nightmare.prototype.registerTitleButton = function(btn) {
console.log("registering toTitle called! " + btn);
this.toTitleButton = btn;
this.toTitleHandler = this.toTitle.bind(this);
this.toTitleButton.addEventListener("click", this.toTitleHandler);
}
spelchan.Nightmare.prototype.toTitle = function(e) {
console.log("toTitle called!");
this.toTitleButton.removeEventListener("click", this.toTitleHandler);
this.stage.gotoAndPlay("Title");
}
This code simply sets up a button that is passed to it to call an event handler that simply returns the game to the title sequence. To remove an event listener, however, you need a link to the event that is to be removed. Binding objects end up creating something new so to properly remove the event handler we need to keep a reference to the binded version of the handler. The actual handler code simply uses this binded reference to properly remove the event handling reference and then goes to the title sreen frame.
Now that it is possible to lose the game, perhaps it would be nice to allow the player to win the game. The winning scene was designed with two purposes in mind. First, as a distinct way of showing the player that they have completed the game. Second, to preview the next episode of the game. The number 666 has certain significance with my upbringing and to this day I still consider that number to be a bad omen. As you can't have that number on a clock, at least not legitimately, I opted for 6:36 for the time. The code for handling the “To be Continued...” button, as with the lose screen, is simply a call to nightmare.registerTitleButton(this.wincon\_btn);
Now we just need the title and intro screens and we are finished.These will be completed next fortnight which will conclude this chapter.
Saturday, May 18, 2019
Enter the Nasty
To add a bit more pressure on the player, I have a villain that pops up after the player has stayed in the room too long. Being a programmer, the first villain that came to mind is the dreaded Blue Screen of Death that occurs on Windows machines. Linux and Macintosh OS X don't have this problem (and are extremely stable operating systems) but most people have windows, and a lot of my programming happens to be for Windows machines. To be fair to Microsoft, the blue-screen problem has largely gone away.
In addition to the BSoD image, we also need a movie that controls the BSoD. This movie consists of nothing for the first few frames (labeled hide) with a stop on the second frame. There is also be a block labeled show which is a two second sequence of the BSoD appearing. For control purposes we have the button code in the previous section call the hide method which shows nothing. There is a flag that is set indicating that there is no BSoD yet. A timer is set up to 0 and when this timer reaches 3 the BSoD will appear. What are we timing? We already have a loop for growing and shrinking the room so we will use the end of that loop as the timer. So instead of having a gotoAndPlay on the last frame to loop the animation, we instead have nightmare.updateBSOD("blueLoop"); with the string being the name of the label to go to for looping the room animation. The BSOD update code is as follows:
spelchan.Nightmare.prototype.updateBSOD = function(loop) {
// BSOD calculations
if (this.bsodAppearing) {
this.stage.gotoAndPlay("loseGame");
return;
}
++this.bsodTimer;
if (this.bsodTimer >= 3) {
this.bsodAppearing = true;
this.stage.bsod_movie.gotoAndPlay("show");
}
this.stage.gotoAndPlay(loop);
}
The function simply keeps track of how many times it has been called. As the function is called every 2 seconds, we simply figure out how long we give the players before the BSoD appears and then start the appearing animation. If another tick happens after the appearing animation has occurred then we know that the player has bit the bullet. This simply goes to the loseGame frame which we use for losing the game. Which leaves us with the task of handing the winning and losing of the game.
In addition to the BSoD image, we also need a movie that controls the BSoD. This movie consists of nothing for the first few frames (labeled hide) with a stop on the second frame. There is also be a block labeled show which is a two second sequence of the BSoD appearing. For control purposes we have the button code in the previous section call the hide method which shows nothing. There is a flag that is set indicating that there is no BSoD yet. A timer is set up to 0 and when this timer reaches 3 the BSoD will appear. What are we timing? We already have a loop for growing and shrinking the room so we will use the end of that loop as the timer. So instead of having a gotoAndPlay on the last frame to loop the animation, we instead have nightmare.updateBSOD("blueLoop"); with the string being the name of the label to go to for looping the room animation. The BSOD update code is as follows:
spelchan.Nightmare.prototype.updateBSOD = function(loop) {
// BSOD calculations
if (this.bsodAppearing) {
this.stage.gotoAndPlay("loseGame");
return;
}
++this.bsodTimer;
if (this.bsodTimer >= 3) {
this.bsodAppearing = true;
this.stage.bsod_movie.gotoAndPlay("show");
}
this.stage.gotoAndPlay(loop);
}
The function simply keeps track of how many times it has been called. As the function is called every 2 seconds, we simply figure out how long we give the players before the BSoD appears and then start the appearing animation. If another tick happens after the appearing animation has occurred then we know that the player has bit the bullet. This simply goes to the loseGame frame which we use for losing the game. Which leaves us with the task of handing the winning and losing of the game.
Saturday, May 4, 2019
Linking the Rooms
Now comes the task of assembling and linking the rooms. I create a block of frames for each of the six rooms with each room being broken into three animated sequences. First is the Enter sequence (labeled enterColor, with Color being the color of the room). This sequence shows the room zooming into view. Next is the main room loop (labeled colorLoop, with color being the color of the room). I want to have an additional disorienting effect added to the room. Therefore, I set this block of frames to loop. The room will slowly grow and then shrink back to it's starting size. Finally there is an exit sequence (labeled colorExit, with color being the color of the room). This shows the room shrinking into nothing.
As animate likes to tie code to the frame it is written in, we are creating a globally accessible class that we will be using for tracking the state of the game. This class will be added to throughout this chapter but to start with we have the following initialization code.
if (typeof(spelchan) == "undefined") spelchan = {};
spelchan.Nightmare = function() {
this.registerStage = function(stage) { this.stage = stage;}
this.dirButtons = [null,null,null,null];
this.dirClickHandler = this.directionClicked.bind(this);
this.exitTarget = "exitRed";
}
This sets up a spelchan.Nightmare class that holds the list of buttons that are used to control the navigation between rooms. We need buttons for the four directions that the player can go. Quite simply, I will label the directions North, South, East and West. The four buttons will be invisible buttons. These are buttons that have a hit box but no image. Actually, when the player is over the buttons, we will have a "Go Direction" message appear. This is done simply by having the over and down frames of the button have the desired text in them. In the editor the invisible buttons have a cyan color and are placed over the doors in the image. Due to the animation of the room this placement isn't exact.
Every room will have it's own set of four buttons. I use the convention of naming the button instances colorDirection_btn. As the logic for the buttons is similar for all the rooms we can create a general method for setting up the buttons for a room as follows:
spelchan.Nightmare.prototype.setDirectionTargets = function(
btnNorth, targetNorth, btnEast, targetEast,
btnSouth, targetSouth, btnWest, targetWest, exitTarget) {
this.dirButtons[0] = btnNorth;
btnNorth.directionTarget = targetNorth;
this.dirButtons[1] = btnEast;
btnEast.directionTarget = targetEast;
this.dirButtons[2] = btnSouth;
btnSouth.directionTarget = targetSouth;
this.dirButtons[3] = btnWest;
btnWest.directionTarget = targetWest;
this.exitTarget = exitTarget;
for (var cntr = 0; cntr < 4; ++cntr) {
this.dirButtons[cntr].addEventListener(
"click", this.dirClickHandler);
}
this.bsodTimer = 0;
this.bsodAppearing = false;
this.stage.bsod_movie.gotoAndPlay("hide");
}
This code simply sets up the buttons and gives each button a target frame to go to when it is clicked. It also provides the frame to goto to start the exit room animation. The buttons are then assigned an event listener to handle being clicked. We will be covering this handler later in this section. Finally the code sets up the timer for the villain. We will cover the appearance of the villain in the next section. Each of the six rooms needs to call the above method when it is appearing with the code being on the frame where the room starts appearing. This code is something like the following:
nightmare.setDirectionTargets(
this.redNorth_btn, "enterCyan",
this.redEast_btn, "enterGreen",
this.redSouth_btn, "enterCyan",
this.redWest_btn, "enterYellow", "exitRed");
As you can see this is simply a function call to the method we created above. The parameters would be the appropriate buttons for that room and the labels of the frame the program should go to when the button is clicked. The button variables are self-evident while the target frames require looking at the map to determine the appropriate room to go to.
Handling the click is the next thing we need to do. This is done by the event handler we hinted at above.
spelchan.Nightmare.prototype.directionClicked = function(e) {
// make sure button has valid target
if (typeof(e.target.directionTarget) == "undefined") {
console.log("ERROR - Missing target in button");
this.directionTarget = "enterRed";
} else {
console.log("Button target is " + e.target.directionTarget);
this.directionTarget = e.target.directionTarget;
}
// clean up buttons
for (var cntr = 0; cntr < 4; ++cntr) {
this.dirButtons[cntr].removeEventListener("click", this.dirClickHandler);
}
this.stage.gotoAndPlay(this.exitTarget);
}
This function first sets up a class variable called directionTarget to be the name of the frame to go to once the room has been exited. We can't go to this frame right away because we have to play an exit animation first. To be good citizens, we need to clean up our event handlers so we remove the event listeners. Finally we start the animation for exiting the room.
To finish our navigation system we need to go to the appropriate room when the player is exiting the room. Each of the exit animations will have a call to nightmare.nextRoom() on the last frame. This is a simple method that simply goes to the frame indicated by the button that was clicked on above.
spelchan.Nightmare.prototype.nextRoom = function() {
this.stage.gotoAndPlay(this.directionTarget);
}
This code simply goes to the appropriate frame for the next room. And that is all that is required for a navigation system. Now we need to implement the villain of this game which we will do next fortnight..
As animate likes to tie code to the frame it is written in, we are creating a globally accessible class that we will be using for tracking the state of the game. This class will be added to throughout this chapter but to start with we have the following initialization code.
if (typeof(spelchan) == "undefined") spelchan = {};
spelchan.Nightmare = function() {
this.registerStage = function(stage) { this.stage = stage;}
this.dirButtons = [null,null,null,null];
this.dirClickHandler = this.directionClicked.bind(this);
this.exitTarget = "exitRed";
}
This sets up a spelchan.Nightmare class that holds the list of buttons that are used to control the navigation between rooms. We need buttons for the four directions that the player can go. Quite simply, I will label the directions North, South, East and West. The four buttons will be invisible buttons. These are buttons that have a hit box but no image. Actually, when the player is over the buttons, we will have a "Go Direction" message appear. This is done simply by having the over and down frames of the button have the desired text in them. In the editor the invisible buttons have a cyan color and are placed over the doors in the image. Due to the animation of the room this placement isn't exact.
Every room will have it's own set of four buttons. I use the convention of naming the button instances colorDirection_btn. As the logic for the buttons is similar for all the rooms we can create a general method for setting up the buttons for a room as follows:
spelchan.Nightmare.prototype.setDirectionTargets = function(
btnNorth, targetNorth, btnEast, targetEast,
btnSouth, targetSouth, btnWest, targetWest, exitTarget) {
this.dirButtons[0] = btnNorth;
btnNorth.directionTarget = targetNorth;
this.dirButtons[1] = btnEast;
btnEast.directionTarget = targetEast;
this.dirButtons[2] = btnSouth;
btnSouth.directionTarget = targetSouth;
this.dirButtons[3] = btnWest;
btnWest.directionTarget = targetWest;
this.exitTarget = exitTarget;
for (var cntr = 0; cntr < 4; ++cntr) {
this.dirButtons[cntr].addEventListener(
"click", this.dirClickHandler);
}
this.bsodTimer = 0;
this.bsodAppearing = false;
this.stage.bsod_movie.gotoAndPlay("hide");
}
This code simply sets up the buttons and gives each button a target frame to go to when it is clicked. It also provides the frame to goto to start the exit room animation. The buttons are then assigned an event listener to handle being clicked. We will be covering this handler later in this section. Finally the code sets up the timer for the villain. We will cover the appearance of the villain in the next section. Each of the six rooms needs to call the above method when it is appearing with the code being on the frame where the room starts appearing. This code is something like the following:
nightmare.setDirectionTargets(
this.redNorth_btn, "enterCyan",
this.redEast_btn, "enterGreen",
this.redSouth_btn, "enterCyan",
this.redWest_btn, "enterYellow", "exitRed");
As you can see this is simply a function call to the method we created above. The parameters would be the appropriate buttons for that room and the labels of the frame the program should go to when the button is clicked. The button variables are self-evident while the target frames require looking at the map to determine the appropriate room to go to.
Handling the click is the next thing we need to do. This is done by the event handler we hinted at above.
spelchan.Nightmare.prototype.directionClicked = function(e) {
// make sure button has valid target
if (typeof(e.target.directionTarget) == "undefined") {
console.log("ERROR - Missing target in button");
this.directionTarget = "enterRed";
} else {
console.log("Button target is " + e.target.directionTarget);
this.directionTarget = e.target.directionTarget;
}
// clean up buttons
for (var cntr = 0; cntr < 4; ++cntr) {
this.dirButtons[cntr].removeEventListener("click", this.dirClickHandler);
}
this.stage.gotoAndPlay(this.exitTarget);
}
This function first sets up a class variable called directionTarget to be the name of the frame to go to once the room has been exited. We can't go to this frame right away because we have to play an exit animation first. To be good citizens, we need to clean up our event handlers so we remove the event listeners. Finally we start the animation for exiting the room.
To finish our navigation system we need to go to the appropriate room when the player is exiting the room. Each of the exit animations will have a call to nightmare.nextRoom() on the last frame. This is a simple method that simply goes to the frame indicated by the button that was clicked on above.
spelchan.Nightmare.prototype.nextRoom = function() {
this.stage.gotoAndPlay(this.directionTarget);
}
This code simply goes to the appropriate frame for the next room. And that is all that is required for a navigation system. Now we need to implement the villain of this game which we will do next fortnight..
Saturday, April 20, 2019
Building the Rooms
The idea behind this episode of the game is that the player is dreaming that they are in a maze of rooms being chased by something. The rooms are connected in a non-linear fashion, but the rooms each have their own color. Thinking about this, all the rooms in the game will look the same except for their color. This means that all we have to do is create a single room and then duplicate it five times changing the colors in the duplicates! There, however, is an even better way of handling the creation of the rooms. Tinting!
To make tinting work the best, it is best to create the non-tinted image using gray-scale. I am going to keep the game in third person perspective so that we don't have all the work required to move an animated figure around. This means that the room needs to be drawn to look three dimensional. To better add to the three dimensional look, I created a tiled floor. This was done by drawing receding lines, then by drawing lines in the distance and angling them so that there is a larger distance between the closer points than the further points. Had I been really ambitious I could have created a far off point (a vanishing point) and having all the horizontal lines coming from that point. I then filled in the squares and finally removed the lines.
The ceiling I wanted to be stuccoed. This would have required a huge amount of work to accomplish using vectors, so I opted to use a texture for this image. The texture was generated in fireworks, but all high-end paint programs (and many low end ones as well) have texture creation support.
The three doors that are in the scene are actually all the same. I drew the far door and then used the distort command to alter the other two doors. While I could have been picky and tried to get the doors to look perfect, to keep the dream motif, I wanted the doors to be a bit distorted.
There are a number of ways of dealing with the room once you have the gray-scale done and want to apply tinting. This could be done within the program. Though tinting is a very costly operation, you would only have to do it once when you entered the room. Another option, which is the approach I took, is to create copies of the gray-scale image and individually tint those symbols. The advantage of doing this is you can get a bit better result from the tinting by tinting different parts of the room with different shades of the room color. The floors and ceiling were tinted a slightly different shade then the walls and doors, resulting in nicer looking rooms from the original flash version of this game.
Now that we have the rooms ready, we need to link them together which is what we will be doing next fortnight.
To make tinting work the best, it is best to create the non-tinted image using gray-scale. I am going to keep the game in third person perspective so that we don't have all the work required to move an animated figure around. This means that the room needs to be drawn to look three dimensional. To better add to the three dimensional look, I created a tiled floor. This was done by drawing receding lines, then by drawing lines in the distance and angling them so that there is a larger distance between the closer points than the further points. Had I been really ambitious I could have created a far off point (a vanishing point) and having all the horizontal lines coming from that point. I then filled in the squares and finally removed the lines.
The ceiling I wanted to be stuccoed. This would have required a huge amount of work to accomplish using vectors, so I opted to use a texture for this image. The texture was generated in fireworks, but all high-end paint programs (and many low end ones as well) have texture creation support.
The three doors that are in the scene are actually all the same. I drew the far door and then used the distort command to alter the other two doors. While I could have been picky and tried to get the doors to look perfect, to keep the dream motif, I wanted the doors to be a bit distorted.
There are a number of ways of dealing with the room once you have the gray-scale done and want to apply tinting. This could be done within the program. Though tinting is a very costly operation, you would only have to do it once when you entered the room. Another option, which is the approach I took, is to create copies of the gray-scale image and individually tint those symbols. The advantage of doing this is you can get a bit better result from the tinting by tinting different parts of the room with different shades of the room color. The floors and ceiling were tinted a slightly different shade then the walls and doors, resulting in nicer looking rooms from the original flash version of this game.
Now that we have the rooms ready, we need to link them together which is what we will be doing next fortnight.
Saturday, April 6, 2019
Planning the Adventure
The basic theme behind nightmare maze is that you are lost in a maze and must move quickly from room to room before the evil Blue Screen of Death reaches you. The maze in this game is consistent in the fact that the same door will take you to the same room, however it is not commutative meaning that the door from A to B does not necessarily go back to A. This means while there is a structure to the maze it works different then the real world, which is typical of dreams.
Mazes are fairly easy to implement. This maze, however, is not a linear maze. With a linear maze, you can use graph paper to plan out the maze. This is obviously not the case with a non-linear maze. Instead, a different type of graph is used for creating a non-linear maze. This graph consists of the rooms drawn as boxes with arrowed lines showing how the rooms connect. I used a variation on this having colored lines corresponding to the room the line is from.
As you can see by the above map, the links between rooms are fairly complex. However implementing the links is actually very easy. You can also see that there are a lot of ways of reaching the exit, but do to the fact that there is nothing highlighting the exit, a player could end up being stuck in the maze for quite a while.
The room approach is very common in adventure games as travelling between locations is a very common activity. Generally, when designing an adventure game, each location will be considered to be a room even if it is an outside location. This allows for rooms to be worked on independently of each other and for earlier computers that had a very limited amount of memory would allow for the computer to only have to load the drawing data for the room that the player was currently in then having some type of transition animation between "rooms" when the player left a room and the game had to load in the image for the next room.
From a programming perspective, having rooms that are connected together with lines allows us to represent the map as a mathematical graph in which each room is a vertex of the graph and the connections between rooms are the edges of the graph. Graph theory, however, is not necessary to build an adventure game. All that really matters is that you are able to create a basic map of the locations within the adventure so that you can move between them. The map can also be used to plan out where objects are located in the world and what obstacles or puzzles there are in the game. This allows for a walk through of the game before you have even started any real work on building the game so that you know that the game is solvable.
Once the map is planned out you then have the ability to itemize all the assets that will be needed for the game and can start work on building the art needed for each of the rooms. Building the rooms is what we will be doing next fortnight, but thanks to the nature of our maze this is a lot easier for this game than it would be for most other adventure games.
Mazes are fairly easy to implement. This maze, however, is not a linear maze. With a linear maze, you can use graph paper to plan out the maze. This is obviously not the case with a non-linear maze. Instead, a different type of graph is used for creating a non-linear maze. This graph consists of the rooms drawn as boxes with arrowed lines showing how the rooms connect. I used a variation on this having colored lines corresponding to the room the line is from.
As you can see by the above map, the links between rooms are fairly complex. However implementing the links is actually very easy. You can also see that there are a lot of ways of reaching the exit, but do to the fact that there is nothing highlighting the exit, a player could end up being stuck in the maze for quite a while.
The room approach is very common in adventure games as travelling between locations is a very common activity. Generally, when designing an adventure game, each location will be considered to be a room even if it is an outside location. This allows for rooms to be worked on independently of each other and for earlier computers that had a very limited amount of memory would allow for the computer to only have to load the drawing data for the room that the player was currently in then having some type of transition animation between "rooms" when the player left a room and the game had to load in the image for the next room.
From a programming perspective, having rooms that are connected together with lines allows us to represent the map as a mathematical graph in which each room is a vertex of the graph and the connections between rooms are the edges of the graph. Graph theory, however, is not necessary to build an adventure game. All that really matters is that you are able to create a basic map of the locations within the adventure so that you can move between them. The map can also be used to plan out where objects are located in the world and what obstacles or puzzles there are in the game. This allows for a walk through of the game before you have even started any real work on building the game so that you know that the game is solvable.
Once the map is planned out you then have the ability to itemize all the assets that will be needed for the game and can start work on building the art needed for each of the rooms. Building the rooms is what we will be doing next fortnight, but thanks to the nature of our maze this is a lot easier for this game than it would be for most other adventure games.
Saturday, March 23, 2019
Nightmare Maze Overview
In the flash version (as well as my original draft) of this book, the adventure game material was near the end of the book but as the game is fairly simple from a programming perspective, I have decided to move it to here. Nightmare Maze is actually the first episode of a 46 episode series called One of those Weeks, which I hope to be redoing using a 3D engine sometime in the future.
In "Planning the Adventure" we take a look at how the game was designed. Adventure games tend to break areas that the player can visit into rooms, with the word room being a generic concept so outdoor areas are also referred to as rooms. For this game, all the rooms in the game are in fact rooms so the next step to the creation of this game is "Building the Rooms" which covers the techniques used to build the rooms used in this game. While it is a little but unconventional, it works for this game and the basic concepts are the same for other adventures.
While it is possible to have an adventure game that exists in a single room, such as a puzzle room, our game requires movement between rooms. I am not taking about adding doors to the room, though they are what the players use, I am taking about the underlying code for moving players between rooms. This is covered in "Linking the rooms"
While mazes are often enough, for this game we have a villain, who also happens to be in all the other dream sequences in this series, so in "Enter the Nasty" we cover the mechanism for getting the villain to appear. This obviously leads to "Losing and Winning" where we cover how to handle the nasty getting the player as well as the opposite but related player escaping from the nightmare.
With the game finished, this only leaves "Final Touches" where the title screen for the game is added. This covers what we will be doing over the next six fortnights, but the game is already on Spelchan.com so feel free to play the game while you wait for my sections on how the game was created.
In "Planning the Adventure" we take a look at how the game was designed. Adventure games tend to break areas that the player can visit into rooms, with the word room being a generic concept so outdoor areas are also referred to as rooms. For this game, all the rooms in the game are in fact rooms so the next step to the creation of this game is "Building the Rooms" which covers the techniques used to build the rooms used in this game. While it is a little but unconventional, it works for this game and the basic concepts are the same for other adventures.
While it is possible to have an adventure game that exists in a single room, such as a puzzle room, our game requires movement between rooms. I am not taking about adding doors to the room, though they are what the players use, I am taking about the underlying code for moving players between rooms. This is covered in "Linking the rooms"
While mazes are often enough, for this game we have a villain, who also happens to be in all the other dream sequences in this series, so in "Enter the Nasty" we cover the mechanism for getting the villain to appear. This obviously leads to "Losing and Winning" where we cover how to handle the nasty getting the player as well as the opposite but related player escaping from the nightmare.
With the game finished, this only leaves "Final Touches" where the title screen for the game is added. This covers what we will be doing over the next six fortnights, but the game is already on Spelchan.com so feel free to play the game while you wait for my sections on how the game was created.
Saturday, March 9, 2019
Blazing Games Life after Death
It has been
no secret that the Blazing Games site is going away in April. This may lead to
the question about what I am going to do with this blog after the site shuts
down? I have been thinking about dropping this blog keeping only my Homebrew Gamejam
blog but I am slowly porting the Flash and Java games from BlazingGames into
HTML5 and hosting the new versions on Spelchan.com. There are a lot of games
that I had created on BlazingGames so this process will take a very long time
so it makes sense to continue to keep this blog running. Besides, I have to
finish posting the chapters from my Making HTML5 Games using Animate eBook.
I will
continue posting the sections of the book each fortnight with updates on game
ports made between the chapters. In addition to Spelchan.com, I also have my
2600Dragons.com and will soon have TarotRevealed.com which is where I plan on
hosting my tarot games. There are a lot of pages that make up the site as well
as a lot of features that I would like to add to the site so this is going to
be a process that will take a fair amount of time. I am going to spread this
work out adding new layouts or features every month with the site being updated
on the 15th of each month.
Right now I
am running into some issues setting up the site (adding it to my hosting is
still pending) but hopefully the site will show up shortly and I will be able
to have the first version of the site ready by the 15th of this
month.
I would
like to be porting games much quicker than I currently am but at the moment am
working on my Masters degree so my spare time is very little. The few hours a
week that I allocate to working on both blogs, porting games, and developing my
emulator should probably be used for study but I consider this my time so try
to allocate some time for these projects. Naively I was hoping to get ahead of
the release schedule so that I wouldn’t need to worry about hitting release
dates but that has not been the case. My summer schedule is lighter but as we
are expected to work on our thesis at that time I suspect that my tune situation
will be just as bad in the summer. The Coffee Quest engine isn’t too bad so I
should have no problem releasing content for that series but I was really hoping
to do my revamped One of those Weeks and Ultimate Retro Project games.
Needless to
say, my focus for the larger project will be Coffee Quest and once that project is done I will have to
make a decision between Ultimate Retro Project and One of those Weeks. What I
want to do with OotW is very time consuming but I should be finished my Masters
degree so unless I decide to go for a PHD I should have more spare time. More
on this once I have finished posting the next chapter of the eBook, which will
be starting next fortnight.
Saturday, February 23, 2019
5.7 Closures
The bind function takes advantage of something in JavaScript known as a closure. This takes advantage of the way that scope works within JavaScript and can be used to hide variables within a function. For binding it is making sure that the reference to the object that created the object is tracked.
Scope simply is a term that describes which variables are known to a particular piece of code. The visibility of a variable depends on where it is declared. When declared outside of a function it is global and is visible to everything, including other scripts running on the same web page, which is why you do not want to have global variables in your code if you can help it. Variables declared within a function are only visible to code within that function. Variables declared within a loop are only visible to code within that loop, and so on. The code within the loop, however, can see all the variables in the scopes leading up to it.
The purpose of scope is two-fold. First, each layer of scope can be considered it's own name-space. Second, and more importantly, this allows JavaScript to know which variables are no longer needed and can be garbage collected so that the memory it used can be reclaimed for use by other things. There is an exception to this garbage collection rule, any variable that is still being referenced by another variable that is still in scope will not be garbage collected.
Functions within another function have access to the parent function's variables. This information is stored in a scope chain, the details of which are a bit beyond the scope of this chapter but the nutshell is that the function has access to the information contained within the function that created. This means that if we have a case where there is a reference to the inside function then even if the outside function goes out of scope, the outside functions data will not be garbage collected as it is still referenced by something that is still in-scope.
Here is a simple demonstration:
// General function for printing to the web page so results can be seen// without requiring the console
function printTestLine(s) {
// we are grabbing an html element
var results = document.getElementById("testResults");
// now append the new line to this element
results.innerHTML = results.innerHTML + "
" + s
}
function HiddingVariables(p, v) {
this.publicValue = p;
var hiddenValue = v;
this.getHiddenValue = function() {
return hiddenValue;
}
this.bindPrint = function() {
var owner = this;
return function() {
printTestLine("The hidden value is " + owner.getHiddenValue());
}
}
}
var hiddenVar = new HiddingVariables(21, 42);
printTestLine("Attempting to read public variable: " + hiddenVar.publicValue);
printTestLine("Attempting to read hidden variable: " + hiddenVar.hiddenValue);
printTestLine("Getting through method: " + hiddenVar.getHiddenValue());
setTimeout(hiddenVar.bindPrint(), 1000);
When the HiddingVariables function runs, the public value is stored as part of the object. The hidden variable is a local variable which means that it will go out of scope as soon as the function finishes running. As the function has a reference to this value, it is still visible to it. If you still don't quite understand how a closure works, don't worry too much as it is not necessary to understand them to use them.
Now that we have a basic understanding of classes we use some of these concepts in the next chapter when we create the Nightmare Maze game.
Scope simply is a term that describes which variables are known to a particular piece of code. The visibility of a variable depends on where it is declared. When declared outside of a function it is global and is visible to everything, including other scripts running on the same web page, which is why you do not want to have global variables in your code if you can help it. Variables declared within a function are only visible to code within that function. Variables declared within a loop are only visible to code within that loop, and so on. The code within the loop, however, can see all the variables in the scopes leading up to it.
The purpose of scope is two-fold. First, each layer of scope can be considered it's own name-space. Second, and more importantly, this allows JavaScript to know which variables are no longer needed and can be garbage collected so that the memory it used can be reclaimed for use by other things. There is an exception to this garbage collection rule, any variable that is still being referenced by another variable that is still in scope will not be garbage collected.
Functions within another function have access to the parent function's variables. This information is stored in a scope chain, the details of which are a bit beyond the scope of this chapter but the nutshell is that the function has access to the information contained within the function that created. This means that if we have a case where there is a reference to the inside function then even if the outside function goes out of scope, the outside functions data will not be garbage collected as it is still referenced by something that is still in-scope.
Here is a simple demonstration:
// General function for printing to the web page so results can be seen// without requiring the console
function printTestLine(s) {
// we are grabbing an html element
var results = document.getElementById("testResults");
// now append the new line to this element
results.innerHTML = results.innerHTML + "
" + s
}
function HiddingVariables(p, v) {
this.publicValue = p;
var hiddenValue = v;
this.getHiddenValue = function() {
return hiddenValue;
}
this.bindPrint = function() {
var owner = this;
return function() {
printTestLine("The hidden value is " + owner.getHiddenValue());
}
}
}
var hiddenVar = new HiddingVariables(21, 42);
printTestLine("Attempting to read public variable: " + hiddenVar.publicValue);
printTestLine("Attempting to read hidden variable: " + hiddenVar.hiddenValue);
printTestLine("Getting through method: " + hiddenVar.getHiddenValue());
setTimeout(hiddenVar.bindPrint(), 1000);
When the HiddingVariables function runs, the public value is stored as part of the object. The hidden variable is a local variable which means that it will go out of scope as soon as the function finishes running. As the function has a reference to this value, it is still visible to it. If you still don't quite understand how a closure works, don't worry too much as it is not necessary to understand them to use them.
Now that we have a basic understanding of classes we use some of these concepts in the next chapter when we create the Nightmare Maze game.
Sunday, February 10, 2019
5.6 Binding Events
The one really nice thing about classes is that they are a nice way of grouping data with the code that manipulates that data. This leads to a very common situation in programming where you want to do something with the data when an event happens. Event-driven programming is where the behavior of a program is structured around events instead of sequences and is the way you typicality approach user-interface related tasks. Combing objects with events seems like a no-brainer but this is where JavaScript starts showing some strangeness. To understand lets write a simple event.
// General function for printing to the web page so results can be seen
// without requiring the console
function printTestLine(s) {
// we are grabbing an html element
var results = document.getElementById("testResults");
// now append the new line to this element
results.innerHTML = results.innerHTML + "
" + s
}
// The timeout method uses a callback which gets called asyncronously
function tickTest(){
printTestLine("Tick Test was called!")
}
setTimeout(tickTest, 1500);
Timing events in JavaScript can be controlled by using a timeout. SetTimeout simply takes a function and a duration in milliseconds which are thousandths of a second. After the duration has expired it will call the function. Note that the timer is not precise and that the delay can be more than the specified amount bur for general usage timeouts are adequate. Running the above would result in a second-and-a-half delay before something was printed.
Now lets write a simple class that will store a value and when a function is called will display that value back.
// A simple class that stores a value and can display the currently stored value when asked to.function Demo() {
this.setValue = function(n) {
this.storedValue = n;
}
this.displayValue = function() {
printTestLine("Stored value is " + this.storedValue);
}
this.displayWithMessage = function(s) {
var str = "NO MESSAGE PROVIDED ";
if (s !== undefined)
str = s;
printTestLine(str + this.storedValue);
}
}
// as this shows, the class works as expected
var demo = new Demo();
demo.setValue(42);
demo.displayValue();
demo.displayWithMessage("Custom message before value ");
This works just fine so using it as part of an event seems trivial but lets try that.
// however, the value does not seem to exist if used as a callback.
setTimeout(demo.displayValue, 2000);
\end{lstlisting}
}
After a couple of seconds delay we get a rather interesting result. This is a byproduct of the way JavaScript calls methods within a function and is something that we will discuss in detail next fortnight. Obviously, this means that we can't use events with classes. But, as this is an obvious necessity, there is a bind function that browsers provide to solve this problem. By simply adding the bind function to the end of the function you are calling you will be able to specify which class the event is for. The function takes the instance of a class to use as it's parameter and does not need to be the calling instance but I can't think of any situation where I wouldn't want to use the same instance.
// this is where binding comes in
setTimeout(demo.displayValue.bind(demo), 2500);
// Binding also helps with parameters.
setTimeout(demo.displayWithMessage.bind(demo), 3000);
setTimeout(demo.displayWithMessage.bind(demo, "Message added in Binding "), 3000);
As can be seen from the demo code, binding can also be used to add additional parameters to a callback function. When dealing with situations such as having multiple buttons being handled by the same logic, this is an incredibly convenient feature of the bind function. But what exactly is the bind function doing? Tune in next fortnight to find out!
// General function for printing to the web page so results can be seen
// without requiring the console
function printTestLine(s) {
// we are grabbing an html element
var results = document.getElementById("testResults");
// now append the new line to this element
results.innerHTML = results.innerHTML + "
" + s
}
// The timeout method uses a callback which gets called asyncronously
function tickTest(){
printTestLine("Tick Test was called!")
}
setTimeout(tickTest, 1500);
Timing events in JavaScript can be controlled by using a timeout. SetTimeout simply takes a function and a duration in milliseconds which are thousandths of a second. After the duration has expired it will call the function. Note that the timer is not precise and that the delay can be more than the specified amount bur for general usage timeouts are adequate. Running the above would result in a second-and-a-half delay before something was printed.
Now lets write a simple class that will store a value and when a function is called will display that value back.
// A simple class that stores a value and can display the currently stored value when asked to.function Demo() {
this.setValue = function(n) {
this.storedValue = n;
}
this.displayValue = function() {
printTestLine("Stored value is " + this.storedValue);
}
this.displayWithMessage = function(s) {
var str = "NO MESSAGE PROVIDED ";
if (s !== undefined)
str = s;
printTestLine(str + this.storedValue);
}
}
// as this shows, the class works as expected
var demo = new Demo();
demo.setValue(42);
demo.displayValue();
demo.displayWithMessage("Custom message before value ");
This works just fine so using it as part of an event seems trivial but lets try that.
// however, the value does not seem to exist if used as a callback.
setTimeout(demo.displayValue, 2000);
\end{lstlisting}
}
After a couple of seconds delay we get a rather interesting result. This is a byproduct of the way JavaScript calls methods within a function and is something that we will discuss in detail next fortnight. Obviously, this means that we can't use events with classes. But, as this is an obvious necessity, there is a bind function that browsers provide to solve this problem. By simply adding the bind function to the end of the function you are calling you will be able to specify which class the event is for. The function takes the instance of a class to use as it's parameter and does not need to be the calling instance but I can't think of any situation where I wouldn't want to use the same instance.
// this is where binding comes in
setTimeout(demo.displayValue.bind(demo), 2500);
// Binding also helps with parameters.
setTimeout(demo.displayWithMessage.bind(demo), 3000);
setTimeout(demo.displayWithMessage.bind(demo, "Message added in Binding "), 3000);
As can be seen from the demo code, binding can also be used to add additional parameters to a callback function. When dealing with situations such as having multiple buttons being handled by the same logic, this is an incredibly convenient feature of the bind function. But what exactly is the bind function doing? Tune in next fortnight to find out!
Subscribe to:
Posts (Atom)