cs255 ยป



Now, in this unit, we're going to be going over the basics of JavaScript, and how to interact with a modern browser. Things like manipulating the DOM, accessing JSON and making an XMLHttp request.

JavaScript Syntax

Now first thing we start off with, is we create a variable here called RenderEngineClass. And you define a variable by starting with the key word var, and then the variable name. And then you say equals, whatever you'd like it to be equal to. In this case we use an opening brace, to indicate that we'd like this to be a JavaScript object. This is the object literal notation, for defining an object in JavaScript. From there we can declare methods and member variables of that object by specifying the name of the member, a colon and then the value that it's going to take. In this case we declare the method to have the name drawString, we use a colon and then we say that this is going to be a function, we use the keyword function to define this and then we give a list of all the parameters. And then open the function with an opening brace. Similarly to how you would in many other languages. Now, again, we create a variable, name it, and then assign to it, the value of gRenderEngine.context. Now this is going to take the JavaScript object, gRenderEngine, and the dot notation is going to tell us that we want the context member of this object. And we do something similar down here where we, grab the font member of the ctx object and assign it this value here. Now you notice that we're using addition and strings. Addition is overloaded in JavaScript to also designate string concatenation. Again similar to a lot of other languages you might have seen. Next we have an example of an if statement. If statements work essentially the same way that they would in any other language where you have the keyword if, then in parentheses you specify the predicate that's going to return a boolean value, either true or false and then the body of the if statement that executes if that evaluates to true. Now, note that the statement here doesn't have braces around it designating what executes if the if statement evaluates to true. This is similar to some other languages where, if there's a single line that you need to evaluate, you don't require those braces. We use this here or there, just for readability purposes. So you might see this in the code. Now for larger if blocks, you can delineate them with a opening brace, and then once they are done, way down here, you close them with another brace. From there we have a number more examples of declaring and setting variables. And then we come to a for loop. For loops are structured essentially the same way they are in C. Where we have an initializer value, then a predicate to evaluate for when the for loop should end. And then an expression to execute at the end of each for loop. And similarly, to you if blocks, the block of code that you'd like to execute each time the for loop runs, is delineated by braces. Although again, if it's a single line, you don't require those braces to be there. Now here we see words[n] where n is in square braces. And, again, n is the variable that our for-loop is looping over. This is an example of accessing a list, where n is the nth element in that list. Now, like most other languages, this is zero indexed as well. So keep that in mind.

Bug Hunting

Alright, so let's take a look at another piece of code. Now this is another bit of the game we'll be building, but there are a few errors here, that we've added in. Your job is to go through this code, find the errors that were introduced, and then fix them based on the syntax you learned previously. Good luck.

Bug Hunting

Okay, so I hope that wasn't to bad, there are only a few errors that you needed to spot. Lets go through them one at a time. The first one is right here, you can see that this is opened with and opened square bracket, but it's closed with an angle bracket, and this should be a square bracket right here. Now, the next error is right down here. And this is, and this is missing a semicolon after the first section of the 4 loop. Now, the next error we'd like to point out is this if statement right here. We need parentheses around this not entity clause. Let's go ahead and add those in.


Now there's one more error in this code, but it's tricky to catch. And it's tricky because, the JavaScript engine of most browser won't catch it either. Let's take a look at that for a second. Now, if you go back up to the top here, you might notice that There's no semi-colon at the end of this ent.update statement. Technically, JavaScript requires semi-colons here. But, the javascript engines in most browsers will actually fix this for you. That is, JavaScript is designed so that when it encounters an error, it will automatically insert a semicolon in an attempt to fix that error. In this case, it would fix it just fine. the job script engine would continue executing your code as if nothing had happened. Don't rely on this though. This can get you into problems. For example, this is a single line if statement. Let's say we didn't bother with these braces here. And now let's say there's an error somewhere in this code so that the job script engine Automatically inserted a semicolon. Well, if it inserted a semicolon right here, then this would be interpreted as an empty if block. So this statement below would actually not be part of the if statement, and would get called all the time, which probably isn't what you want to happen. Be careful about this. Make sure to add semicolons at the end of your statement.


Now, I don't know about you, but I think this manual bug hunting is a little bit tedious. Though, why don't we introduce you to some tools that will make our lives a little bit easier. All the major browsers have developer tools built into them that can help you with just the kind of problems that we are looking at, and then some. Now if you're watching this in Google Chrome, you can open the developer tools by moving over here, into Tools and clicking on Developer Tools. Now you can see that there's a handy little shortcut here. Depending on what platform you're on, that shortcut might be different. On Mac, it's Command Option I. And you can see that it opens up this console here. And if we were to load our file with bugs into it. Then you can see that it starts catching syntax errors. Now, it only goes so far, and then it just crashes. But you can see that it points us to the first syntax error here. And then we can fix them as necessary. If we kept going with this by fixing this, let's say and then reloaded the page, you would see that it would get to the next error. Which is right in this for loop. Now, you notice that it skipped right over this error here. Didn't even catch it because the way Javascript handles semicolons.

Easier Way

Alright, now that we've got some better tools, let's take a look at a bigger piece of code. Now this is the entire base game engine class for the game that we're going to be building. Now, what I'd like you to do, is debug this much larger piece of code. And to do this, you're going to need some help, otherwise, it's going to take far too long. Now, there are only a few syntax errors here. So, it's going to be a little bit hard to find them unless you use some tools, whether the Chrome developer tools or some other browser's tools.

Easier Way

Alright, so hopefully you used some tools to make that a little bit simpler for you. If we load up the developer tools here, we can see that we've already got a syntax error. And if we go over, and click right here on line 28, and it'll take us right to where the offending error is. You can see that it actually doesn't technically take us to the error. It takes us to the line after. sometimes these kinds of tools will get you close and Then you'll have to figure it out from there. So, the problem is right here. You see that local user ID calling negative 1 doesn't have a comma after it. It just ends. And since it was expecting a comma, we;; Javascript inserts a semicolon, and that causes issues. So let's go ahead and fix that one. Okay. So if we insert that comma there, and then reload the page. We get our next syntax error at line 103. And the error here is that functions expect parenthesis after them where the perameters are. Even if it doesn't take any perameters it still expects parenthesis here. Let's go ahead and add those in. And again reload the page. And we get to our next error. And this one is way down on line 207. Now this is maybe a little bit harder to see, but the problem is right here. This current tick should have a dot, as see down here, rather than a colon, since we use dots to access member methods and variables. Okay, so now that we've fixed this here. And then reload, we get to another error on 318. And here we can see on line 318 that we have a comma here, where normally we would use a colon to specify a member method. So, if we fix that and then reload the page, we can see that we don't have any syntax errors left. And, those are the only ones that we put in. So, you can see that it was a lot easier to go through the developer tools and fix these things as necessary. As it pointed it out to us, rather than trying to walk through the code line-by-line manually. So, I hope that shows how useful it is to have the proper tools on hand.


Now one important detail we'll need to understand is how to get our image data that our artists create into our game. For example, the image file name. Also the width and height of the image, whether it's been rotated at all and various other pieces of information we might need to know. Now to do this, we're going to use JSON, which is a very lightweight data interchange format that's based on JavaScript object syntax. Now, since it's based on JavaScript, it turns out that it's really easy to use with JavaScript. Much easier than, say XML. Now, here's an example of a JavaScript object, right here. Now, this is in JSON. Technically. It is the JavaScript object representation of JSON that has been passed in. The difference between a JavaScript object and JSON is that JSON is simply a string that we can then parse to create a java script object. And that's what we're going to do.

Inspecting JSON

Now, you see we have a parseJSON function that takes a string of JSON in, and then we're going to parse it using the JSON.parse method that is included in and accessible in just about any modern browser. JSON.parse takes this string. Weapon.JSON and will return a JavaScript object representing the JSON that it's parsed. Now, once we've done that what I want you to do is grab a specific piece of data, from that JSON. Let's say you want to grab data from the JavaScript object returned from JSON.parse and let's say you put that JavaScript object into the variable parsed. Now in order to grab the chaingun sub object then you'd simply say parsed frames chaingun.png like so and then put it in the variable chaingun lets say. Now lets take a look up above at this structure, what that would do it'd walk down on first on frames and then in the chaingun and what would be stored in the chaingun variable. Would then be this entire structure, so everything inside of chaingun.png. Now what I would like you to do, is grab the x data field inside spriteSourceSize of chaingun<u>impact.png.</u> And go ahead and print that out to the console. chaingun<u>impact.png isn't up in</u> our example JSON, but the JSON that we'll be running through this function does have it.

Inspecting JSON

Alright. So, this actually isn't too much code. So first, what we do is run weaponJSON through JSON.parse and then store the return JavaScript object into parsedJSON. From there, we print out to the console parsedJSON frames chaingun<u>impact.png spriteSourceSize finally, the x data field.</u>


Alright. So now we know how to parseJSON data. How do we actually retrieve that from our server? This is where XMLHttPRequest come in. An XMLHttpRequest allows our Javascript code running in a browser to fire a request off to our server to a specific URL. We can also specify a function call once the server responds to our request. Now, there are a few steps to this. First, we need to create a new XMLHttpRequest object, and we do this using the new keyword, followed by XMLHttpRequest with the parentheses. Now, note that case is sensitive here. Next, we need to call the XMLHttpRequest open method. First, we need to specify the HTTP method to use. In our cases, we're pretty much always going to want to use GET. Second, we specify the URL to call out to. For example, if we were requesting a JSON file, we would specify the file name that we were interested in. Finally, we specify a Boolean value that is set to true if we want the call to be asynchronous. We pretty much always want the call to be asynchronous. Next, we specify the onload parameter, which is a function that we define that gets called once the server responds to our request. Finally, we need to call the xhr.send method. This will actually kick-off the request. Note that we need to do all of these things first, before we can call send. Otherwise, the request might hit the server and respond before we can specify our onload function. And if that happens, we won't actually know what to do with the response yet.

Making a Request

Alright, now let's try creating our own XML HGP request. What we'd like to do is request weapon dot JSON which is the previous JSON code that we parsed. Then, once the response kicks in, we'd like the onLoad function specified to parse it like we did before, If you're a little confused, more detailed instructions are provided in the comment,

Making a Request

Alright, so not too much code. First we call a new XMLHttpRequest, then we specify the open method with the primaries GET, weapon.json, and true since we want the call to be asynchronous. And then we set the onload function to be our parsing code from before. And finally we kick of the request with xhr.sent. Now if we open this In chrome's developer tools, we can see that we actually do make this request for weapon dot JSON. Method get, and it's successful status, and it takes about thirteen milliseconds. And if we look at the console, we can see that we do actually print out the value of the X parameter that we were looking for before.

Loading Sound

Now, this is great for j sound but what if we want to grab something else, say, a sound file. To do that, we need to set the response type of the XMLHttp request object to arraybuffer and what that will do is specify that it is binary information rather than text that we can then decode as necessary. What we like you to do is create another XMLHttp request but this time we're going to request. Bg<u>menu.ogg, a sound file and set the response type to arraybuffer.</u> Now, we've already created the on load function for you to use. Don't worry if you don't understand any of this. We'll be going over this in more detail later in the sound unit. For right now, your job is just to fire off the XMLHttp request.

Loading Sound

Just a few lines of code. Create a new XMLHttpRequest object like before. We call request.open again, pretty much the same except that we've changed weapon.jsan to bgmenu.ogg, and we set request.responseType to be arraybuffer. And if we fire this up in our browser, we see that we do make that request, and it starts playing our sound file.

Abstracting XMLHttpRequests

Alright. So, we've written this XMLHttp request code a few times now. Let's go ahead and extract to that. What I'd like you to do is fill out the function xhrGet that does, well, exactly what we've done the past couple of times with xhrs. Takes in the reqUri, like weapon.json, or bg<u>menu.ogg.</u> It takes in a callback function to set the on load function to and it takes in a type, which could be either nothing, if we're expecting text error or arraybuffer, if we are expecting arraybuffer data. Now, one quick note about the callbacks, we're going to create the callbacks such that we assume that it takes the request object as a parameter. So, for example, you can see our parseJSON function here takes the xhr, and then parses xhr.responseText. Now, we have both the parseJSON and playSound functions here, that if passed in as callbacks, will appropriately play sound or parseJSON as we've done before. Now, down at the bottom of this file, we make 2 calls to xhrGet with weapon.json and bg<u>menu.ogg.</u> Just for you to test against to make sure that your xhrGet function is behaving properly.

Abstracting XMLHttpRequests

Alright, so the skeleton of this code is pretty much what you've already done before, but we're going to introduce a few other things here. First of all, we set this caller variable to be the caller of xhrGett. Now, this is a special thing in Javascript and what it does is, whoever ends up calling xhrGet, will be set as this xhrGet.caller parameter. And you can grab that as necessary. Next, we do the same thing that we've done this entire time, create a new XML http request and call the open method. Then we check the type. If it exists, then we set it, otherwise, we assume by default that it is just text, now the onload function is where things get interesting if we set a callback then we go ahead and try and call it otherwise we don't do anything and this try catch plug is something that some of you might be familiar with we try to do what is an this callback here and if it fails then we catch the error and throw an exception. Now this is basically just going to print out a whole bunch of information about the exception. And this is where caller comes in as well. You can see that we print out the exception. The response text and the caller just for debugging purposes. Finally, we call xhr.send, and that's it. And if we load this up in our browser, we can see we make both calls. The first one takes a lot less time than the second one. Since it's only JSON. We can see our output JSON in the console. [MUSIC] And our song starts.


So now we've gone through the basics of javascript syntax. Structuring and interacting with JSON data, and requesting data from a server. Now, we need to talk about how to interface to the browser. More specifically, we need to talk about the DOM, or document object model. The DOM is an interface to the structure of an HTML. document. For example, the head or body element. The DOM allows us to access and modify our hml document dynamically, using Javascript. Our game is primarily going to exist within a single element, the canvas, which we'll get into later. But what this means is that we won't have a lot of reason to heavily access the. The DOM. In fact we're only going to need a few things. So let's take a look at a quick example. Let's say you want to validate whether a user has entered a valid password into an input field. Here's how you would do that using the DOM API in Javascript. You can see the basic HTML here with the form. And the password input and the submit button, and we have a script down here where we start executing our javascript. First, we have this document.getElementById method. What this does is grab a dom element of the given id. In this case, it's exampleForm. Form, which is right here, so we would grab this entire form. When it's submitted, we run this function in here. Now, you don't really need to worry about the password rejects too much. We're interested in this part down here. Now if the password doesn't match, then we create a new tag element, assuming it doesn't already exist. We check if it exists by again using the document.getElementById method and checking for the ID notify. If it doesn't exist we use the document,createElement method specified at p tag. This parameter is just the name of a type of element. For example p or form or canvas. Now we set the text content. Of that p tag to this bit here. And we set the ID attribute to notify. That way, if we submit multiple times, we don't simply create a new p tag every single time. Finally, we grab a reference to the body tag. Since the body element has an ID of. Body we can do that, and we append, notify, to the body. Now if we look at this in our browser, we can see we have an input form with a submit button and you can see our basic HTML down here. However, if we submit an incorrect password, press submit, we can see that this pops up right here, which is the text that we set our tag to. You can also see that this tag was created down here. With an idea of notify and the correct text. You'll also see that if we keep pressing Submit again, more p tags don't get created, since we made that check.

    <body id="body">
        <form action="javascript:void(0);" id="exampleForm">
            <input type="password" id="examplePass" />
            <input type="submit" />

document.getElementById("exampleForm").onsubmit = function() {
    // Regular expression matching strings between 6 and 8
    // characters long and consisting of uppercase characters,
    // lowercase characters, and digits.
    var passwordRegex = /^[A-Za-z/d]{6,8}$/; // any upper/lowercase characters and digits,
    // only create user notification if password doesn't match.
    if(!passwordRegex.test(document.getElementbyId9"examplePass").value)) {
        console.log("Regex didn't match");
        var notify = document.getElementById("notify");
        if (notify === null) {
            notify = document.createElement("p");
            notify.textContent = "Passwords need to be between 6 and 8 characters long and consist of uppercase characters, lowercase characters, and digits only."
            notify.id = "notify";

            var body = document.getElementById("body");


Interfacing to the DOM

Alright, now that we've seen this in action, let's go ahead and use it ourselves. What I'd like you to do is create a new canvas DOM object inside a new div DOM object, that is then put inside the body element. To do this, we're going to have to grab the body element by its id of body. We're going to have to create a new element, using document.createElement, both for the div and for the canvas. Then, we'd like to set their ids. For the div, we'll set it to gameContent. And for the canvas, we'll set it to gameCanvas. Finally, we'll have to append both of those. The canvas to the div, and then the div to the body. You'll have to use document.getElementById, document.createElement, the appendChild method of DOM objects, and the id property to do all of this.

Interfacing to the DOM

So, the first thing we do, is grab the body dom object using document.getElementById with an id of body, and we create a div object, as well as a canvas object, and set their id's appropriately to div.id = "gameContent" and canvas.id = gameCanvas"" and finally, we append the div object to the body and the canvas object to the div. If we open this up into our browser, we can see that we have indeed created a div element and inside that is our new canvas element and both.

Javascript and Inheritance

Now, Javascript at first glance really doesn't resemble the same sort of object oriented programming languages that you see in C and C++ code. Now these are typically the languages that games are written in, NES, Super NES, XBox 360, PS3, all had some resemblance of this. Now Javascript provides a way that you can define a set of variables as well as functions encapsulated as an object called a prototype. But for game dev, we're really missing the inheritance factor, that is the ability to define that prototype and have another one inherent from it. Luckily, we can duct tape JavaScript just enough to make it look like we're getting classes and structure definitions. Now this type of setup is actually the backbone of how everything works inside of grids. So, before we move on, make sure that you're very, very familiar


All right. Now that Colt's explained why we want to use a more traditional object-oriented class base set up, let's go ahead and do that. Now, we'll be using a piece of code by John Resig that fakes class-based object oriented programming. Feel free to take a look at the code or the linked blog below to see how it works. Now, we're not terribly interested in the internals for our purposes. What we care about is how to use it for instantiating the proper class-based inheritance trees for our game objects. So, let's say we want to create the following inheritance tree. We want weapon and entity to both inherit from Class. And we want MachineGun and ChainGun to inherit from Weapon. And Teleporter and EnergyCanister to inherit from entity. Now we've started this off for you, but we're going to have you complete this yourself. First, we set weapon to be Class.extend. What this means is that weapon extends all of classes functionality, whatever that happens to be, and then adds it's own on top of it. Similarly, MachineGun is set to weapon.extend, which extends all of weapon's functionality, and then builds on top of that. Now, we've created these for you for a template. And, what I'd like you to do is fill in the rest of the inheritance tree we discussed above.


Alright. So really, all you have to do is set ChainGun equal to Weapon.extend and in this case, we're not extending it with any further functionality. We'll be getting to that later. And similarly, we're defining Entity to extend Class, Teleporter to extend Entity, and EnergyCanister to extend Entity. This bit of code doesn't really do anything by itself but we'll be adding more functionality to these, as we go. And this way, we have a nice clean framework for doing that.


Great job. Now that we've got the fundamentals down, we're going to build on that in the later units to create fun interactive games.