Making Games in JavaScript

2,303 views

Published on

An introduction to making browser based games in JavaScript and HTML5.

This workshop was presented at an open day for the Academy of Interactive Entertainment in Sydney, Australia on November 17, 2012.

Published in: Technology
3 Comments
0 Likes
Statistics
Notes
  • Be the first to like this

No Downloads
Views
Total views
2,303
On SlideShare
0
From Embeds
0
Number of Embeds
193
Actions
Shares
0
Downloads
31
Comments
3
Likes
0
Embeds 0
No embeds

No notes for slide
  • Final source code for the game is on the last slide
  • Aimed at those thinking about becoming programmersNo programming experienced assumed, do not need to know or have had any exposure to programming, butI’m going to talk about technology and it is going to be a technical talk. I will be covering a bit of programming
  • Rather than talk extensively about coding, or getting tied down in the specific syntax of the JavaScript language, I will present a high level overview of how to set up a game in JavaScript. I'll show you how you can get images drawing to the screen. How to interact with the user, and how to structure your game loop. I've also made a very basic game you can take home and look over, and start hacking to make your own game. Some of these topics I’ll just touch on, and others I delve a bit more deeply into and show you how to perform those tasks in code. But I hope all the advice I give you today is practical and something you can take away and begin to get your hands dirty with Talk for 30 minutesTake questions at the end
  • Scripting language – lets you integrate animation, interactivity, and dynamic visual effects into HTML pagesScripting languages not compiled into stand-alone programsAllows for fun, dynamic, and interactive interfaces in web pages. Immediacy - Let’s you respond instantly to clicking, moving the mouse, filling out a formRuns in the browserAdvantage over server-side scripts, no delays when communicating between server and clientExamples – Google MapsJS programs can be really simple (pop up new browser / forms), or full blown web applications or games  JavaScript is a programming language – or more specifically, a scripting language – that lets you integrate animation, interactivity, and dynamic visual effects into your HTML pages. Scripting languages differ from traditional programming languages in that they are not compiled and turned into a standalone program. Instead, scripts are read by other programs (in this case the web browser), and the commands contained in them are interpreted and executed by the program. JavaScript allows you create fun, dynamic, and interactive interfaces to integrate into your web pages. In fact, one of JavaScript’s main selling points is its immediacy. It lets your web pages respond instantly to actions like clicking a link, filling out a form, or moving the mouse around the screen. JavaScript runs in the browser. This offers a significant advantage over server-side scripting languages like PHP, which suffer from frustrating delays when communicating between the web browser and the web server. Because JavaScript doesn’t rely on constantly reloading web pages in order for the browser to communicate with the web server, it lets you create web pages that feel and act more like desktop programs than web pages. If you’ve ever visited Google Maps, you’ve seen JavaScript in action.  The programs you create with JavaScript range from the really simple (like popping up a new browser window with a web page in it), to full-blown web applications like Google Docs, or games like the one we’ll be building in this workshop.
  • Want as many people to see your game as possible, with minimum development timeCapitalize on a large audience, across a number of devicesWeb based games allow us to do thisAvoid writing native code, get a cross-platform code baseA few more reasons to consider… Making games is hardAs an independent game developer, you want as many people to be able to play your games with as little time spent on porting between different platforms as possible.The less time you have to spend get your game to work on different hardware, then the more time you can spend on developing the actual game. We can deliver games over the web in order to capitalize on the largest possible audience with a minimal amount of work need on our side in order to deliver that game to all the various hardware and software configurations available on the user’s end. So if we’re targeting the largest possible audience for our game, we want a web based or browser based game that will work on all platforms, including tablets and iOS – which takes flash out of the equation. So HTML 5 is really the technology that is going to afford you that flexibility That will let you avoid writing native code. You’ll get a cross-platform code-base that will run across devices, and it will also let you avoid app stores But before I get into showing you some code, I want to give you a few more reasons why you should consider game development in HTML5. And the chief among those is fast iteration.
  • Fast iteration key to making good gamesCompiling / recompiling can take a long timeBuilding takes time, getting it onto the hardware can take longerThen run and hit your breakpointsCode-compile-run cycle – longer cycle means less time developingJavascript isn’t compiledGame programmers love scripting languagesIn the browser, just reload  A fast iteration is the key to making good games. Compiling a game can take a long time.  At Gameloft, especially as we were nearing the end of the development cycle and we were testing and polishing the game, if the testers came back to me and told me I had a bug, I would have to fix the code then recompile the program, execute the game, set a breakpoint and then stat debugging or playing the game to see if my fix worked.  The process of recompiling could take up to 5 minutes, depending on whether or not I needed a clean build, and what platform I was targeting. It is not uncommon for this process to take up to 15 minutes for some game companies, depending on the game, the development environment, and their deployment target. Then, if I wanted to test it on an actual device, I would have to wait for our submissions team to validate it and upload it to the carrier’s server, and then I would be able to test it on the device. And if we were releasing a lot of games that day, I might be waiting up to half a day for an upload. iPhone programming is a little better, but you can still be waiting a while for the compilation to complete. Then we need to play the game and wait for our breakpoint to be hit and then start debugging This comes down to what is known as the code-compile-run cycle. And the longer it takes you to do that, the less time you have in a day to actually play and test your game and identify any problems, code it, and make it better. If it is taking you 15 minutes from code fix to play, then that’s 4 times an hour you can play your game. 16 times before lunch, 16 times after. You can play your game 32 times a day. You just can’t get any work done in that kind of environment. JavaScript is a scripting language, meaning that the code we write isn’t compiled until its read and executed by the browser. In fact, game developers use scripting languages a lot for game development for this very reason. If we embed a scripting engine in our game, then we just have to push a button to reload our scripts while our game is still executing to see if our code worked. When you are making games in a web browser, all we need to do is reload the web page and we get reloads instantly, so we’ve got that fast iteration cycle.
  • Updating can be done in two ways – content released as DLC, or title updateMaking your DLC as a script can bypass the release cycle processiPhone apps are not allowed to use scriptsHTML5 games can bypass this – hosted on your server, viewed directly by client, cuts out middlemanNo one lagging behind, everyone has latest version  In console industry 2 types of updates when releasing content for your game after it has shipped:content pack released as DLCtitle update, where your actually modifying the source code of the game. This requires going through a full QA cycle, getting your program revalidated (eg, iPhone store). It can cost lots of money (eg PS) and take a lot of time. If you can make your DLC as a script instead of actual source code, you can bypass that whole process. A couple years ago there was a lot of press about the App Store rejecting programs that implemented scripts, and there was a lot of debate about exactly what that means, what you could do with scripts and what you couldn't. When you make a game in HTML5, you bypass all of this. The game is hosted on your server, and it’s viewed directly in the browser running on the players device. There's no one in the middle. You are in complete control of what content your delivering, and how your delivering it. Also because you are delivering your content directly to the player, you can be guaranteed that there is no-one lagging behind. There is no need to release updates because everyone is always running the same version. You eliminate the need for anyone to explicitly go and download the latest update.
  • Here's a screenshot of the sample JavaScript game I've made for this presentation. It’s a 2D top down game. This is actually a port of one of the assignments for this year's first year programming class. It's a very simple Crimson Land clone, and I've just implemented some very basic commands as a jumping off point for you to start experimenting with JavaScript.  It’s a JavaScript game running of the canvas object, so it will work in really anything with a modern web browser.
  • Dictated by the browserTop down or isometric will work better – smaller sprites2D will work better In choosing your game make sure it will work in the HTML5 environmentTouch interactions, keyboard / mouse
  • Annotate text to tell the browser how to render itTo run scripts, we use the scripts tagThe HTML rendering engine runs as far as the script, then starts the JS VM, compiles and executes the code applying any side effects, then continues processing HTML is a language where you annotate text with little annotations that tell it how to render in the browser. HTML is a text language To make text bold we annotate the text with ‘b’ tags<b>Bold<b/> Likewise, to make text italics we use the ‘I’ tag.<i>italics</i> And to run javascripts within our page we use the ‘script’ tag.<script> When you embed scripts within your HTML page, the html rendering engine will download as far as the script tag, it’ll stop, then it’ll start a JS virtual machine, it will compile the code, it will execute the code, it will apply any side effects to the web page itself, and then it will continue processing the rest of the page.
  • C++ has a main function, the program is linear and starts at mainThere is no main function in JavaScriptCode comparison c++ / JavaScript C++ function on the leftint main(){printf(“hello world”);}The HTML file and script are on the right (HTML on top, script file on bottom)<script src=”main.js” type=”text/javascript”></script> alert(“Hello World”);
  • Defines a standard way for accessing and manipulating HTML documentsThe DOM presents an HTML document as a tree-structure
  • The document has children, the head and the bodyThe DOM is the link between the JS code and the HTML page itself. This is how the web page is exposed to JavaScript.  So from the JavaScript code we’re going to be editing the DOM. The DOM is the link between the JS code and the HTML page itself.
  • Web browsers were designed to render textGame programming requires some sneaky subversionCreate a canvas in the page, grab the DOM elementGet the 2D contextCall the interval function (setTimeout or setInterval) The web browser was designed to render text, and when we use it to run a game we’re subverting what the browser was designed to do. So there are a few hurdles we need to overcome in order to render a game.
  • The easiest way to render to the screen is by using the canvas element This was invented by apple in around 2004 for the widges on the dash in OSX It’s a resolution independent bitmap that gives you a 2d context, and exposes a 2d drawing API Its intended use is for graphs and for games
  • In the script, grab the canvas from the DOM element. From the canvas element you can get the 2d context, which is what we use to draw to the screen.From the context we can grab the width/height to use when drawing a frame (clearing the screen, for example).
  • What window.setInterval does is it calls our function at a set interval of about once every .033 seconds.
  • Here we have a very simple program that will draw a bouncing ball. I have a few variables to control things like gravity, and then I’m calling the function that controls updating and drawing at a set interval using the window.setInterval function  This will call my function repeatedly, updating my ball and drawing it at the new position on the screen. And it does this at intervals of around 33 milliseconds.
  • The sample program here is pretty impressive when you consider the amount of code you need to write to get something working in JavaScript as opposed to C++, or a similar language But we’re jumping ahead with a lot of things here.
  • Let’s get into it and start making our game. I’ll be making a top down shooter, and I have a small texture that I want to use as the grass that covers the ground of my game. So how do I render that to the screen? Start off by grabbing the 2D context like in the previous example var canvas = document.getElementById("gameCanvas");var context = canvas.getContext("2d"); Now to load the grass image I create a new DOM image element, and specify the filename of the image I want to load in the source parameter. I use the image onloadcallback function to get the framework to call my drawFrame function once the image has finished loading var image = document.createElement("img");image.src = "grass.png"; image.onload = function(){drawFrame(context);};   Code to actually draw an image function drawFrame(c){ // clear the background with blackc.fillStyle = "#000"; c.fillRect(0, 0, canvas.width, canvas.height);c.drawImage(image, 100, 100);}
  • Screen shot of the code above. Note that the frame is only drawn once the image has been loaded.
  • We’re using a 2D array to store a grid of tiles. Imagine an array as a bucket. A simple one dimensional array would hold a collection of objects – in this case tile images. You can think of a 2D array as a bucket of buckets, with each bucket holding a collection of objects.Create the array to store the background tiles var background = new Array(15); for(var y=0;y<15;y++){ background[y] = new Array(20); for(var x=0; x<20; x++) background[y][x] = image;} Modify the drawFrame function to draw the tiles in the array function drawFrame(c){ // clear the background with blackc.fillStyle = "#000"; c.fillRect(0, 0, canvas.width, canvas.height); for(var y=0; y<15; y++) { for(var x=0; x<20; x++) {c.drawImage(background[y][x], x<<5, y<<5); } } setTimeout("drawFrame(context)", 0);}
  • setInterval, call a function repeatedlysetTimeout, call a function after a delayadd some code to track the frame ratecalculate the delta time We can call the setTimeout function to call the drawFrame function repeatedly after a delay. In this case we want to run the game as fast as the browser will let us, so I’m passing in a value of 0 milliseconds. This means that the browser will try to call the drawFrame function again as soon as it possibly can. Alternatively you can use the setInterval function to call the same function repeatedly after a set delay. Either method is fine. Because we’re continually updating the context and redrawing the frame, there’s no need to wait until the grass image loads before we start drawing. We can just go ahead and draw straight away, and when that image is ready it will be drawn.  
  • Since we are no longer making that initial call to the drawFrame function when the image loads, we need to call drawFrame at the very end of the script.I’ve also added some variables to track the frame rate – the number of frames we are drawing per second. To do this I first calculate what is known as the delta time. Delta time is the time in milliseconds that it took the last frame to draw. We use it in games to control the speed of movement and animations so that our games appear to run at the same speed no matter how fast the computer runs. Here I calculate the delta time and use it to track the number of frames per second. I have a variable that tracks the accumulated time by added the delta time each frame. When this value reaches 1000 I record how many frames were drawn during that second. I can then draw this value as text to the context so I can see how fast the game is running.
  • vector and matrix classsprite classbuild the sprite frames – hCount, vCount, w, h, xOff, yOff, xPad, yPad, frameDurationmatrix transformationssprite updating using delta time There is a lot of code changes needed to get animation working. I won’t go deeply into setting up the sprite class that controls the updating and drawing of the animation, but the code shown here demonstrates how to add a new sprite to the game and get it drawing. The first thing we need to do is add the new script files to the html file. I’ve added 3 new scripts: matrix3x3, vector2, and sprite <script src="vector2.js"></script><script src="matrix3x3.js"></script><script src="sprite.js"></script><script src="main.js"></script> The matrix and vector scripts contain some mathematical operations and object definitions needed to get images drawn at the correct location on the screen. These are complex topics that can’t be covered in this presentation. But a deep understanding of the underlying maths isn’t going to be absolutely essential for us to get things working.
  • Create the sprite using the following initialisation code: game.sprites.player = new Sprite("player.png");game.sprites.player.buildFrames(8, 1, 32, 32, 0, 0, 0, 0, 0.05);game.sprites.player.setOffset(16, 16); The parameters for the build frame function are the horizontal and vertical frame count that we take from the image. Our image for the player sprite is arranged as 1 row of 8 frames.  Then comes the width and height of each frame. This is a simple sprite class so each frame has to be the same width and height. I’ve also included an x and y offset, in case your frames don’t start in the top-left hand corner, and x and y padding variables to specify the number of padding pixels around each frame.  Finally there is the frame duration, which is the number of seconds to display the frame for. This will be multiplied by the delta time so that the speed of the animation appears consistent.  A value of 1 for the frame duration means that 1 frame will be drawn every second. Here I’m saying draw a new frame every 50 milliseconds, which should give us a frame rate of 20 frames per second – which will look natural when we come to moving the player around the screen. When we come to drawing the sprite we have to set up what is known as a transformation matrix. This matrix will specify where on the screen the sprite will be drawn. A transformation matrix can also be used to control the scale, rotation, and skew of the sprite. The math behind it is not complex, but requires more time to go into than I have time today. After we draw the sprite I reset the transformation matrix by passing in the identity matrix to the context. The identity matrix is the matrix equivalent to 0.
  • To handle interactions like key press events, mouse movements, or touch screen press events, we use what are called callback function. How these work is that whenever one of these events happens, the window object on the DOM will intercept the event and call any of the functions that we’ve told the window to call.
  • To add a callback function for key down events, we use this code. I’ve make a keyboard object and told the window to call that object’s onKeyDown function whenever a key is pressed. All this is handled by the keyboard script, so all we have to do in our game is check to see whether or not a key has been pressed, and then handle that appropriately.
  • To add this keyboard handling to the game I’ve added three new scripts:keyboardplayerbullet The player script will wrap up all the functionality for the player inside one object. This script will handle what happens when the user presses the ‘w’ key – the player sprite will move forward. When we press the space, the player will fire a bullet.
  •  new zombie classmath functions for lookAt and randomsplit drawFrame into Update and Drawadded collision detection I’m skipping a lot of details with the implementation, but next I’ve add a zombie object and a few extra math functions to randomize their location. I create an array of zombies and for each frame I just run through that array and update and draw each zombie. You may have noticed that our drawFrame function was getting a little crowded. What we usually do in games is split out processing into updating and drawing. For each frame we first want to update everything that’s on the screen, and then go through and actually draw it. So I’ve split the drawFrame function in the main script into the update and draw functions. I’ve also added some collision detection, so we can detect when a bullet hits a zombie and, if it does, we kill the zombie and put some blood on the ground.
  • At the moment the zombies don’t actually move.  The last thing to do to finish off our game is to get the zombies moving towards the player.
  • The zombies have some very simple AI – probably the simplest AI you can give an entity in your game. All they do is look at there the player currently is and start walking towards him. This is the code to get that working. If you add this code inside the Update function in the Zombie script, then all the zombies will start walking towards the player.
  • If you have any questions, you can email me at samc@aie.edu.au
  • Making Games in JavaScript

    1. 1. Making Games in JavaScript Sam Cartwright Game Programming Instructor Academy of Interactive Entertainment, Sydney
    2. 2. Welcome
    3. 3. Who am I?
    4. 4. Who are you?
    5. 5. Topics• JavaScript• HTML• The DOM• Rendering• Main Loop• Animation• User Input
    6. 6. What is JavaScript?
    7. 7. Why HTML5?(making games is hard)
    8. 8. Fast Iteration
    9. 9. Scripts are data
    10. 10. What Type of Games?
    11. 11. HTML<b>bold<b/><i>italics</i> <script>
    12. 12. How do we run code? <script src=”main.js” type=”text/javascript”>int main() </script>{ printf(“hello world”);} alert("Hello World");
    13. 13. DOMDocument Object Model
    14. 14. HTML DOM Tree
    15. 15. Rendering
    16. 16. <canvas>
    17. 17. 2D Contextvar canvas = document.getElementById("gameCanvas");var context = canvas.getContext("2d");var width = canvas.width;var height = canvas.height;
    18. 18. window.setInterval(funciton, delay) window.setInterval(“drawFrame()”, 1000/30);
    19. 19. window.onload = function(){ context.beginPath(); var canvas = document.getElementById(game); context.arc(0.5 * width, ball * height, var context = canvas.getContext(2d); width * radius, 0, Math.PI*2); var width = canvas.width; context.closePath(); var height = canvas.height; context.fill(); var ball = 0.1; var radius = 0.1; context.fillRect(0, wall * height, width, var wall = 0.9; (1-wall) * height); var velocity = 0; }, 1000 * dt);} var dt = 1.0/30.0; var scale = 0.005; window.setInterval(function(){ canvas.width = canvas.width; var gravity = 9.8; velocity = velocity + gravity * dt * scale; ball = ball + velocity; if( (ball + radius) > wall ){ ball = wall - radius; velocity = -velocity; }
    20. 20. drawImagevar image = document.createElement("img");image.src = "grass.png";image.onload = function(){drawFrame(context);};function drawFrame(c){ // clear the background with black c.fillStyle = "#000"; c.fillRect(0, 0, canvas.width, canvas.height); c.drawImage(image, 100, 100);}
    21. 21. Tiled Backgroundvar background = new Array(15); function drawFrame(c){ c.fillStyle = "#000";for(var y=0;y<15;y++){ c.fillRect(0, 0, canvas.width, canvas.height); background[y] = new Array(20); for(var x=0; x<20; x++){ for(var y=0; y<15; y++) { background[y][x] = image; for(var x=0; x<20; x++) { } c.drawImage(background[y][x],} x*32, y*32); } } }
    22. 22. Game LoopsetTimeout("drawFrame(context)", 0);
    23. 23. var fps = 0; }var fpsCount = 0; }var fpsTime = 0;var dt = 0; // draw some debugging informationvar startFrameMillis = Date.now(); c.fillStyle = "#f00";var endFrameMillis = Date.now(); c.fillText("FPS: " + fps, 5, 20, 100);function drawFrame(c) // update the frame counter{ fpsTime += dt; endFrameMillis = startFrameMillis; fpsCount++; startFrameMillis = Date.now(); if(fpsTime >= 1000) { dt = startFrameMillis - endFrameMillis; fpsTime = 0; fps = fpsCount; var delta = dt * 0.001; fpsCount = 0; } if(delta > 1) delta = 1; setTimeout("drawFrame(context)", 0); // clear the background with black } // end of drawFrame function c.fillStyle = "#000"; c.fillRect(0, 0, canvas.width, canvas.height); // call the drawFrame function to start the game loop. for(var y=0; y<15; y++) // call frame will repeatedly call itself { drawFrame(context); for(var x=0; x<20; x++) { c.drawImage(background[y][x], x<<5, y<<5);
    24. 24. Animation
    25. 25. <script src="vector2.js"></script><script src="matrix3x3.js"></script> player.update(dt);<script src="sprite.js"></script> var trans = new Matrix3x3(); trans.setupTranslation(100, 100); trans.applyToContext(c);player = new Sprite("player.png"); player.draw(c);player.buildFrames( 8, 1, 32, 32, 0, 0, 0, 0, 0.05); identityMatrix.applyToContext(c);player.setOffset(16, 16);
    26. 26. Keyboard Input
    27. 27. Key Press Eventswindow.addEventListener(keydown, function(evt) { self.onKeyDown(evt); }, false);
    28. 28. game.textures.bullet = loadImage("bullet.png"); drawFrame(c) { …game.sprites.player = new Sprite("player.png"); game.player.update(dt);game.sprites.player.buildFrames(8, 1, 32, 32, 0, 0, 0, if(game.player.fired === true) {0, 0.05); game.player.fire();game.sprites.player.setOffset(16, 16); }… for(var bulletIdx=0; bulletIdx<game.bullets.length; bulletIdx++) { // create the player object if(game.bullets[bulletIdx].alive == true) {game.player = new Player(game.sprites.player, game.bullets[bulletIdx].update(dt); game.canvas.width/2, game.canvas.height/2); } } // set up the mouse and keyboard event handlergame.keyboard = new Keyboard(); game.player.draw(c); for(var i=0; i<game.bullets.length; i++) {var BULLET_COUNT = 6; if(game.bullets[i].alive == true) { game.bullets[i].draw(c);game.bullets = new Array(); }for(var bulletIdx=0; bulletIdx<BULLET_COUNT; } bulletIdx++) { … game.bullets[bulletIdx] = new } Bullet(game.textures.bullet);}
    29. 29. zombies
    30. 30. Zombie.prototype.update// seek to playerthis.velocity.x = game.player.position.x - this.position.x;this.velocity.y = game.player.position.y - this.position.y;// look at playerthis.rotation = lookAt(this.velocity.x, this.velocity.y);// scale down the velocitythis.velocity.normalize();this.velocity.multiplyScalar(dt*30);this.position.add(this.velocity);
    31. 31. QUESTIONS?

    ×