Separating the data and view
While designing games, we usually want to separate the logic of manipulating data and the logic of displaying and drawing elements. In our logic, the composition and quest are data. The scenes are for displaying. That's why we use the gameScene.visualize
method to display data into the DOM element once we declare the quest composition data.
We need to dynamically create elements to represent the pattern in the quest DOM node. Sometimes we create HTML directly in JavaScript and append it to the node. A better approach is to have the HTML placed inside, well, HTML. That's why we have the template element for JavaScript to clone it and put it back into the quest node.
Note
Using the data-* attribute
It is often useful to use the data-*
attribute to embed extra information when we use DOM elements to represent game objects. Take the card as an instance. We can define data-pattern='3'
to indicate that element is a visual of pattern number 3. We can define whatever we like as long as it begins with data-
. Then, we can use the getAttribute
method to access it and use the setAttribute
method to update it. Alternatively, we can use the dataset
method to access the data-*
attribute.
Visualizing the quest patterns
A pattern is a stack of background-transparent cards. We can represent each card as a DIV and overlay them together in one container. In the composition node, we overlap the pattern by setting the position to absolute, top-left position to 0.
Whenever we use absolute elements, we want to make sure that we have control of the reference point of the top and left properties; this means controlling where the top 0 and left 0 positions are.
Elements that are positioned at the absolute point reference the top-left point in the following way:
- They find the first parent with a position and set it as absolute or relative
- They use the body's top-left point if no parents are found with the position's setting
Therefore, what we need to do is set a position that is relative to the container, namely, .composition
.
The position styling for the quest and pattern has been defined in the CSS. What we need to do is append the newly created HTML node to the quest node from the gameScene.visualize
method. The pattern HTML nodes are created from the template and with the class defined that match the CSS rules.
In this game, we require the player to select the pattern in the correct sequence to match the quest. However, some patterns are not overlapped with other patterns. In this case, we will put the two non-overlapped pairs together so that the order of choosing among these patterns will not be treated in the wrong order.
We would like to come up with an approach to compare the player's composition with the quest's composition.
The quest is composited by a sequence of patterns. A straightforward approach is to store the pattern sequence in an array. Then, all we need to do is compare whether the player's sequence is exactly the same as the given one.
Sounds good, but it fails in one case. In our patterns, there are some patterns that don't overlap with the others. Take the following pattern shown in the screenshot as an example:
The trapezoids to the left and right fit together without overlapping. We require the player to match the pattern visually so the sequence of these two selections does not change the effect, as shown in the following screenshot:
However, in the following pattern, the circle does overlap with the triangle:
Therefore, a simple sequence array does not work. Let's improve how we store the patterns in an array. How about using a 2-dimensional array?
The first dimension is the z index of the patterns, which is the sequence that players must match.
In order to represent the same level of relationship between the two trapezoids, we put them into one slot inside our array; thus, the array inside the code becomes the following:
To make the array item type consistent, we can force a single item to be wrapped inside the group too. Let's call each group of non-overlapped pattern layer.
Now, the final data array will be as follows:
Here, each array inside the quest level represents one layer with patterns that are interchangeable. Any overlapping pattern will be another new layer. Moreover, we put all the levels into an array to represent all the levels.