Book Image

HTML5 Game Development Hotshot

By : Seng Hin Mak, Makzan Makzan (Mak Seng Hin)
Book Image

HTML5 Game Development Hotshot

By: Seng Hin Mak, Makzan Makzan (Mak Seng Hin)

Overview of this book

Table of Contents (15 chapters)
HTML5 Game Development HOTSHOT
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Comparing the player and compositions of the quest


In this task, we create logic to make multilayered pattern compositions from player's selection and then compare it with the quest pattern's composition.

Prepare for lift off

We need a way to represent the pattern overlapping and non-overlapping relationships.

Representing a pattern overlapping relationship

We will use the data structure of this section to remember the overlapping relationship. Most patterns will overlap others, so we would need to think the other way round. So, we store those patterns that do not overlap together.

The pattern is a two-dimensional (2D) array. The first dimension contains every pattern. Each pattern is a list of the other patterns that do not overlay with it.

For example, the following A pattern does not overlap with the C and D shapes. We represent it with the ensuing equation:

array['A'] = [ 'C', 'D'];

For a pattern that always overlaps with the others, an empty array will be assigned.

Engage thrusters

In the following steps, we code the logic that allows us to compare two given quest compositions:

  1. In the composition.js file, we have the following class variable to represent the relationship of the overlapping patterns. It indicates the pattern that overlaps with other patterns. The index of the nonOverlappedPattern array is the pattern ID, and the corresponding array value is the list of patterns that do not overlap with that pattern:

    // static variable. available as only one copy among all composition instances.
    Composition.nonOverlappedPattern = [
      [], // pattern 0
      [2], // pattern 1, doesn't overlap with pattern 2.
      [1], // pattern 2, doesn't overlap with pattern 1.
      [], // pattern 3
      [], // pattern 4
      [6], // pattern 5, doesn't overlap with pattern 6.
      [5], // pattern 6, doesn't overlap with pattern 5.
     ];
  2. We create the following new method in the Composition method that can turn a composition back to a one-dimension array:

    Composition.prototype.toSequence = function() {
      var seq = [];
      for (var i=0; i < this.data.length; i++) {
        for (var j=0; j <this.data[i].length; j++ ) {
          seq.push(this.data[i][j]);
        }
      }
      return seq;
    }
  3. Then, we create the createFromSequence method with the following code that turns a sequence back to a composition:

    Composition.createFromSequence = function(sequence) {
      // function to determine if 2 given patterns overlap.
      var allowPatternsInSameLevel = 
        function(patternA, patternB) {
          // iterate the array to see if current pattern overlaps the
          var nonOverlappedPattern = Composition.nonOverlappedPattern[patternA]
          var len = nonOverlappedPattern.length;
          for (var i=0; i<len; i++) {
            if (nonOverlappedPattern[i] === parseInt(patternB)) {
              return true;
            }
          }
          return false;
        };
      // layer is an array that contains existing pattern
      var layerAllowsPattern = function(layer, pattern) {
        for (var i=0, len=layer.length; i<len; i++) {
          if (!allowPatternsInSameLevel(layer[i], pattern)) {
            return false;
          }
        }
        return true;
      };
      // end helper functions
    
      var newComposition = new Composition();
      var layer = [];
      for (var i=0, len=sequence.length; i<len; i++) {
        if (layerAllowsPattern(layer, sequence[i])) { 
          // we are still in same layer.
          layer.push(sequence[i]);
        } else {  
          // two patterns overlapped, 
          // we push the current layer to composition 
          // and use a new layer for the current pattern.
          newComposition.data.push(layer);
          layer = []; // new array instance to prevent browser using the same array and crashes the data.
          layer.push(sequence[i]);
        }
      }
      // for the last layer
      if (layer.length> 0) newComposition.data.push(layer); 
      return newComposition;
    }
  4. We add a new method to the Quest method that can compare two multilayered pattern compositions and check whether they are equal to each other:

    Quest.prototype.isEqualToComposition = function(composition) {
      var a = this.data;
      var b = composition.data;
    
      // sort each level in both array
      for (var i=0, len=a.length; i<len; i++) {
        a[i].sort();
      }
      for (var i=0, len=b.length; i<len; i++) {
        b[i].sort();
      }
      // flatten both compositions into sequence.
      a = this.toSequence();
      b = composition.toSequence();
    
      if (a.length !== b.length) return false;
      for (var i=0, len=a.length; i<len; i++) {
        if (parseInt(a[i]) !== parseInt(b[i])) return false;
      }
      return true;
    }
  5. In the composition-view.js file, we check whether the player's latest selection matches the quest level. Therefore, in both the selectPattern and undo methods, we keep a composition from the sequence and check it with the quest level:

    selectPattern: function(pattern) {
      ...
      game.composition = game.Composition.createFromSequence(game.compositionSeq);
      if (game.quest.isEqualToComposition(game.composition)){
        game.flow.gameWin();
      }
    },
    undo: function() {
      ...
      game.composition =   game.Composition.createFromSequence(game.compositionSeq);
      if (game.quest.isEqualToComposition(game.composition))   
      {
        game.flow.gameWin();
      }
    },

Objective complete – mini debriefing

The comparison requires us to create a multilayered pattern composition from the selection sequence. Then, we compare the player's one with that of the quest level.

Composition is a two-dimensional array that we need to compare between the quest and the player's selection. However, the player's selection is a sequence that does not reflect our layer's structure. This is the reason why we need a conversion between the composition and the sequence. Moreover, we need to keep a copy of the player's sequence because we need that information for the undo feature.

Comparing players and compositions of the quest

In our createFromSequence method, we created two helper functions to manipulate multilayered patterns. The allowPatternsInSameLevel function checks whether the given two patterns can be overlapped together by looking up the non-overlapped pattern table. The layerAllowsPattern function makes use of the previous function and checks whether the given pattern fits all other patterns inside the given layer, which is an array of all non-overlapped patterns put together.

The createFromSequence method makes use of the function to scan the selection array in a sequence and then put each pattern into either the same layer (without overlapping) or a new layer.

Finally, we have the isEqualToComposition method in the quest instance to compare the player's selection composition with the quest level's one. This method sorts all the layers in both the compositions into the same order and then converts the composition back to a one-dimension array using the toSequence method.

This ensures the player's selection can match our defined level of data on non-overlapping patterns, regardless of the order of selection.

Classified intel

We attach the relationship of non-overlapping patterns directly to the composition object because they are the same, regardless of each instance. Attaching it to the composition instead of the instance's prototype prevents this block of data from being copied to each instance.