In this part, we will need more data for gameplay.
Add
started and
paused as Boolean values, set to
false.
started and
paused are used to determine what buttons are available.
paused is also meant to disable certain functions while animation is running.
data:
{
started: false,
paused: false,
max: 100,
moves: 50,
remainingMoves: 50,
score: 0,
grid: [],
rainbow:
{
red: 0,
orange: 0,
yellow: 0,
green: 0,
blue: 0,
indigo: 0,
violet: 0
}
},
In the
reset() method, set
paused to
false. That's because we want to un-pause whenever there's a reset.
reset: function()
{
this.resetEggs();
this.remainingMoves = this.moves;
this.score = 0;
this.rainbow = {
red: 0,
orange: 0,
yellow: 0,
green: 0,
blue: 0,
indigo: 0,
violet: 0
};
this.handleimpossibleScenario();
this.paused = false;
},
Now in the HTML, bind the styles of the buttons to the
setButtonVisibility() method, passing in the names of the buttons as arguments.
<div class="bottom">
<br />
<button v-bind:style=getButtonVisibility("confirm")>CONFIRM</button>
<button v-bind:style=getButtonVisibility("start")>BEGIN</button>
<button v-bind:style=getButtonVisibility("stop")>STOP GAME</button>
<button v-bind:style=getButtonVisibility("restart")>REPLAY</button>
</div>
And then create the method. Declare
vis. By default, it is "none". We return a style string using the value of
vis.
getMarginTop: function(color)
{
var percentage = this.max - this.rainbow[color];
return "margin-top:" + ((percentage / this.max) * 480) + "px";
},
getButtonVisibility: function(section)
{
var vis = "none";
return "display:" + vis;
},
getEggClass: function(c, s)
{
return "egg " + this.grid[c][s].style + " " + this.grid[c][s].color;
},
So first of all, we handle the scenarios for "start". We use the "start" button only if
started is
false and we want to set it to
true. But regardless, if the game is paused, the button is hidden.
getButtonVisibility: function(section)
{
var vis = "none";
if (section == "start" && !this.started) vis = "block";
if (this.paused) vis = "none";
return "display:" + vis;
},
And then there's the other buttons. We should only be able to stop a game if
started is
true. And we should only be able to restart a game if
remainingMoves is 0 (which means the game is over).
getButtonVisibility: function(section)
{
var vis = "none";
if (section == "start" && !this.started) vis = "block";
if (this.paused) vis = "none";
if (section == "stop" && this.started) vis = "block";
if (section == "restart" && this.started && this.remainingMoves == 0) vis = "block";
return "display:" + vis;
},
Now, because
started is
false, only the "BEGIN" button is visible!
Let us add an action to the button. It calls the
setStarted() method, passing the value
true in as an argument.
<div class="bottom">
<br />
<button v-bind:style=getButtonVisibility("confirm")>CONFIRM</button>
<button v-on:click="setStarted(true)" v-bind:style=getButtonVisibility("start")>BEGIN</button>
<button v-bind:style=getButtonVisibility("stop")>STOP GAME</button>
<button v-bind:style=getButtonVisibility("restart")>REPLAY</button>
</div>
The method starts off by setting
started to the value of the parameter
started, which is either
true or
false.
getEggClass: function(c, s)
{
return "egg " + this.grid[c][s].style + " " + this.grid[c][s].color;
},
setStarted: function(started)
{
this.started = started;
},
fillMissingEggs: function()
{
var arr = this.grid;
for (var i = 0; i < arr.length; i++)
{
for (var j = 0; j < arr[i].length; j++)
{
if (arr[i][j].style == "" && arr[i][j].color == "")
{
arr[i][j] = this.getRandomPair();
}
}
}
this.grid = [];
this.grid = arr;
},
If the value of the parameter
started is
true, we also call
reset(). If not, we set the value of
paused to
false.
setStarted: function(started)
{
this.started = started;
if (started)
{
this.reset();
}
else
{
this.paused = false;
}
},
Now we set an action to the "STOP GAME" button. Again, we call
setStarted() but pass in
false as an argument.
<div class="bottom">
<br />
<button v-bind:style=getButtonVisibility("confirm")>CONFIRM</button>
<button v-on:click="setStarted(true)" v-bind:style=getButtonVisibility("start")>BEGIN</button>
<button v-on:click="setStarted(false)" v-bind:style=getButtonVisibility("stop")>STOP GAME</button>
</div>
Refresh. Click the "BEGIN" button. You should see it disappear to be replaced by the "STOP GAME" button. If you click that, it should revert to the "BEGIN" button.
Let's spruce up this interface a little in the meantime. Make this change to the styling for
middle. Remove the specification for
height. Add two other properties.
overflow should be set to
hidden, and we set
transition to 1 second because we're going to animate this.
.middle
{
width: 100%;
float: left;
/*height: 500px;*/
overflow: hidden;
webKit-transition: all 1s;
transition: all 1s;
}
In the div styled using
middle, bind the
style attribute to the
getMiddleHeight() method, passing in "game" as an argument.
<div class="middle" v-bind:style=getMiddleHeight("game")>
Now add a div, also styled using
middle, also with the
style attribute bound. This time, however, the argument should be "instructions".
<div class="middle" v-bind:style=getMiddleHeight("instructions")>
</div>
<div class="middle" v-bind:style=getMiddleHeight("game")>
<div class="grid">
Maybe add some text.
<div class="middle" v-bind:style=getMiddleHeight("instructions")>
<h1>Instructions</h1>
<p>Your objective is to form a full rainbow in as few moves as possible.</p>
<p>Select a line (2 or more) of similarly colored eggs and click CONFIRM. This counts as one move, and we fill up the appropriate color on the meter.</p>
<p>A line can be any combination of horizontal or vertical lines.</p>
<p>The game ends when you run out of moves, or when a full rainbow is formed.</p>
<p>Extra points are earned from lines greater than 2 eggs.</p>
</div>
And then create the
getMiddleHeight() method. We start by declaring
height, which is set to 0 by default. At the end, we return a style string using the value of
height.
getMarginTop: function(color)
{
var percentage = this.max - this.rainbow[color];
return "margin-top:" + ((percentage / this.max) * 480) + "px";
},
getMiddleHeight: function(section)
{
var height = 0;
return "height:" + height + "px";
},
getButtonVisibility: function(section)
{
var vis = "none";
if (section == "start" && !this.started) vis = "block";
//if (section == "confirm" && this.selection.length >= 2) vis = "block";
if (this.paused) vis = "none";
if (section == "stop" && this.started) vis = "block";
if (section == "restart" && this.started && this.remainingMoves == 0) vis = "block";
return "display:" + vis;
},
And here, we handle the cases. If the value of
section is "game" and
started is
true, we set
height to 500. If the value of section is "instructions" and the game is not started, we set
height to 500. This basically means that either one of the divs that have been styled using
middle, will be visible depending on the value of
started.
getMiddleHeight: function(section)
{
var height = 0;
if (section == "game" && this.started) height = 500;
if (section == "instructions" && !this.started) height = 500;
return "height:" + height + "px";
},
Try it! Now you should see a panel of instructions when you refresh the game. When you click on "BEGIN GAME", thus setting
started to
true, the grid appears to scroll up! It's actually because the height of that div was 0 when
started was
false, and since the
overflow property is
hidden, that means the grid is not visible. And only partially visible when the height of the div is more than 0. Same for the instructions panel!
Just to make it look nicer, encase the instructions in a div and style it using
instructions.
<div class="middle" v-bind:style=getMiddleHeight("instructions")>
<div class="instructions">
<h1>Instructions</h1>
<p>Your objective is to form a full rainbow in as few moves as possible.</p>
<p>Select a line (2 or more) of similarly colored eggs and click CONFIRM. This counts as one move, and will fill up the appropriate color on the meter.</p>
<p>A line can be any combination of horizontal or vertical lines.</p>
<p>The game ends when you run out of moves, or when a full rainbow is formed.</p>
<p>Extra points are earned from lines greater than 2 eggs.</p>
</div>
</div>
Here's the styling for
instructions. Just making it look pretty, so don't worry about it.
.middle
{
width: 100%;
float: left;
overflow: hidden;
webKit-transition: all 1s;
transition: all 1s;
}
.instructions
{
border-radius: 10px;
background-color: rgb(100, 100, 100);
width: 80%;
height: 80%;
padding: 10px;
margin: 5% auto 0 auto;
overflow: hidden;
}
.grid
{
width: 500px;
height: 100%;
float: left;
}
Yup!
Time for gameplay!
We're supposed to be able to click the eggs to select them, so add an event to each square. Clicking on them will run the
selectSquare() method, passing in the values of
c and
s as arguments.
<div class="square" v-for="(s, square) in col" v-on:click="selectSquare(c, s)">
<div v-bind:class="getEggClass(c, s)">
<div> </div>
<div> </div>
<div> </div>
</div>
</div>
Create the method.
setStarted: function(started)
{
this.started = started;
if (started)
{
this.reset();
}
else
{
this.paused = false;
}
},
selectSquare: function(c, s)
{
},
fillMissingEggs: function()
{
var arr = this.grid;
for (var i = 0; i < arr.length; i++)
{
for (var j = 0; j < arr[i].length; j++)
{
if (arr[i][j].style == "" && arr[i][j].color == "")
{
arr[i][j] = this.getRandomPair();
}
}
}
this.grid = [];
this.grid = arr;
},
Because we will be working with the
selection array, add this to
data as an empty array.
data:
{
started: false,
paused: false,
max: 100,
moves: 50,
remainingMoves: 50,
score: 0,
grid: [],
selection: [],
rainbow:
{
red: 0,
orange: 0,
yellow: 0,
green: 0,
blue: 0,
indigo: 0,
violet: 0
}
},
And make sure that in
reset(), it's set to an
empty array.
reset: function()
{
this.resetEggs();
this.remainingMoves = this.moves;
this.score = 0;
this.selection = [];
this.rainbow = {
red: 0,
orange: 0,
yellow: 0,
green: 0,
blue: 0,
indigo: 0,
violet: 0
};
this.handleimpossibleScenario();
this.paused = false;
},
Now back to the
selectSquare() method. Firstly, exit early if the value of
paused is
true. If the game is paused, we don't want anything to happen.
selectSquare: function(c, s)
{
if (this.paused) return;
},
Declare the variable
reset and set to
false by default. At the end of the method, if
reset has somehow been set to
true, set
selection to an empty array.
selectSquare: function(c, s)
{
if (this.paused) return;
var reset = false;
if (reset) this.selection = [];
},
Now declare
insertPos and set the value by calling the
isLinkableAtPos() method, passing in the value of
c and
s. The method should return either 0 (if linkable at the beginning of selection) or 1 (linkable at the end of selection) or
null (not linkable at all).
selectSquare: function(c, s)
{
if (this.paused) return;
var reset = false;
var insertPos = this.isLinkableAtPos(c, s);
if (reset) this.selection = [];
},
Now, we have another method,
isInSelection(). We call it and pass in the value of
c and
s. It's going to return either
true (yes, that particular square is already selected) or
false (no, it isn't). So if the result is
false and the value of
insertPos is
null, we need to reset the
selection array.
selectSquare: function(c, s)
{
if (this.paused) return;
var reset = false;
var insertPos = this.isLinkableAtPos(c, s);
if (!this.isInSelection(c, s) && insertPos == null)
{
reset = true;
}
if (reset) this.selection = [];
},
Now, if
insertPos is 0, we call
unshift() to insert the array containing
c and
s in the beginning of
selection. If it's 1, use
push() to insert at the end of
selection.
selectSquare: function(c, s)
{
if (this.paused) return;
var reset = false;
var insertPos = this.isLinkableAtPos(c, s);
if (!this.isInSelection(c, s) && insertPos == null)
{
reset = true;
}
if (insertPos == 0 && insertPos != null)
{
this.selection.unshift([c, s]);
}
else
{
this.selection.push([c, s]);
}
if (reset) this.selection = [];
},
And of course, we need to define the methods
isLinkableAtPos() and
isInSelection().
getEggClass: function(c, s)
{
return "egg " + this.grid[c][s].style + " " + this.grid[c][s].color;
},
isInSelection: function(c, s)
{
},
isLinkableAtPos: function(c, s)
{
},
setStarted: function(started)
{
this.started = started;
if (started)
{
this.reset();
}
else
{
this.paused = false;
}
},
isInSelection() is simpler, so let's do that first. By default, it returns
false. In this method, there are two parameters,
c and
s.
isInSelection: function(c, s)
{
return false;
},
isLinkableAtPos: function(c, s)
{
},
Before that, we iterate through selection. If at any time, the array containing
c and
s shows up, we return
true.
isInSelection: function(c, s)
{
for (var i = 0; i < this.selection.length; i++)
{
if (this.selection[i][0] == c && this.selection[i][1] == s) return true;
}
return false;
},
That was simple enough! Now we will work on
isLinkableAtPos(). In this method, again, there are two parameters,
c and
s. First, if there are no elements in the
selection array, we return 1 to tell the parent method,
selectSquare(), that we can push the array containing
c and
s into selection. By default, we return
null.
isLinkableAtPos: function(c, s)
{
if (this.selection.length == 0) return 1;
return null;
},
Let's break away for a bit to add this into the
getEggClass() method. In here, we will add the
outline CSS class if a call to
isInSelection() returns
true.
getEggClass: function(c, s)
{
return "egg " + this.grid[c][s].style + " " + this.grid[c][s].color + " " + (this.isInSelection(c, s) ? "outline" : "");
},
Here's the outline CSS class. In fact, while we're at it, we will set this to the
hover pseudoselector of egg. So if you mouse over an egg, it has a
white dotted outline. If you click on it and add it to the
selection array, the outline should be solid!
.egg
{
width: 70%;
height: 90%;
border-radius: 50%/60% 60% 40% 40%;
overflow: hidden;
position: relative;
margin: 2px auto 0 auto;
filter: opacity(100);
}
.egg:hover
{
outline: 2px dotted rgb(255, 255, 255);
}
.egg.outline
{
outline: 2px solid rgb(255, 255, 255);
}
.egg:after
{
display: block;
position: absolute;
content: "";
width: 100%;
height: 100%;
}
Now try positioning your mouse cursor over an egg (in this example, it's one of the
red eggs in the middle. Does the
white dotted outline appear? If you mouse out, it should disappear.
If you click on it, it should now be a solid
white outline! If you click elsewhere, the outline should disappear because
null was returned.
Now back to the
isLinkableAtPos() method. We need to cater to other cases. First, we declare variables.
firstNodeLocationCompatible is a flag that determines if the egg selected is right next to the first egg in the
selection array, either horizontally or vertically.
lastNodeLocationCompatible does the same, except for the last egg in the
selection array.
colorCompatible checks if the selected egg is the same color as all elements in the
selection array. By default, the value is
false.
isLinkableAtPos: function(c, s)
{
if (this.selection.length == 0) return 1;
var firstNodeLocationCompatible = false;
var lastNodeLocationCompatible = false;
var colorCompatible = false;
return null;
},
Declare
firstNode, and set it to the first element in the
selection array. Also declare
lastNode as the last element in the
selection array. At this point, there should be at least one element in the array because the case where there are no elements, has already been handled with the guard clause at the beginning of the method.
isLinkableAtPos: function(c, s)
{
if (this.selection.length == 0) return 1;
var firstNodeLocationCompatible = false;
var lastNodeLocationCompatible = false;
var colorCompatible = false;
var firstNode = this.selection[0];
var lastNode = this.selection[this.selection.length - 1];
return null;
},
Now remember that
firstNode and
lastNode are both arrays containing two elements - column and row indexes. First we need to determine if
firstNodeLocationCompatible is
true. So if the first element of
firstNode matches
c and and the second element of
firstNode is 1 removed from
s (we use
abs() to determine this), this means that the selected egg is next to the first egg vertically.
isLinkableAtPos: function(c, s)
{
if (this.selection.length == 0) return 1;
var firstNodeLocationCompatible = false;
var lastNodeLocationCompatible = false;
var colorCompatible = false;
var firstNode = this.selection[0];
var lastNode = this.selection[this.selection.length - 1];
if ((firstNode[0] == c && Math.abs(firstNode[1] - s) == 1)) firstNodeLocationCompatible = true;
return null;
},
If the second element of
firstNode matches
s and and the first element of
firstNode is 1 removed from
c (again, we use
abs() to determine this), this means that the selected egg is next to the first egg horizontally. Now if the selected egg is either horizontally or vertically next to that first egg, firstNodeLocationCompatible is true.
isLinkableAtPos: function(c, s)
{
if (this.selection.length == 0) return 1;
var firstNodeLocationCompatible = false;
var lastNodeLocationCompatible = false;
var colorCompatible = false;
var firstNode = this.selection[0];
var lastNode = this.selection[this.selection.length - 1];
if ((firstNode[0] == c && Math.abs(firstNode[1] - s) == 1) || (firstNode[1] == s && Math.abs(firstNode[0] - c) == 1)) firstNodeLocationCompatible = true;
return null;
},
The same logic goes for
lastNode and
lastNodeLocationCompatible.
isLinkableAtPos: function(c, s)
{
if (this.selection.length == 0) return 1;
var firstNodeLocationCompatible = false;
var lastNodeLocationCompatible = false;
var colorCompatible = false;
var firstNode = this.selection[0];
var lastNode = this.selection[this.selection.length - 1];
if ((firstNode[0] == c && Math.abs(firstNode[1] - s) == 1) || (firstNode[1] == s && Math.abs(firstNode[0] - c) == 1)) firstNodeLocationCompatible = true;
if ((lastNode[0] == c && Math.abs(lastNode[1] - s) == 1) || (lastNode[1] == s && Math.abs(lastNode[0] - c) == 1)) lastNodeLocationCompatible = true;
return null;
},
And then we get the
color property from the element of
grid pointed to by
c and
s, and compare it to the
color property from the element of
grid pointed to by the array in
firstNode. If there's a match,
colorCompatible is
true.
isLinkableAtPos: function(c, s)
{
if (this.selection.length == 0) return 1;
var firstNodeLocationCompatible = false;
var lastNodeLocationCompatible = false;
var colorCompatible = false;
var firstNode = this.selection[0];
var lastNode = this.selection[this.selection.length - 1];
if ((firstNode[0] == c && Math.abs(firstNode[1] - s) == 1) || (firstNode[1] == s && Math.abs(firstNode[0] - c) == 1)) firstNodeLocationCompatible = true;
if ((lastNode[0] == c && Math.abs(lastNode[1] - s) == 1) || (lastNode[1] == s && Math.abs(lastNode[0] - c) == 1)) lastNodeLocationCompatible = true;
if (this.grid[firstNode[0]][firstNode[1]].color == this.grid[c][s].color) colorCompatible = true;
return null;
},
If
colorCompatible is
true and
firstNodeLocationCompatible is
true, that means we can return 0 to say that the selected egg can be added to the beginning of the
selection array. If
colorCompatible is
true and
lastNodeLocationCompatible is
true, we return 1 to say that the selected egg can be added to the end of the
selection array.
isLinkableAtPos: function(c, s)
{
if (this.selection.length == 0) return 1;
var firstNodeLocationCompatible = false;
var lastNodeLocationCompatible = false;
var colorCompatible = false;
var firstNode = this.selection[0];
var lastNode = this.selection[this.selection.length - 1];
if ((firstNode[0] == c && Math.abs(firstNode[1] - s) == 1) || (firstNode[1] == s && Math.abs(firstNode[0] - c) == 1)) firstNodeLocationCompatible = true;
if ((lastNode[0] == c && Math.abs(lastNode[1] - s) == 1) || (lastNode[1] == s && Math.abs(lastNode[0] - c) == 1)) lastNodeLocationCompatible = true;
if (this.grid[firstNode[0]][firstNode[1]].color == this.grid[c][s].color) colorCompatible = true;
if (firstNodeLocationCompatible && colorCompatible) return 0;
if (lastNodeLocationCompatible && colorCompatible) return 1;
return null;
},
Now test this! Select an egg. In this example, I've selected a
violet egg from the large clump of
violet eggs in the middle. But if we then click on the
green egg directly above it, it would get deselected, meaning the
selection array would be empty.
If we were to select the
violet egg two eggs to the right, it would also be deselected.
You can only select
violet eggs right net to the initially selected
violet egg, and the first and last eggs in the "line" changes with each egg added. For instance, now, if we were to click on the
violet egg directly below the selected line of
violet eggs, right next to the
indigo egg, the
selection array would get cleared as well. Because that egg, while the same color, is not horizontally or vertically next to the first and last eggs in the line.
Now that we're able to select eggs, we need to make sure that the "CONFIRM" button is shown when a minimum of two eggs are selected. In
getButtonVisibility(), make sure that if
section is "confirm" and
selection has at least 2 elements, we set
vis accordingly. Of course, if
paused is true, everything is still hidden. The following line takes care of that.
getButtonVisibility: function(section)
{
var vis = "none";
if (section == "start" && !this.started) vis = "block";
if (section == "confirm" && this.selection.length >= 2) vis = "block";
if (this.paused) vis = "none";
if (section == "stop" && this.started) vis = "block";
if (section == "restart" && this.started && this.remainingMoves == 0) vis = "block";
return "display:" + vis;
},
See what we did? When the two
blue eggs are selected, the "CONFIRM" button appears! Try deselecting. The button should disappear again!
Let's set the "CONFIRM" button to run the method
confirm().
<div class="bottom">
<br />
<button v-on:click="confirm()" v-bind:style=getButtonVisibility("confirm")>CONFIRM</button>
<button v-on:click="setStarted(true)" v-bind:style=getButtonVisibility("start")>BEGIN</button>
<button v-on:click="setStarted(false)" v-bind:style=getButtonVisibility("stop")>STOP GAME</button>
<button v-bind:style=getButtonVisibility("restart")>REPLAY</button>
</div>
Create the
confirm() method. We begin by decrementing
remainingMoves.
getRandomPair: function()
{
var randomIndex;
randomIndex = Math.floor(Math.random() * 3) + 1;
var style = "style" + randomIndex;
randomIndex = Math.floor(Math.random() * 7);
var color = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"][randomIndex];
return {"style": style, "color": color};
},
confirm: function()
{
this.remainingMoves--;
},
isPossibleToMove: function()
{
var possible = false;
var arr = this.grid;
We create
arr as a temporary variable, setting it to the value of
grid because we don't want the grid to re-render until we're good and ready. We want to make those changes in
arr first. And then we set
paused to
true because there is going to be animation and we want to make sure that clicking stuff while it's going on, does not do anything.
confirm: function()
{
this.remainingMoves--;
var arr = this.grid;
this.paused = true;
},
Then we iterate through the
selection array and make sure that all elements in
arr that correspond with the element in selection, have the CSS class
fadeout added to their styling. This means that any egg inside the grid that has been selected, is now styled using
fadeout. And then we set
grid to the value of
arr.
confirm: function()
{
this.remainingMoves--;
var arr = this.grid;
this.paused = true;
for (var i = 0; i < this.selection.length; i++)
{
arr[this.selection[i][0]][this.selection[i][1]].style += " fadeout";
}
this.grid = [];
this.grid = arr;
},
This is the
fadeout CSS class. In here, we ensure that opacity is set to 0 and we have a
transition duration of 1.
.egg
{
width: 70%;
height: 90%;
border-radius: 50%/60% 60% 40% 40%;
overflow: hidden;
position: relative;
margin: 2px auto 0 auto;
filter: opacity(100);
}
.fadeout
{
webkit-transition: all 1s;
transition: all 1s;
filter: opacity(0);
}
.egg:hover
{
outline: 2px dotted rgb(255, 255, 255);
}
Now do a selection and click the "CONFIRM" button. For illustration, I have selected a bunch of
indigo eggs.
And watch the indigo eggs fade out! The "CONFIRM" button disappears because pause is now true. Also note that the top right display now says "49 / 50" because
remaningMoves has been decremented.
Back to the
confirm() method! Now we're left with gaping
black hole within the grid. We will need to fill them in... but it's not as simple as it sounds. First, we use the
setTimeout() function to ensure that the next piece of code executes only after the
fadeout animation is done. So if the
fadeout CSS class is set to 1 second duration, make sure the
setTimeout function delays for 1000 milliseconds.
confirm: function()
{
this.remainingMoves--;
var arr = this.grid;
this.paused = true;
for (var i = 0; i < this.selection.length; i++)
{
arr[this.selection[i][0]][this.selection[i][1]].style += " fadeout";
}
this.grid = [];
this.grid = arr;
setTimeout(
()=>
{
},
1000
);
},
So first, we iterate through the
selection array to ensure that all those elements that we added the
fadeout CSS class to, now have the
style and
color properties reset to empty strings.
confirm: function()
{
this.remainingMoves--;
var arr = this.grid;
this.paused = true;
for (var i = 0; i < this.selection.length; i++)
{
arr[this.selection[i][0]][this.selection[i][1]].style += " fadeout";
}
this.grid = [];
this.grid = arr;
setTimeout(
()=>
{
for (var i = 0; i < this.selection.length; i++)
{
arr[this.selection[i][0]][this.selection[i][1]].style = "";
arr[this.selection[i][0]][this.selection[i][1]].color = "";
}
},
1000
);
},
The next bit is going to be crazy. We want to go through every column, and look for any squares that are empty (
style and
color are empty strings), When we find them, we want to replace them with the values from the eggs above. So it looks like eggs are "falling" into place. So first, we examine each and every column of
arr using a
For loop.
confirm: function()
{
this.remainingMoves--;
var arr = this.grid;
this.paused = true;
for (var i = 0; i < this.selection.length; i++)
{
arr[this.selection[i][0]][this.selection[i][1]].style += " fadeout";
}
this.grid = [];
this.grid = arr;
setTimeout(
()=>
{
for (var i = 0; i < this.selection.length; i++)
{
arr[this.selection[i][0]][this.selection[i][1]].style = "";
arr[this.selection[i][0]][this.selection[i][1]].color = "";
}
for (var i = 0; i < arr.length; i++)
{
}
},
1000
);
},
Now, we iterate through the current array inside
arr, from the rear. Meaning, we work from the bottom. We don't do it for element 0 because there's no element above 0. So if there's any element at position 0 (at the top of the column) is empty, they will be filled in with random eggs. More on that later.
for (var i = 0; i < arr.length; i++)
{
for (var j = arr[i].length - 1; j > 0; j--)
{
}
}
Now we check to see if the
style property is an empty string.
for (var i = 0; i < arr.length; i++)
{
for (var j = arr[i].length - 1; j > 0; j--)
{
if (arr[i][j].style == "")
{
}
}
}
If so, we traverse that particular array from that index onwards, all the way up to 0...
for (var i = 0; i < arr.length; i++)
{
for (var j = arr[i].length - 1; j > 0; j--)
{
if (arr[i][j].style == "")
{
for (var k = j; k >= 0; k--)
{
}
}
}
}
...and during that traversal, if the current element is not empty, the previous element needs to take on its
style and
color properties. And we will set the current element to empty.
for (var i = 0; i < arr.length; i++)
{
for (var j = arr[i].length - 1; j > 0; j--)
{
if (arr[i][j].style == "")
{
for (var k = j; k >= 0; k--)
{
if (arr[i][k].style != "")
{
arr[i][j].style = arr[i][k].style;
arr[i][j].color = arr[i][k].color;
arr[i][k].style = "";
arr[i][k].color = "";
break;
}
}
}
}
}
And then we will empty
selection and update
grid!
confirm: function()
{
this.remainingMoves--;
var arr = this.grid;
this.paused = true;
for (var i = 0; i < this.selection.length; i++)
{
arr[this.selection[i][0]][this.selection[i][1]].style += " fadeout";
}
this.grid = [];
this.grid = arr;
setTimeout(
()=>
{
for (var i = 0; i < this.selection.length; i++)
{
arr[this.selection[i][0]][this.selection[i][1]].style = "";
arr[this.selection[i][0]][this.selection[i][1]].color = "";
}
for (var i = 0; i < arr.length; i++)
{
for (var j = arr[i].length - 1; j > 0; j--)
{
if (arr[i][j].style == "")
{
for (var k = j; k >= 0; k--)
{
if (arr[i][k].style != "")
{
arr[i][j].style = arr[i][k].style;
arr[i][j].color = arr[i][k].color;
arr[i][k].style = "";
arr[i][k].color = "";
break;
}
}
}
}
}
this.selection = [];
this.grid = arr;
},
1000
);
},
Try this. Select a line of eggs. For example, I have selected
green eggs. Then click "CONFIRM".
Now there's the fadeout, leaving a gaping hole...
And then you see the eggs at the top have fallen down to fill in the holes, leaving the gaps at the top!
Now use
setTimeout() again with a delay of 500 milliseconds. In there, use
fillMissingEggs() to fill in the empty elements with random eggs. And then set
paused to
false so that the "CONFIRM" button appears after the animation is done.
confirm: function()
{
this.remainingMoves--;
var arr = this.grid;
this.paused = true;
for (var i = 0; i < this.selection.length; i++)
{
arr[this.selection[i][0]][this.selection[i][1]].style += " fadeout";
}
this.grid = [];
this.grid = arr;
setTimeout(
()=>
{
for (var i = 0; i < this.selection.length; i++)
{
arr[this.selection[i][0]][this.selection[i][1]].style = "";
arr[this.selection[i][0]][this.selection[i][1]].color = "";
}
for (var i = 0; i < arr.length; i++)
{
for (var j = arr[i].length - 1; j > 0; j--)
{
if (arr[i][j].style == "")
{
for (var k = j; k >= 0; k--)
{
if (arr[i][k].style != "")
{
arr[i][j].style = arr[i][k].style;
arr[i][j].color = arr[i][k].color;
arr[i][k].style = "";
arr[i][k].color = "";
break;
}
}
}
}
}
this.selection = [];
this.grid = arr;
setTimeout(
()=>
{
this.fillMissingEggs();
this.paused = false;
},
500
);
},
1000
);
},
No more screenshots. Just try the animations and see if it's working for you.
Next
Scoring, filling up the rainbow, and ending the game!