Friday 8 April 2022

Web Tutorial: Easter Egg Hunt (Part 2/4)

Welcome back, programmers! In the previous part, we took care of the HTML and CSS for the application. We will now prepare the JavaScript portion.

In the script tag which has remained empty up to now, we add a game object. We then have jQuery's ready() method to execute any functionality we want on page load.

index.html
<script>
    let game = {

    };

    $( document ).ready(function()
    {

    });

</script>


For the game object, we have the following properties.

timeLeft - this is an integer that measures the minutes remaining.
eggs - this is an integer that keeps track of how many eggs have been collected so far.
visited - an array that keeps track of the locations in the story that the user has encountered.

index.html
let game = {
    "timeLeft" : 0,
    "eggs" : 0,
    "visited" : []


That's all for properties. We will now focus on methods. There are a bunch of methods we will be using, but we will be covering just a few for now. The first one is gotoSection(). It has three parameters - sectionName, mins and eggs. This is how it should work: when the method is run, the timeLeft and eggs properties of the game object should be modified according to the value of mins and eggs. And then content and choices will be displayed based on sectionName.

index.html
let game = {
    "timeLeft" : 0,
    "eggs" : 0,
    "visited" : [],
    "gotoSection" : function(sectionName, mins, eggs)
    {

    }

};


We begin this method by making sure that if sectionName is "begin", we reset the visited property to an empty array. We also run modifyTime() and modifyEggs() with mins and eggs passed in as arguments, respectively.

index.html
"gotoSection" : function(sectionName, mins, eggs)
{
    if (sectionName == "begin") game.visited = [];

    game.modifyTime(mins);
    game.modifyEggs(eggs);

}


Let us build these methods.

index.html
"gotoSection" : function(sectionName, mins, eggs)
{
    if (sectionName == "begin") game.visited = [];

    game.modifyTime(mins);
    game.modifyEggs(eggs);
},
"modifyTime" : function(mins)
{

},
"modifyEggs" : function(qty)
{

}


We will work on the modifyTime() method. Now pay close attention because this will be relevant later. Here we will handle two cases. The first case is when the value of mins is greater than 0. In that case, you set the value of the timeLeft property to mins.

index.html
"modifyTime" : function(mins)
{
    if (mins > 0) game.timeLeft = mins;
},


If the value of mins is less than 0, that means we want to deduct from timeLeft. And if the value is less than 0 after the deduction, we set it to 0.

index.html
"modifyTime" : function(mins)
{
    if (mins > 0) game.timeLeft = mins;
    if (mins < 0)
    {
        game.timeLeft += mins;

        if (game.timeLeft < 0) game.timeLeft = 0;
    }

},


Next, we work on the modifyEggs() method. We can pass a null into the method, which will ensure that it does nothing. So to that end, we have an If block that checks that qty is not null.

index.html
"modifyEggs" : function(qty)
{
    if (qty != null)
    {

    }

}


In that block we check if qty is 0. If so, we set the eggs property to 0.
index.html
"modifyEggs" : function(qty)
{
    if (qty != null)
    {
        if (qty == 0)
        {
            game.eggs = 0;
        }
        else
        {
    
        }

    }
}


If it is anything but 0, we increment eggs by that number. This might be a negative number, so if the result is less than 0, we set eggs to 0.

index.html
"modifyEggs" : function(qty)
{
    if (qty != null)
    {
        if (qty == 0)
        {
            game.eggs = 0;
        }
        else
        {
            game.eggs += qty;

            if (game.eggs < 0) game.eggs = 0;  
 
        }
    }
}


Now in the file sections.js, which we included in the last part of this web tutorial, we will add code. The first thing we need is the section object.

sections.js
let sections =
{

};


It is made out of several sub-objects, all with the same properties. We will add only one, for now. Let's call it "begin". It will have the following properties.

content - some HTML. Leave blank for the time being.
flag - to determine if we should record this section as being visited when encountered. false by default.
visitedChecks - more sub-objects that will determine extra content and choices. null by default.
messages - an array of useful messages to display when this section is encountered. Empty array by default.
choices - an array of objects. These are the links to different sections. Empty array by default.

sections.js
let sections =
{
    "begin" :
    {
        "content" : "",
        "flag" : false,
        "visitedChecks" : null,
        "messages" : [],
        "choices" : []
    }

};


For content, let's put in some HTML. Note that double quotes in the content have to be represented by HTML special characters. In this section, we will also have the image below.

img_easterbunny.jpg

The styling has already been done in the last part of this web tutorial.

sections.js
let sections =
{
    "begin" :
    {
        "content" : "<p>Easter has come. The sky is bright and cheery. You are on the porch of the house you live in, facing the Easter Bunny. The Easter Bunny wiggles his little nose and tells you, &quot;<b>Happy Easter! I have hidden several Easter eggs all around the garden, outside of the house. Your mission is to find 30 eggs within 120 minutes. Good hunting!</b>&quot; With that, he hops away.</p><p><img src='img_easterbunny.jpg'></p><p>You are now seated on the steps, and the hunt is under way.</p>",
        "flag" : false,
        "visitedChecks" : null,
        "messages" : [],
        "choices" : []
    }
};


For choices, each object looks something like this. The properties are:
time - the number to set the timeLeft property to, or subtract by.
eggs - the number to set the eggs property to, or add/subtract by.
section - the name of the section to go to when this choice is selected.
text - the text that appears beside the button.

sections.js
let sections =
{
    "begin" :
    {
        "content" : "<p>Easter has come. The sky is bright and cheery. You are on the porch of the house you live in, facing the Easter Bunny. The Easter Bunny wiggles his little nose and tells you, &quot;<b>Happy Easter! I have hidden several Easter eggs all around the garden, outside of the house. Your mission is to find 30 eggs within 120 minutes. Good hunting!</b>&quot; With that, he hops away.</p><p><img src='img_easterbunny.jpg'></p><p>You are now seated on the steps, and the hunt is under way.</p>",
        "flag" : false,
        "visitedChecks" : null,
        "messages" : [],
        "choices" :
        [
            { "time" : -1, "eggs" : null, "section" : "test", "text" : "Begin the hunt!"}
        ]
    }
};


None of that will be apparent now. We need to do some more work first. So let's get back to index.html and work on the gotoSection() method. The next thing we will do is grab the section that sectionName points to, and assign it to the variable section. We then get messages from the messages property of section.

index.html
"gotoSection" : function(sectionName, mins, eggs)
{
    if (sectionName == "begin") game.visited = [];

    var section = sections[sectionName];
    var messages = section.messages;

                    
    game.modifyTime(mins);
    game.modifyEggs(eggs);    
}


We follow up by grabbing content the same way we did for messages. choices as well... though in the case of choices, we also do a stringify() and parse() on the value so as to ensure that we clone the choices object from section.

index.html
"gotoSection" : function(sectionName, mins, eggs)
{
    if (sectionName == "begin") game.visited = [];

    var section = sections[sectionName];
    var messages = section.messages;
                    
    game.modifyTime(mins);
    game.modifyEggs(eggs);
    
    var content = section.content;
    var choices = JSON.parse(JSON.stringify(section.choices)); 
   
}


And then the next thing we do is run the showContent() method and pass content and messages into it as arguments. And we also run the showChoices() method, and pass in sectionName and choices as arguments.

index.html
"gotoSection" : function(sectionName, mins, eggs)
{
    if (sectionName == "begin") game.visited = [];

    var section = sections[sectionName];
    var messages = section.messages;
                    
    game.modifyTime(mins);
    game.modifyEggs(eggs);
    
    var content = section.content;
    var choices = JSON.parse(JSON.stringify(section.choices));    
    
    game.showContent(content, messages);
    game.showChoices(sectionName, choices);

}


Naturally, we next define showContent() and showChoices().

index.html
    game.showContent(content, messages);
    game.showChoices(sectionName, choices);
},
"showChoices" : function(sectionName, links)
{
                
},
"showContent" : function(content, messages)
{

},

"modifyTime" : function(mins)
{
    if (mins > 0) game.timeLeft = mins;
    if (mins < 0)
    {
        game.timeLeft += mins;

        if (game.timeLeft < 0) game.timeLeft = 0;
    }
},


Let us work on showContent() first. It will show (surprise, surprise) content and inventory, along with time left, and any messages that might need to be shown. We begin by putting a string within the div that has the CSS class timeLeft, to sow how many minutes are left.

index.html
"showContent" : function(content, messages)
{
    $(".timeleft").html(game.timeLeft + " minutes");
},


And then we do the same with the div with the CSS class inventory. However, because we will be expanding on this later, we first assign the string to the variable invStr.

index.html
"showContent" : function(content, messages)
{
    $(".timeleft").html(game.timeLeft + " minutes");

    var invStr = "Eggs x " + game.eggs + "<br />";
    $(".inventory").html(invStr);

},


The next thing we do, is populate the div that has the CSS class content, with the value of content.

index.html
"showContent" : function(content, messages)
{
    $(".timeleft").html(game.timeLeft + " minutes");

    var invStr = "Eggs x " + game.eggs + "<br />";
    $(".inventory").html(invStr);

    $(".content").html(content);
},


Next, if messages is not an empty array...

index.html
"showContent" : function(content, messages)
{
    $(".timeleft").html(game.timeLeft + " minutes");

    var invStr = "Eggs x " + game.eggs + "<br />";
    $(".inventory").html(invStr);

    $(".content").html(content);

    if (messages.length > 0)
    {
                        
    }
},


Now we create a new div. It will be the variable div. We also create a variable, messageStr, and set it to an empty string.

index.html
if (messages.length > 0)
{
    var div = $("<div class='message'></div>");
    var messageStr = "";          
             
}


Now we use a For loop to iterate through messages. We will append each string to messageStr, with a break tag.

index.html
if (messages.length > 0)
{
    var div = $("<div class='message'></div>");
    var messageStr = "";

    for (let i = 0; i < messages.length; i++)
    {
        messageStr += (messages[i] + "<br />");
    }  
                     
}


We set div's HTML content by using its html() method and passing in messageStr as an argument. After that, we insert div into the div styled using the CSS class content.

index.html
if (messages.length > 0)
{
    var div = $("<div class='message'></div>");
    var messageStr = "";

    for (let i = 0; i < messages.length; i++)
    {
        messageStr += (messages[i] + "<br />");
    }

    div.html(messageStr);
    $(".content").append(div); 
                       
}


It will not be visible until we call the gotoSection() method. So we call it in here. We pass in "begin", which is the name of the section we created in sections.js. The next argument is 120, which is what we want to set the timeLeft property to. After that, is 0, which is what we want to set the eggs property to.

index.html
$( document ).ready(function()
{
    game.gotoSection("begin", 120, 0);
});


Now you see this! The left column shows time left and eggs. The right column shows the HTML content we had in sections.js. See how the image of the bunny fits in - we handled all that CSS styling in the first part of this tutorial.




Now we add some test content into the messages property of the section we created.

sections.js
"begin" :
{
    "content" : "<p>Easter has come. The sky is bright and cheery. You are on the porch of the house you live in, facing the Easter Bunny. The Easter Bunny wiggles his little nose and tells you, &quot;<b>Happy Easter! I have hidden several Easter eggs all around the garden, outside of the house. Your mission is to find 30 eggs within 120 minutes. Good hunting!</b>&quot; With that, he hops away.</p><p><img src='img_easterbunny.jpg'></p><p>You are now seated on the steps, and the hunt is under way.</p>",
    "flag" : false,
    "visitedChecks" : null,
    "messages" : ['test1', 'test2'],
    "choices" :
    [
        { "time" : -1, "eggs" : null, "section" : "test", "text" : "Begin the hunt!"}
    ]
}


Note that we have to scroll down because the content is too large for the div. But you can see clearly the translucent black div with the red text.




Now revert that messages array to an empty array. We will work on the showChoices() method next. We begin by using the html() method to clear the HTML of the div that is styled using the CSS class choices.

index.html
"showChoices" : function(sectionName, links)
{
    $(".choices").html("");                
},


Then we use a For loop to go through the array links.

index.html
"showChoices" : function(sectionName, links)
{
    $(".choices").html("");

    for (let i = 0; i < links.length; i++)
    {
                                
    }  
             
},


For every element, we create a div and a button with the text "Go", and ensure that div has the text property specified in the current element of the links array. Then we append button to div. And after that, we append div to the div styled using the CSS class choices.

index.html
"showChoices" : function(sectionName, links)
{
    $(".choices").html("");

    for (let i = 0; i < links.length; i++)
    {
        var div = $("<div></div>");
        var button = $("<button>Go</button>");
        div.html(links[i].text);
        div.append(button);
       
$(".choices").append(div);                           
    }                
},


After that, we affix the gotoSection() method into the click event of button. In it, we pass in the appropriate arguments, which are provided by the current element in the links array.

index.html
"showChoices" : function(sectionName, links)
{
    $(".choices").html("");

    for (let i = 0; i < links.length; i++)
    {
        var div = $("<div></div>");
        var button = $("<button>Go</button>");
        div.html(links[i].text);
        div.append(button);
        $(".choices").append(div);

        button.click(()=> {
            game.gotoSection(links[i].section, links[i].time, links[i].eggs);
        });  
                             
    }                
},


The yellow button won't be clickable right now because the section it is pointing to does not exist, but at least the button shows up!




Now let us add one more button, which will appear for all scenarios. It is the restart button.

index.html
"showChoices" : function(sectionName, links)
{
    $(".choices").html("");

    for (let i = 0; i < links.length; i++)
    {
        var div = $("<div></div>");
        var button = $("<button>Go</button>");
        div.html(links[i].text);
        div.append(button);
        $(".choices").append(div);

        button.click(()=> {
            game.gotoSection(links[i].section, links[i].time, links[i].eggs);
        });                                
    }    
    
    var div = $("<div></div>");
    var button = $("<button>Go</button>");
    div.html("Restart");
    div.append(button);
    $(".choices").append(div);

    button.click(()=> {
        game.gotoSection("begin", 120, 0);
    });    

},


There you go. Click that button and you should still see the same thing. The magic is only apparent if you're in another section. No worries, we will handle that in the next part of this tutorial.




Next

We are going to dive right into inventory display!

No comments:

Post a Comment