Thursday, 30 March 2023

Web Tutorial: Easter Egg Line Game (Part 4/4)

We've built most of the moving parts, now let's get to scoring, and ending the game. To do this, we need more properties in data. Add the pointsPerEgg property. Set it at 10. We can change this later if you feel like it.
data:
{
    started: false,
    paused: false,
    max: 100,
    moves: 50,
    remainingMoves: 50,
    pointsPerEgg: 10,
    score: 0,
    grid: [],
    selection: [],
    rainbow:
    {
        red: 0,
        orange: 0,
        yellow: 0,
        green: 0,
        blue: 0,
        indigo: 0,
        violet: 0
    }
},


Remember the confirm() method? The first For loop was for the selection array. In it, declare inc as a formula. If i is greater than 1, square the values of i less 1, then multiply by pointsPerEgg. If i is 1 or less, inc is 0. And then increment score by inc. What this does is, as long as there are more than 2 elements in selection, the player earns points. The more eggs above 2, the more points! If the player only has 2 eggs selected when clicking "CONFIRM", there are zero points.
for (var i = 0; i < this.selection.length; i++)
{
    var inc = (i > 1 ? (i - 1) * (i - 1) * this.pointsPerEgg : 0);
    this.score += inc;


    arr[this.selection[i][0]][this.selection[i][1]].style = "";
    arr[this.selection[i][0]][this.selection[i][1]].color = "";
}


Let's give this a go. If I select these 2 blue eggs and click "CONFIRM", I get 0 points.




But if I select these 4 blue eggs and click "CONFIRM"...




...I get 140 points!




Go on, count it. If pointsPerEgg is 10...

Egg 0: 0 points
Egg 1: 0 points
Egg 2: 1 x 1 x 10 = 10 points
Egg 3: 2 x 2 x 10 = 40 points
Egg 4: 3 x 3 x 10 = 90 points

The total is (10 + 40 + 90 = 140) points!

Now for more scoring! In the For loop, add a variable, color. Set it to the color property of the element in arr that is pointed to by the appropriate values in the current values of selection. Basically, that will be the color of the eggs in the selected line.
for (var i = 0; i < this.selection.length; i++)
{
    var color = arr[this.selection[i][0]][this.selection[i][1]].color;
    var inc = (i > 1 ? (i - 1) * (i - 1) * this.pointsPerEgg : 0);
    this.score += inc;

    arr[this.selection[i][0]][this.selection[i][1]].style = "";
    arr[this.selection[i][0]][this.selection[i][1]].color = "";
}


Increment the appropriate color in the rainbow object by 10. If the value has exceeded the value of max, set it to max.
for (var i = 0; i < this.selection.length; i++)
{
    var color = arr[this.selection[i][0]][this.selection[i][1]].color;
    var inc = (i > 1 ? (i - 1) * (i - 1) * this.pointsPerEgg : 0);
    this.score += inc;
    this.rainbow[color] += 10;
    if (this.rainbow[color] >= this.max) this.rainbow[color] = this.max;


    arr[this.selection[i][0]][this.selection[i][1]].style = "";
    arr[this.selection[i][0]][this.selection[i][1]].color = "";
}


Let's see what this does! If I select 4 green eggs, for example...




...the green stripe in the rainbow is filled up by 40%! Try selecting more green eggs and see if you can get above 100%. You shouldn't be able to (because of that If block we added to prevent that specifically), but you'll continue to score points anyway.




Now, what happens if we fill up the entire rainbow? We're about to handle that. In the confirm() method, we set paused to false at the end. Now instead, we will set it to the value returned by running the isEndGame() method, which will return either true or false. Thus, if it is an endgame scenario, the game will remain paused. Otherwise, pause is set to false and the game continues.
setTimeout(
    ()=>
    {
        this.fillMissingEggs();
        this.paused = this.isEndGame();
    },
    500
);


Create the method. In it, declare variable endGameScenario and set it to false by default. At the end of the method, return endGameScenario.
            setTimeout(
                ()=>
                {
                    this.fillMissingEggs();
                    this.paused = this.isEndGame();
                },
                500
            );
        },
        1000
    );
},
isEndGame: function()
{
    var endGameScenario = false;

    return endGameScenario;
},

isPossibleToMove: function()
{
    var possible = false;
    var arr = this.grid;

    for (var i = 0; i < arr.length; i++)
    {
        if (possible) break;

        for (var j = 0; j < arr[i].length; j++)
        {
            if (i > 0)
            {
                if (arr[i][j].color == arr[i - 1][j].color)
                {
                    possible = true;
                    break;
                }
            }

            if (i < arr.length - 1)
            {
                if (arr[i][j].color == arr[i + 1][j].color)
                {
                    possible = true;
                    break;
                }                                            
            }

            if (j > 0)
            {
                if (arr[i][j].color == arr[i][j - 1].color)
                {
                    possible = true;
                    break;
                }        
            }

            if (j < arr[i].length - 1)
            {
                if (arr[i][j].color == arr[i][j + 1].color)
                {
                    possible = true;
                    break;
                }    
            }
        }
    }

    return possible;
}


Right! Now, if remainingMoves is 0, that means there are no more moves and thus the game is over. In this case, we set endGameScenario to true.
isEndGame: function()
{
    var endGameScenario = false;

    if (this.remainingMoves == 0) endGameScenario = true;

    return endGameScenario;
},


If every property in the rainbow array is the value of max, then the game is also over.
isEndGame: function()
{
    var endGameScenario = false;

    if (this.remainingMoves == 0) endGameScenario = true;
    if (this.rainbow.red == this.max && this.rainbow.orange == this.max && this.rainbow.yellow == this.max && this.rainbow.green == this.max && this.rainbow.blue == this.max && this.rainbow.indigo == this.max && this.rainbow.violet == this.max) endGameScenario = true;

    return endGameScenario;
},


Here, we check if it's an endGameScenario. If not, we need to run the handleimpossibleScenario() method.
isEndGame: function()
{
    var endGameScenario = false;

    if (this.remainingMoves == 0) endGameScenario = true;
    if (this.rainbow.red == this.max && this.rainbow.orange == this.max && this.rainbow.yellow == this.max && this.rainbow.green == this.max && this.rainbow.blue == this.max && this.rainbow.indigo == this.max && this.rainbow.violet == this.max) endGameScenario = true;

    if (endGameScenario)
    {

    }
    else
    {
        this.handleimpossibleScenario();
    }


    return endGameScenario;
},


If it's time to end the game, we will do this fancy animation. We want the final score to appear, but we want the number to run! At the same time, the number of moves remaining will go to zero. The more moves remaining there are, the more points the user scores. So first, let us add this property, pointsPerMove, to data. Set it at 100. You can change it later.
data:
{
    started: false,
    paused: false,
    max: 100,
    moves: 50,
    remainingMoves: 50,
    pointsPerEgg: 10,
    pointsPerMove: 100,
    score: 0,
    grid: [],
    selection: [],
    rainbow:
    {
        red: 0,
        orange: 0,
        yellow: 0,
        green: 0,
        blue: 0,
        indigo: 0,
        violet: 0
    }
},


Back to the isEndGame() method, we declare scoreTimer and set it by running the setInterval() function with a 100 millisecond delay. It will run the code within every 100 milliseconds.
isEndGame: function()
{
    var endGameScenario = false;

    if (this.remainingMoves == 0) endGameScenario = true;
    if (this.rainbow.red == this.max && this.rainbow.orange == this.max && this.rainbow.yellow == this.max && this.rainbow.green == this.max && this.rainbow.blue == this.max && this.rainbow.indigo == this.max && this.rainbow.violet == this.max) endGameScenario = true;

    if (endGameScenario)
    {
        var scoreTimer = setInterval(
            ()=>
            {

            },
            100
        );

    }
    else
    {
        this.handleimpossibleScenario();
    }
    
    return endGameScenario;
},


In here, we check for the value of remainingMoves.
var scoreTimer = setInterval(
    ()=>
    {
        if (this.remainingMoves > 0)
        {

        }
        else
        {

        }

    },
    100
);


If it's more than 0, decrement it. And then increment score by pointsPerMove.
var scoreTimer = setInterval(
    ()=>
    {
        if (this.remainingMoves > 0)
        {
            this.remainingMoves--;
            this.score += this.pointsPerMove;

        }
        else
        {

        }
    },
    100
);


If it's arrived at 0, run clearInterval() on scoreTimer to stop the sequence. Then add the string "(GAME OVER)" to score. That's lazy AF, but it works, so blow me.
var scoreTimer = setInterval(
    ()=>
    {
        if (this.remainingMoves > 0)
        {
            this.remainingMoves--;
            this.score += this.pointsPerMove;
        }
        else
        {
            clearInterval(scoreTimer);
            this.score += " (GAME OVER)";

        }
    },
    100
);


Now we're going to test this. Play till you fill up the entire rainbow. Once you fill up the last stripe, you'll find that you can't click on the eggs anymore, or at least, there's no effect when you do. And then the numbers start moving till "Moves Remaining" is 0, with the scoreline increasing each time! You can also test what happens when you use up all your moves.




You may have noticed that the "REPLAY" button came on, as well, once the game ended. Do this, so that when the user clicks on it, it restarts the game.
<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-on:click="setStarted(true)" v-bind:style=getButtonVisibility("restart")>REPLAY</button>
</div>


Cleanup and stuff

Now let's give the game a nice header, using the styles we created.
<div class="title">
    <div class="letter red">E</div>
    <div class="letter orange">A</div>
    <div class="letter yellow">S</div>
    <div class="letter green">T</div>
    <div class="letter blue">E</div>
    <div class="letter indigo">R</div>
    <div class="square">
        <div class="egg style1 violet">
            <div>&nbsp;</div>
            <div>&nbsp;</div>
            <div>&nbsp;</div>
        </div>
    </div>
    <br style="clear:both" />
    <h2><i>line game</i></h2>

</div>


Here is the letter CSS class. We'll set height, width, and make it float left. Text is aligned center.
    .violet
    {
        background-color: rgb(200, 50, 200);
    }

    .letter
    {
        width: 50px;
        height: 55px;
        font-weight: bold;
        font-size: 3em;
        float: left;
        text-align: center;
        color: rgb(0, 0, 0);
    }

</style>


While we're doing this, let's remove the red outline.
div {outline: 0px solid red;}


Now this looks respectable! I really liked being able to add an egg at the end.




Phew, that's it!

This was quite a Herculean effort. But I think I did justice to this Easter's web tutorial. Go try it, and have fun playing it!

Have an AMAZING Easter,
T___T

No comments:

Post a Comment