HTML5 Game Development by Example:Beginner's Guide(Second Edition)
上QQ阅读APP看书,第一时间看更新

Time for action – adding game logic to the matching game

We have prepared the game environment in the last example and decided the game logic should be the same as playing a real deck. It is time to code the JavaScript logic now:

  1. Let's begin from our last matching game example. We have styled the CSS, and now, it is time to add the game logic in the js/matchgame.js file.
  2. The game is to match pairs of playing cards. We have 12 cards now, so we need six pairs of playing cards. Put the following code in the js/matchgame.js file. The array declares six pairs of card patterns:
    var matchingGame = {};
    matchingGame.deck = [
      'cardAK', 'cardAK',
      'cardAQ', 'cardAQ',
      'cardAJ', 'cardAJ',
      'cardBK', 'cardBK',
      'cardBQ', 'cardBQ',
      'cardBJ', 'cardBJ',
    ];
  3. We aligned the cards in jQuery's ready function in the previous chapter. Now we need to prepare and initialize more code in the ready function. To do this, change the ready function into the following code. The changed code is highlighted here:
    $(function(){
     matchingGame.deck.sort(shuffle);
    
      for(var i=0;i<11;i++){
        $(".card:first-child").clone().appendTo("#cards");
      }
    
      $("#cards").children().each(function(index) {
        var x = ($(this).width() + 20) * (index % 4);
        var y = ($(this).height() + 20) * Math.floor(index / 4);
        $(this).css("transform", "translateX(" + x + "px) translateY(" + y + "px)");
    
     // get a pattern from the shuffled deck
     var pattern = matchingGame.deck.pop();
    
     // visually apply the pattern on the card's back side.
     $(this).find(".back").addClass(pattern);
    
     // embed the pattern data into the DOM element.
     $(this).attr("data-pattern",pattern);
    
     // listen the click event on each card DIV element.
     $(this).click(selectCard);
      });
    });
  4. Similar to playing a real deck, the first thing we want to do is shuffle the deck. To do this, we need to add the following shuffle function to the JavaScript file:
    function shuffle() {
      return 0.5 - Math.random();
    }
  5. When we click on the card, we flip it and schedule the checking function. So, we must append the following codes to the JavaScript file:
    function selectCard() {
      // we do nothing if there are already two card flipped.
      if ($(".card-flipped").size() > 1) {
        return;
      }
      $(this).addClass("card-flipped");
      // check the pattern of both flipped card 0.7s later.
      if ($(".card-flipped").size() === 2) {
        setTimeout(checkPattern,700);
      }
    }
  6. When two cards are opened, the following function is executed. It controls whether we remove the card or flip it back:
    function checkPattern() {
      if (isMatchPattern()) {
        $(".card-flipped").removeClass("card-flipped").addClass("card-removed");
        $(".card-removed").bind("transitionend",removeTookCards);
      } else {
        $(".card-flipped").removeClass("card-flipped");
      }
    }
  7. It is time for the pattern-checking function. The following function accesses the custom pattern attribute of the opened cards and compares them to see whether they are in the same pattern:
    function isMatchPattern() {
      var cards = $(".card-flipped");
      var pattern = $(cards[0]).data("pattern");
      var anotherPattern = $(cards[1]).data("pattern");
      return (pattern === anotherPattern);
    }
  8. After the matched cards fade out, we execute the following function to remove the cards:
    function removeTookCards() {
      $(".card-removed").remove();
    }
  9. The game logic is ready now. Let's open the game's HTML file in a browser and play. Remember to check the console window in Developer Tools to see whether there is any error.

The following screenshot shows the CSS3 Card Matching game:

What just happened?

We coded the game logic of the CSS3 matching game. The logic adds the mouse click interaction to the playing cards, and it controls the flow of pattern checking. You can try the game and view the full source code at http://makzan.net/html5-games/card-matching-wip-step2/.

Executing code after the CSS transition has ended

We remove the paired cards after playing the fade out transition. We can schedule a function to be executed after the transition has ended by using the transitionend event. The following code snippet from our code example adds a card-removed class to the paired card to start the transition. Then, it binds the transitionend event to remove the card complete with the DOM, afterwards:

$(".card-flipped").removeClass("card-flipped").addClass("card-removed");
$(".card-removed").bind("transitionend", removeTookCards);

Delaying code execution on flipping cards

The game logic flow is designed in the same way as playing a real deck. One big difference is that we used several setTimeout functions to delay the execution of the code. When the second card is clicked, we schedule the checkPattern function to be executed 0.7 seconds later by using the following code example snippet:

if ($(".card-flipped").size() == 2) {
  setTimeout(checkPattern, 700);
}

The reason we delay the function call is to give time to the player to memorize the card pattern.

Randomizing an array in JavaScript

There is no built-in array randomize function in JavaScript. We have to write our own. Luckily, we can get help from the built-in array sorting function.

Here is the usage of the sort function:

sort(compare_function);

The sort function takes one optional argument:

The trick here is that we used the compare function that returns a random number between -0.5 and 0.5:

anArray.sort(shuffle);
function shuffle(a, b) {
  return 0.5 - Math.random();
}

By returning a random number in the compare function, the sort function sorts the same array in an inconsistent way. In other words, we shuffle the array.

Note

The following link from the Mozilla Developer Network provides a detailed explanation on using the sort function with examples:

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort

Storing internal custom data with an HTML5 custom data attribute

We can store custom data inside the DOM element by using the custom data attribute. We can create a custom attribute name with the data- prefix and assign a value to it.

For instance, we can embed custom data to the list elements in the following code:

<ul id="games">
  <li data-chapter="2" data-difficulty="easy">Ping-Pong</li>
  <li data-chapter="3" data-difficulty="medium">Matching Game</li>
</ul>

This is a new feature proposed in the HTML5 spec. According to the W3C, the custom data attributes are intended to store custom data that is private to a page or an application for which there are no more appropriate attributes or elements.

W3C also states that this custom data attribute is "intended for use by the site's own script and not a generic extension mechanism for publicly-usable metadata."

We are coding our matching game and embedding our own data to the card elements; therefore, custom data attribute fits our usage.

We use the custom attribute to store the card pattern inside each card so that we can check by comparing the pattern value whether the two flipped cards match in JavaScript. In addition, the pattern is used to style the playing cards into corresponding graphics as well:

$(this).find(".back").addClass(pattern);
$(this).attr("data-pattern",pattern);

Pop quiz

Q1. According to W3C's guidelines about the custom data attribute, which of the following statements is true?

  1. We can create a data-link attribute to store the link of the css tag.
  2. We can access the custom data attribute in a third-party game portal website.
  3. We can store a data-score attribute in each player's DOM element to sort the ranking in our web page.
  4. We can create a ranking attribute in each player's DOM element to store the ranking data.

Accessing custom data attribute with jQuery

In the matching game example, we used the attr function from the jQuery library to access our custom data:

pattern = $(this).attr("data-pattern");

The attr function returns the value of the given attribute name. For example, we can get the links in all the a tags by calling the following code:

$("a").attr("href");

For the HTML5 custom data attribute, jQuery provides us with another function to access the HTML5 custom data attribute. This is the data function.

Data function was designed to embed custom data into the jQuery object of the HTML elements. It was designed before the HTML5 custom data attribute.

Here is the usage of the data function:

.data(key)
.data(key,value)

The data function accepts two types of functions:

In order to support the HTML5 custom data attribute, jQuery extends the data function to let it access the custom data that is defined in the HTML code.

Now, let's see how we use the data function. Consider the following line of an HTML code:

<p id="target" data-custom-name="HTML5 Games"></p>

Now, using the preceding line of code, we can access the data-custom-name attribute by calling the data function in jQuery:

$("#target").data("customName")

This will return "HTML5 Games".

Note

Keep in mind that attr would always return a string value. However, the data method will attempt to convert the HTML string value into a JavaScript value, such as a number or a Boolean.

Pop quiz

Q1. Given the following HTML code, which jQuery statements read the custom score data and return 100 in the integer format?

<p id="game" data-score="100"></p>
  1. $("#game").attr("data-score");
  2. $("#game").attr("score");
  3. $("#game").data("data-score");
  4. $("#game").data("score");

Have a go hero

We have created the CSS3 matching game. So, what is missing here? The game logic does not check whether the game is over. Try adding a "You won!" text when the game is over. You can also animate the text by using the techniques that we discussed in this chapter.

Making other playing card games

This CSS3 playing card approach is suitable to create card games. There are two sides on a card that fit the flipping. The transition feature is suitable to move the cards. With both moving and flipping, we can just define the playing rule and make the most of the card games.

Have a go hero

Can you use the playing card graphics and flipping techniques to create another game? How about poker?