Debugging the Jelly Gravity Game



Objective: Fix the bugs in the Jelly Wobbly Gravity GameWe are using the book Learn HTML5 by Creating Fun Games and its provided source code to explore HTML5, CSS3, and JavaScript. The code in the Chapter 4 folder (which actually goes with Chapter 3 in the book) does not work! The game will start but has some serious flaws.What are the functional requirements for the game? Run the game and determine which of these requirements is met:Provide drag-and-drop functionality for the lid on bowl of “jellies”. When the lid is dragged onto the target area, start the game. Enable the following steps after game startsAllow player to move the character (named “dude” in code) left or right when arrow keys are pressed. Spew a new jelly out of the bowl at regular intervals; assign random values for: color, velocity, change amount for x (horizontal position), change amount for y (vertical position)At regular intervals, move each jelly that is in play; each jelly should have a different pathNew position varies based on velocity and change amount for x and y, factoring in the gravity. Increase velocity for each moveIf a jelly hits the floor, splatter it and stop its movementIf a jelly hits the dude, reduce his health barWhen the dude’s health bar is at 0 the dude becomes sick triggering the end game sceneWhat’s wrong in this picture?38481001233170The “dude” is stuck and won’t move with arrow keys00The “dude” is stuck and won’t move with arrow keys1390650375920All jellies stack at same x (horizontal) position. Jellies splatter without hitting the floor.00All jellies stack at same x (horizontal) position. Jellies splatter without hitting the floor.Take a Look at the Structure of the Game’s Code:Before jumping into debugging a program with whose code we are unfamiliar, it helps to get an overview of the structure. In Cloud9 we can use Code Folding to collapse the details within each block of code. From menu: Edit --> Code Folding --> Fold All. Here is a partial view of the results:Naming Conventions:This illustrates how important it is to give functions and variables meaningful names!What function names sound like they may have something to do with moving the character when a key is pressed? What function might set the starting position of the dude?Debugging the “Dude’s” Moves: The character controlled by the player is supposed to move when the left or right arrow keys are pressed. At the start of the game event listeners are assigned to the key up and key down events. Let’s first look at those in action:Setting breakpoints for the key event handlers:View game in Chrome: Run the game in Cloud9 and view it in the Chrome Browser. Before dragging the lid off the bowl, open Developer Tools using F12 or right-click and Inspect. Or shortcut keys Ctrl-Shift-C on Windows or Cmd-Shift-C on MacFind the event handler code: Select the Sources tab in Dev Tools, then the game.js file in the js folder of the sources. In the game.js file find the function doOnKeyDown. Hint: use ctrl-F or cmd-F shortcut to open the FIND input box. Set a breakpoint on the first line of code inside the doOnKeyDown function by clicking the line number in the margin; a blue block pointing to the right should appear on the line numberRun to breakpoint and step through code: Drag the lid off the jelly bowl and drop it on target; then press the left arrow key to attempt to move the dude. The game should pause and at the top of the screen you will see:See event argument value: Hover over the word “which” in the line switch (event.which) to see the value that was passed to the event. If you pressed the left arrow it will be “37”Step into the next line of code: click the down arrow icon in the right-most panel. Note that it will set the dude.isMoving.left property to true.Examine the dude object: Step into the next line of code (“break;”. Then hover over the word “dude” in dude.isMoving.leftA detailed object viewer pops up right below the word “dude”The dude SVG graphic is selected on the game screen16098591609859Hovering over the “dude” object in code shows the detailed properties within the object. The box can be scrolled and indicator arrows within can expand00Hovering over the “dude” object in code shows the detailed properties within the object. The box can be scrolled and indicator arrows within can expand3108101566670When the “dude” object is selected in code below, the SVG element it represents is highlighted0When the “dude” object is selected in code below, the SVG element it represents is highlightedSet a watch on the dude object: In the right panel click the + in the Watch bar to add an expression; type the word dude. Adding a watch to a variable during program execution is an extremely valuable tool for developers. We can now see what changes in the complicated object that is the dude:Analyze what happened when we pressed the key: we saw that the key event handler is setting the value for the dude’s isMoving property. And we can see in the watch window that dude.isMoving.left has been set to true. So the code in the key event doesn’t seem to be the problem.OK, the dude object has an isMoving.left property that has been set to true; the object then “knows” it should be moving to the left, but what code actually looks at that property and executes the move?Let’s search for “isMoving.left”. Using the Find command shows us 4 places containing that code; but all except one of those lines of code are simply setting the value. The one line of code that uses it to do something is a Conditional inside the Tick() function which executes at regular intervals:Put a breakpoint on the line “if (dude.isMoving.left)” and un-pause the debugger to run to that line of code. Step into the next line of code and examine the properties of the dude object by hovering over “dude.pos.x” in the code and by looking in the Watch window:76843946793236232563691941090411158839Hovering over the object in code shows that dude.pos.x is NaN; the same is shown in the Watch windowHovering over the object in code shows that dude.pos.x is NaN; the same is shown in the Watch windowNaN: not a number! This means the calculation of the dude’s position will fail!Trace the bug back another step:Find the line of code where dude.pos.x is set; it is set at the start of the Tick function each time the interval runs and in the startGame function. Which would make sense to debug first to get at the root of the problem?Set a breakpoint in startGame:Restart the game by refreshing the Web page; drag the lid off the bowl to kick off the startGame function. Look at what the debugger show us about the initial x position of the dude:126642341669Before running this line of code the value of dude.pos.x is 0 as seen by hovering over the code and in the Watch window!Before running this line of code the value of dude.pos.x is 0 as seen by hovering over the code and in the Watch window!105606818665After running the above line of code, the value of dude.pos.x is “undefined” in the Watch window! Hovering over the value “dude.offsetLeft” on the right side of the assignment statement reveals why00After running the above line of code, the value of dude.pos.x is “undefined” in the Watch window! Hovering over the value “dude.offsetLeft” on the right side of the assignment statement reveals whyGoogle It! What is offsetLeft and why is it undefined?“The?HTMLElement.offsetLeft?read-only property returns the number of pixels that the?upper left corner of the?current element is offset to the left within the?HTMLElement.offsetParent?node.”So every HTMLElement has an offsetLeft, why doesn’t the dude have one?Look at our index.html to see where the dude is defined:SVG elements are NOT HTMLElements! The dude is built from Scalable Vector Graphics (SVG) which are defined inside an SVG element. Although it is layered inside a <div> HTMLElement, the SVG is not itself an HTMLElement so doesn’t have any of the offset properties (offsetLeft, offsetTop, offsetRight, offsetBottom)More Googling! Workaround for SVG Positioning: article and several others tell us that we can create a variable that represents the box that surrounds the SVG graphic element with the getBoundingClientRect() function. We can use that box variable for positioning.Fix the starting position:In the game.js file, inside startGame() function find the line that says dude.pos.x = dude.offset;Make these changes:Comment out the original line of codeAdd a comment explaining the change; multiline comments are enclosed between /* and */Set the dude.pos.x to dude.getBoundingClientRect().left;Code should resemble this://dude.pos.x = dude.offsetLeft;/* FVGCC: the above line to establish starting position was causing a bug where the dude wouldn't move at all in response to arrow keys! Debugger revealed the offsetLeft is undefined for the dude; it turns out that an SVG element does not have the offsetLeft property. Added the following line to get the left value for the dude; this does let the dude move! */ dude.pos.x = dude.getBoundingClientRect().left;Run the game in the Browser again. To force the Browser to refresh its cache and load the updated JavaScript use ctrl-F5 in Windows; in Mac use Shift and the Reload button or Cmd-shift-R(? Please check this…)You should now be able to move the dude using the left and right arrow keysFix the rest of the bugs:We will provide an updated JavaScript file with all of these fixes; and you can swap it into your game!Here are the bugs that are observed and all are caused by misuse of the offset propertiesIn startGame function initial position of Dude is not set properly; we’ve just fixed that!getHeight function for the jelly is returning “undefined”getWidth function for the jelly is returning “undefined”In the tick function the code that is supposed to reposition the dude if he is moving right and hits the right edge is not able to correctly determine that he is at the edgeIn the tick function, the code that checks each jelly for a collision is never detecting a collision even when the jelly is right on top of the dudeTo copy the file with all the bug fixes:Go to?Wobbly Jelly Gravity Corrected JavaScriptClick the "Raw" button when viewing the fileRight-click and select "save as" to save it to your machineTo Load the file into your Cloud9 Project:In the menu choose File --> Upload Local FilesDrag the file from your Finder or File Explorer to the popup window or manually select the fileSave it under Chapter 4\js. You should now have a game.js and a gameFVGCC.js file thereSwap in the Correct JavaScript:In your index.html file for Chapter 4, find the <script> tag just above the closing </body> tagChange the name of the file; you may wish to comment out the original file name if you want to swap back and forth to do any further debugging/analysisGlossary/Concepts:Variable:?a named data element representing a piece of information to be rememberedExamples of variables in game:var jellies = [];var MAX_JELLIES = 50;var jellyHP = 5.75;var hitFloor = false;var dude = document.querySelector(".dude-svg").cloneNode(true);var jellyModel = document.querySelector(".jelly-model");These represent several types of data. Each variable is initialized with the value on the right side of the “=”. The variable “jellies” is set up as an array, i.e., a list that can contain multiple items; during the game each new jelly created gets added to the “jellies” array. The variable “hitFloor” holds a Boolean, i.e., true or false value. The variable “MAX_JELLIES” represents a Constant, i.e., a value that will not change during code execution. Naming a variable with all caps is the naming convention for a constantThe most interesting variables here may be “dude” and” jellyModel” as they are initialized by finding elements in the HTML document that have class=dude-svg or class=jelly-model. These two variables will be treated as objects with multiple properties.Object Properties: in JavaScript, an object variable has a collection of properties with names and values. We access an object’s property in code by the syntax objectName.propertyName, aka the dot operator.Examples of object properties in the game:var dude = document.querySelector(".dude-svg").cloneNode(true);dude.isDead = false;dude.isMoving = {left: false, right: false};dude.pos = {x : 0, moveBy : 11.75};After we create the object variable named “dude”, we create properties and assign values to those properties. We create a Boolean “isDead” property and assign it the value false. We create the “isMoving” property and assign it a value which is itself an object having “left” and “right” properties. We access these properties using the dot operator; note the two “dots” used for the second line of code:if (!dude.isDead) {if (dude.isMoving.right) {Function: A Block of code that encapsulates specific functionality, typically limited to accomplishing one task. The Function may take one or more parameters as inputs. The Function will be “called” by another code section when it is neededParameter: a defined piece of data to be input into a block of code; it may be required or optional. When the program is executed the parameter value will be set by the corresponding argument passed into the code blockArgument: value passed into a block of code to tell the code the current value of a parameterLoop:? a code control structure that causes code to be repeated a specified number of times or based on a condition (while or until some condition is true). Loop example: the game needs to do something for each of the jellies. It does this by using a “for” loop:// Iterate through each jelly and check its state for (var i in jellies) {// code goes inside the {} to handle a jelly; the code is executed repeatedly until each of the jellies has been handled }Event:?Something that happens for which a program can “listen”. It can be something the user does such as clicking a button, pressing a key, dragging and dropping an element, or something the Browser does such as finish loading a Web page, or firing a timer at a regular interval in response to JavaScript. Code blocks called Event Handlers can be “hooked” to events so they will execute when the event occurs. We hook an Event Handler to an event via an Event ListenerEvent Example: The game needs to respond to the events of a user pressing a key; in the startGame() function, event listeners are set up for the “keyup” and the “keydown” events. document.body.addEventListener("keyup", doOnKeyUp);This code says that when the “keyup” event occurs, the function named doOnKeyUp will be executed; that function is the Event Handler for the “keyup” event.Conditional: a flow of control structure that determines what code gets executed based on a decision. If the condition is true a certain block of code will be executed. Sometimes it will have an “else” condition defined as well as an “if” condition. Conditions can be “nested” as in this example:if (dude.isMoving.left) { if (dude.pos.x < 425) { dude.pos.x = 425; } else { dude.pos.x -= dude.pos.moveBy; dude.style.left = dude.pos.x + "px"; } } ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download