Monday, August 2, 2010

Barebones.html/.js

Hey everyone! Things have been a bit too busy for me to keep up on this day after day, but work on the next article is absolutely being done! The breakout clone from my last article is about 50-60% done, and I ran into all sorts of dumb little issues that you'll want to read about. In the meantime, click here to access barebones.html, which is just an HTML and JavaScript file pair that you can use as a template to start your own project. All it does is randomize RGB color values on each draw step (very slowly), and fills the canvas with the resulting color. Do something MUCH cooler with it and let me know what you're up to! :-)

Thursday, July 29, 2010

Game in Progress: Planning a Breakout Clone

Alright, so it seems that I'm back where I started - creating a game in HTML5 and blogging about the journey. However instead of hopping into a relatively complex platformer, we're going to ease up and do something that's easier to follow: a Breakout clone. Breakout is that game you've played a million times in a zillion ways, where you use a paddle at the bottom of the screen to hit a ball toward blocks at the top of the screen. You may know it better as Arkanoid, which is Russian for "Breakout with better graphics and an unreasonable back-story". Regardless of what you call it, we're going to make the paddle block game. The scope of this article will be the planning stage, followed by some rudimentary blueprinting in code.

PLANNING!

A business teacher of mine used to have a favorite saying about planning, that "failure to plan is planning to fail". This couldn't be more true in the programming world. No matter how badly you want to just get down to business and start putting stuff all over the screen, PLAN AHEAD! I don't know how many projects I've started prematurely, only to lose interest a quarter of the way through when I realize I have to completely redo a large portion of my work. Now that I think of it, my teacher had another saying: "Proper planning prevents piss poor performance." He was really into planning for the same reason, because if you just up and start a business without some sort of plan you may as well just start throwing money in a fire instead. PLAN! Here are some questions you should run through before you hit a single key on the keyboard:

  • Does the platform I've chosen provide the tools/technologies I need to build this game to its full potential? If not, can I work within the limitations?
  • What are the objects in my game? What are their properties and behaviors? Do any of them interact with each other?
  • How can I prevent my game from being too easy or hard? Should I implement a difficulty system?
  • Is this game even fun? Who would play this game? Is anyone listening to me? Where am I?

Since Breakout is already an established game that we all know is very awesome, let's focus our planning on breaking the system down into the properties that each play object has.

Game properties
- Game state (intro screen, running, game over)
- Number of lives remaining
- Score
- Playfield
- Paddle, ball, and array of blocks

Playfield properties
- Bounds (size)
- Shape and color, or sprite graphic

Paddle properties
- X/Y coordinates (x is variable, y is fixed)
- Shape and color, or sprite graphic
- Movement speed

Ball properties
- X/Y coordinates (free-moving within playfield)
- Shape and color, or sprite graphic
- Movement speed

From this little breakdown, I ended up with this code. An exercise like this as a first step is great, because I wasn't thinking about variables for ball/paddle speed, or the high-level game variables until I started jotting things down. To add to these skeleton classes, I focus on each of the objects and ask what they need to do as part of the game.

  • Game: increase score, take away/add lives, change levels, manage game state.
  • Playfield: be the boundary for ball/paddle, not sure what else yet.
  • Paddle: move left/right, check collision with ball.
  • Ball: move, check collision with paddle/blocks.

Click here to see the updated code where I have added some of the behaviors listed above as public methods of the game objects. You'll notice a Level class that I didn't mention above, which I only realized was necessary once I started breaking this stuff out. See? PLANNING! Some of the methods have placeholder arguments where they're easy enough to determine, like numOfPoints to add via Game.increaseScore(). Even though the majority of the code is comments explaining functionality, the idea is to create building blocks of code that eventually can be pieced together as the game is built.

I get it, PLANNING - Now let's make a game already!

Okay, FINE! It's obviously impossible to account for *every* issue you'll encounter while developing your game. However, the more you plan ahead the less hair you'll pull out when you need to reconsider the work you've done!

Next up: The next article should come quickly, as I'm eager to start putting all of this together and creating something playable. In the next article, we'll get our Game object rolling and start drawing on some canvas!

Tuesday, July 27, 2010

Anatomy of a Game

So with all of the small little quirks that were arising in my animation code, I'm going to do us all a favor and step back into the basics. This article is meant to provide you with an idea of what the framework of a game looks like, how it operates, and how to utilize these basics to get you started.

The Bare Minimum

To get us started, let's take a look at the HTML we'll use:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Games in HTML5 - 20100728: Anatomy of a Game</title>

<script language="javascript" src="game.js"></script>

</head>

<body onload="init();">

<canvas id="gameCanvas" width="300" height="300"></canvas>

</body>
</html>


I'm assuming that most of you have seen this framework HTML document before, we're only adding a few things to get us started. First off, I've added a reference to game.js, which will contain all of the JavaScript code that this simple example will need. Also, the canvas element is in place with the id gameCanvas and a width/height of 300x300 pixels. The body tag's onload event will trigger init(), which is the only function in the game.js file:

function init() {

alert('loaded');

}


This will simply throw a message box 'loaded' when the body of the document has finished loading. With that in place, we can start to dissect the inner workings of a typical game.

Loop Crazy

In the simplest of computer programs, the machine is given a list of instructions to perform one after the other. A equals 5, add 5 to A, print A on the screen. This system would make for an incredibly short game, as you're spit out as soon as the program is finished with the last step. A typical game will run in a loop, updating its state as input is processed from the player(s). Let's use E.T. for the Atari 2600 to determine how a game operates at its most basic level.

Step 1: Game is started, display title screen - wait for input to start.
Step 2: Game begins, receive input until an end state is reached:
- Player dies, show game over screen.
- Player somehow figures out how to beat E.T., show whatever screen that results in.
Step 3: Go to step 1.

In our example, init() is the equivalent to powering on the Atari. It is where we will begin the game loop itself, allows us to perform any setup for the game ahead of time. Here is a basic init() function that will get us into our step 2:

var FPS = 30;
var canvas;
var ctx;

function init() {
canvas = document.getElementById("gameCanvas");

if (canvas.getContext) {
ctx = canvas.getContext("2d");
setInterval(gameLoop, 1000/FPS);
}
}


We set FPS as a global frame speed reference (not actually frames per second), and assign the canvas from our HTML document to a JavaScript variable. The if statement assigns the canvas' 2D drawing context to ctx, which allows us to use it to draw to the canvas itself. setInterval() initiates looping of gameLoop, and tells the function to fire at a set rate.

Step 2 is the actual gameLoop() function that will run our game.

function gameLoop() {

var r = g = b = Math.floor(Math.random()*255);

ctx.fillStyle = 'rgb('+r+','+g+','+b+')';
ctx.fillRect(0,0,300,300);

}


This loop only does one thing per render, assigns a random value from 0-255 to r, g, and b, and applies their values to the fill color of the context object. It then fills the entire canvas with the color given, which will be grayscale since each value is the same. Click here to see it in action.

If this was an actual game, this is an example of what our code would actually look like:

function gameLoop() {
// gameStart = false at start...

showTitleScreen(); // Waits for user to start game, sets gameStart to true

if (gameStart) {
checkPlayerInput();
movePlayer();
moveEnemies();
checkForCollisions();
updateHealth();

if (player.health == 0)
playerDied(); // If player.lives > 0, restart - else game over screen
}
}


A very basic example, but it's the idea that counts: the game loop allows for fast updates of the game state, and determines when an end state has been reached (I win, or I die).

Hopefully this is helpful to some beginners, as it may seem confusing at least to anyone coming from a very procedural background. My next article will flesh out the basic game.js we have created, and start to turn it into an example game in HTML5. Any questions, feel free to leave them below!

Sunday, July 25, 2010

Game in Progress: Move the character

Alright, so it was a bit too ambitious to immediately start on level design after getting animation down. It's downright foolish to create the world around your character without being comfortable about how they will move around! This post will probably be easier to follow because I'll write it alongside changes to the code, instead of after the fact. Our goal for this session is to create a move function for the player character, and bind it to keyboard input that will initiate movement.

EDIT! When I had originally started this article my plan was to bind document.onkeydown to a function that would call Sprite.move(), which would change the character's x/y coordinates accordingly. That went horribly bad because onkeydown will sometimes fire repeated button presses based on the operating system's key repeat functionality! This revised article explains how I got around this by monitoring both onkeydown and onkeyup.

I can't sit still!

So Mega Man has a problem right now, specifically that as soon as you load him up he's on the run. In order to test out how the transition from still movement to running will appear, we'll add another sequence to his animation graphic that's only one frame of him standing still. Thanks to our Animation class, it's only a matter of expanding the graphic in Photoshop and adding two standing still frames (one facing left, the other right):

It's a good time to note that you should make sure each frame has a common foot height so the animation doesn't wiggle around

To keep things organized in the animation graphics, I'm keeping each animation on a separate layer in Photoshop named after the animationName. After uploading the graphic, I call addAnimation() two more times in the init() function for the megaMan object. A single frame technically isn't an animation so I should probably edit the Animation class to ignore the animation code for single-frame sequences. For now, I'll just add them and assume we're fine.

  1. megaMan.addAnimation("StandLeft", new Animation(megaManImage, 0, 60, 25, 30, 1, 5));
  2. megaMan.addAnimation("StandRight", new Animation(megaManImage, 0, 90, 25, 30, 1, 5));

I've also changed megaMan's startAnimation to "StandRight", so he can actually catch his breath before you start mashing the arrow keys. After loading the demo, Mega Man is straight chillin' cold.

Movin' on up...

Movement for our character should stay with the Sprite class, as it is a representation of the character on-screen. startMove() and stopMove() are added to the Sprite class, which enable/disable boolean variables for direction that have also been added.

  1. Sprite.prototype.startMove = function(direction) {
  2.   // Enable direction
  3.   switch (direction) {
  4.     case 'left':
  5.       this.left = true;
  6.       break;
  7.     case 'right':
  8.       this.right = true;
  9.       break;
  10.   }
  11. }
  12. Sprite.prototype.stopMove = function(direction) {
  13.   // Enable direction
  14.   switch (direction) {
  15.     case 'left':
  16.       this.left = false;
  17.       break;
  18.     case 'right':
  19.       this.right = false;
  20.       break;
  21.   }
  22. }

Our final step involves capturing keyboard input and attaching it to our character's behavior.

Keyboard Input

Capturing keyboard input is relatively simple for our purposes, because we're not going to worry about simultaneous keypresses for now. All we want to do is move the character left and right whenever those arrow keys are pressed. In order to do that, we bind a custom function to the document.onKeyDown event that the browser provides, and use that custom function to determine which keys are pressed:

  1. document.onkeyup = checkKeyUp
  2. document.onkeydown = checkKeyDown;
  3. // Custom functions to handle keyboard input
  4. function checkKeyDown(e)
  5. {
  6.   var currentKey = e.which;
  7.   switch (currentKey)
  8.   {
  9.     case 37: // Left arrow
  10.       megaMan.startMove("left");
  11.       megaMan.setAnimation("RunLeft");
  12.       break;
  13.     case 39: // Right arrow
  14.       megaMan.startMove("right");
  15.       megaMan.setAnimation("RunRight");
  16.       break;
  17.   }
  18. }
  19. function checkKeyUp(e)
  20. {
  21.   var currentKey = e.which;
  22.   switch (currentKey)
  23.   {
  24.     case 37: // Left arrow
  25.       megaMan.stopMove("left");
  26.       megaMan.setAnimation("StandLeft");
  27.       break;
  28.     case 39: // Right arrow
  29.       megaMan.stopMove("right");
  30.       megaMan.setAnimation("StandRight");
  31.       break;
  32.   }
  33. }

This code changes the animation to either running left or right depending on which key is being pressed, and changes it to standing left or right based on which key was released. At this point the demo functions properly, but there's one minor issue: multiple keypresses at the same time. If left arrow is held down while right arrow is pressed, this can result in a situation where megaMan.x is still being modified even though the key has been released. To fix this, I simply added code to the startMove switch clauses that stopped left or right movement if the opposite key is pressed. This is almost where we want to be, as there is some confusion if onkeyup fires before another onkeydown (resulting in some backwards sliding). However I'm tired and it will have to wait until part 2.

For now, the next post will most likely be about fixing movement, getting Mega Man in a test "room", and giving him some jumping skills (ooh physics!) Here are links to the code as it stands now:

Demo
Sprite/Animation classes

Excellent color cycling article!

Hey all, right now I'm currently in the process of writing my next post on movement in my HTML5 project, life gets busy sometimes though and will inadvertently throw me off course. I've got two issues to deal with at the moment:
  • Keypresses in OS: I hooked document.onkeydown and document.onkeyup to custom functions that modify the sprite's x/y coordinates on each draw cycle. Originally I was only using onkeydown and moving the character when that specific key is down. However, this method is inaccurate because different browsers interpret key-repeat functionality differently. In Firefox, holding down the right arrow key results in one move, followed by a pause and then a repeat of the key being pressed. Safari and Chrome don't seem to do this. Solution: I'm going to create flags on the sprites for up/down/left/right movement that are set on the first keypress, and unset when that key is released. The Sprite class will handle movement for these flags in the draw() function.
  • Double-buffering: In order to prevent flickering, the normal technique is to create two drawing fields, one active and one hidden. During each frame, you draw to the hidden field (a canvas in this case), and then flip the two when the hidden one is complete. I'm not sure if this can be gracefully done with HTML5 canvases, I really hope it can somehow. 

In the meantime, I just found this incredible article about color cycling with an HTML5 canvas, and it looks like the author has tackled a lot of the issues I will eventually run into with animation. I've got a business trip to take on Tuesday, and sitting in the airport should give me plenty of time to tackle the two above issues and write an article about the progress. Stay tuned!

Friday, July 23, 2010

A primer on class variables and methods in JavaScript

I figured this was a great topic for the beginning of this blog, because up until I was introduced to jQuery I had no idea that classes ever existed in JavaScript. Before I took up serious web development, my JS experience was limited to copying cheesy scripts from JavaScript Source into whatever awful personal website I'd be building at the time in high school. However, you can actually use functions (as jQuery does) to create classes in JavaScript that will make your code immediately more extensible and organized. The variables and methods within those classes can have various levels of access (public, private, static and privileged), and I'll go over public and private today using classes from my Sprites and Animations post as examples.

JavaScript Classes

This here is how you create a new class:

  1. // Class declaration
  2. function Sprite(x, y, w, h, startAnimation) {
  3.   // Do constructor stuff here, instantiate local variables, etc.
  4. }
  5. // Create a Sprite object
  6. var mySprite = new Sprite(200, 200, 16, 16, "DefaultAnimation");

Easy enough. However, how you declare variables and methods within your class will determine where you can access them. We'll start with public variables/methods, as they're the most open.

Public Variables/Methods

Public variables and methods are accessible by any class in your code. Let's add a public variable and draw() method for the Sprite class.

  1. function Sprite(x, y, w, h, startAnimation) {
  2.   // Do constructor stuff here, instantiate local variables, etc.
  3. }
  4. // Public variable
  5. Sprite.prototype.currentAnimation = null;
  6. // Public method
  7. Sprite.prototype.draw = function() {
  8.   // Do drawing related things here
  9. }
  10. // Create a Sprite object and use it
  11. var mySprite = new Sprite(200, 200, 16, 16, "DefaultAnimation");
  12. mySprite.currentAnimation = "MyAnimation";
  13. mySprite.draw();

You might be wondering what "prototype" is all about. Consider it to be the main copy of your class. Every object that you create from your class will contain the variables/methods you define under its prototype. Also, note that Sprite.prototype.draw is assigned in the same manner as a variable is, except that you're assigning a function to it. Since currentAnimation and draw() are public, you are able to access them directly from outside of your object. While this wide-open behavior ensures that you'll have access to them whenever the need arises, it's always advisable to only make member variables/functions as accessible as they need to be! That's where privacy comes in.

Private Variables/Methods

Private variables and methods are not visible outside of the class they belong to, and can only be accessed from the outside via the class' public methods. If we add a private variable to the Sprite class, it can't be accessed simply by mySprite.privateVar - rather, you would have to create a public function to retrieve its value as seen below.

  1. function Sprite(x, y, w, h, startAnimation) {
  2.   // Private variable
  3.   var currentAnimation = startAnimation;
  4.   // Private function (specify new active animation)
  5.   var setAnimation = function(animationName) {
  6.     this.currentAnimation = animationName;
  7.   }
  8. }
  9. // Public function to access private variable/method
  10. Sprite.prototype.publicSetAnimation = function(animationName) {
  11.   this.currentAnimation = animationName; // OK
  12.   // OR
  13.   this.setAnimation(animationName); // OK
  14. }
  15. // Create a Sprite object and use it
  16. var mySprite = new Sprite(200, 200, 16, 16, "DefaultAnimation");
  17. mySprite.currentAnimation = "MyAnimation"; // FAIL
  18. mySprite.setAnimation("MyAnimation"); // FAIL
  19. mySprite.publicSetAnimation("MyAnimation"); // OK

This example is a bit tricky, but bear with me. The Sprite class now has a private variable currentAnimation, and a private method called setAnimation that changes its value. Both are unavailable at the bottom of the code snippet where we create a Sprite object and attempt to access them directly. However, the public method publicSetAnimation is a "gateway" of sorts that can be used to change the variable through either method.

Summary

  • Public variables and methods are visible to all classes.
  • Private variables and methods are only visible to the class they belong to.

The decision to use public or private variables and methods will vary depending on the specific situation. As a rule of thumb, ask yourself "do I really need to be able to access this from outside directly?" If you find yourself answering yes, you should still consider keeping it variable private and providing a public method via which to set/retrieve its value. This strategy is also helpful in case you have to alter the method by which a variable is set/retrieved, as it's (hopefully) likely you'll only have to make the change once to your public method. Happy... classing I guess!

Next up: I will cover static and protected variables/methods in a future post, followed by something other than level creation. I'm starting to think it would be a good idea to get my character moving around a test "room", and possibly figuring out the physics situation before I delve into creating the levels themselves. Always be willing to reevaluate your plan! :-)

Thursday, July 22, 2010

Game in Progress: Sprites and Animation

This is the first post of hopefully many about my attempts at building games in HTML5. HTML5 is a breakaway from past revisions, in that it lends itself heavily to JavaScript programming, local information storage, and other paradigms that allow for many applications that were either impossible or prohibitively complex in the past. A perfect example of this is the canvas element, which is a panel that can be drawn on with JavaScript code. My goal throughout this process will be to create an interesting (or at least functional) game using the new technologies provided by HTML5.

I started out wondering what type of game I should focus on, as usually the best introduction to a new programming language is a simple puzzle game such as Tetris or the like. However my ambition always gets the best of me, so the hell with it - we're making a classic platformer.

First things first, all platform games consist of the following elements:
- Levels, containing:
-- Objects, that are:
--- Inanimate (blocks, obstacles)
--- Animate (player character, NPC helpers, enemies)
--- Power-up items
-- Goal (usually get to the end alive)

I began by tackling what was going to be the most tedious issue: displaying and animating the game objects.

Sprites

The Sprite class will represent anything on the page that has to move, with variables for size and location.

Sprite class
new Sprite(x, y, w, h, startAnimation);

Variables
- x, y: Coordinates relative to top-left of canvas
- w, h: Width and height
- startAnimation: Will get into this later, but I figured all animate objects will have a default animation to start with.

Methods
- addAnimation(animationName, newAnimation): Adds newAnimation (an Animation object) to the Sprite's animations array, with the name given (i.e. megaMan.animations["RunRight"]).
- setAnimation(animationName): Sets the Sprite's currentAnimation variable to the given animation name. If the sprite is visible on-screne, the draw loop will pick up this change and immediately change to the given animation.
- draw(): Calls draw() function of the current Animation, which keeps track of frames elapsed and renders the sequence.

Using Mega Man as an example (because he is awesome and someone had already ripped his animation frames at Game Sprites Archive, his sprite is initialized as follows before the setInterval call in the init() function:

megaMan = new Sprite(250, 400, 25, 29, "RunLeft");

This places the megaMan sprite at (250,400) at a height/width of (25,29). "RunLeft" is a string that specifies the name of the default animation that the sprite should begin with. Once the Animation class is in place, we will create an animation of running left frames, and assign it to him with the name "RunLeft".

Animations

The sprite and animation classes were tricky to work out, because it's hard to determine what behaviors/properties should stay with the Sprite class.


Animation class
new Animation(image, startX, startY, frameW, frameH, lastFrame, frameRate);

Variables
- image: Image() object whose 'src' property points to the graphic containing the animation frames. More on this file format later.
- startX, startY: Coordinates of the given image where the desired animation frames begin.
- frameW, frameH: Width and height of the animation frames (must all be same size for now).
- lastFrame: # of last frame in the animation sequence, zero-indexed.
- frameRate: # of global frames that should render before the next animation step.

Methods
- draw(): Draws a frame specified by how many frames have elapsed (frameCounter), which frame to draw (currentFrame), and how long it should stay for (frameRate).


The behavior of the animation is as follows: The global draw() function calls draw() for each Sprite object on the screen. In turn, the Sprite's draw() function will call draw() for its current Animation object. The Animation object will continue to draw the first frame of the sequence until its frameCounter exceeds its frameRate - at that point, currentFrame will increment and the next image in the sequence will be displayed. The demo at the end of this post consists of Mega Man's RunRight animation, which consists of 4 images that are displayed for 5 frames each before looping back to the first.

Animation Graphic Format

MM.png, which contains the animation rows for "RunRight" and "RunLeft" animations


Using the Mega Man example, the first animation I wanted was of him running to the right. My goals in creating the format of the animation graphic were two fold: it should be easy to edit, and all animations for any given character should fit in one image. I decided on a format where each animation sequence will sit on a "row" of the graphic, with each cell being one frame. It uses PNG for its built-in transparency. Here is the example MM graphic with "RunLeft" and "RunRight":



Putting it all together

With information on the start x/y coordinates of an animation, how wide the steps are, and how many frames, the animation will now be able to render by switching frames after each n number of times the draw() loop has run. This is accomplished by the Animation classes own draw() function, which is called each frame by the Sprite class. While that might sound confusing, it breaks down rather nicely:

1) Load the image that contains your animation sequences.
-- megaManImage = new Image();
-- megaManImage.src = "img/assets/MM.png"

2) Create a new sprite with the name of the animation you will create as startAnimation (i.e. "RunRight").
-- megaMan = new Sprite(250, 400, 25, 29, "RunRight");

3) Use the 'addAnimation()' function of the sprite to add a new animation to the Sprite's animations array.
-- megaMan.addAnimation("RunRight", new Animation(megaManImage, 0, 0, 25, 29, 3, 5));

4) Add megaMan's draw() call to the global draw() function. This will call the draw() function for whatever animation name is in megaMan's currentAnimation variable (set to startAnimation by default).
-- function draw() { megaMan.draw(ctx) }

(ctx is the canvas context that's set in init(), we're passing it because drawing is handled by the context object).


I know this explanation is somewhat convoluted because I'm darting around everywhere, but that's actually how the entire thing came together. If you'd like, you can feel free to use sprite.js which contains these Sprite and Animation classes, and also check out the demo where you can press the left and right arrow keys to change megaMan's currentAnimation. As I create various other aspects of the game, they will be available for use also - just be aware that some of the code is (very) likely to change. Any questions? Leave them in the comments section and I'll do my best to answer them!

Next up: Level design. Why just build a level format and hand-code them, when you can waste your time with a level editor? Great...