Creating A Game 101
Last updated: Mar 15, 2020
Programming is fun. Games are fun. Programming games should, in theory, be double the fun!
Well, I’m not here to tell you otherwise. I consider making games to be a fantastic way to practice code - as well as learn algorithms, physics, design and more. It’s immensely satisfying to be able to play something you created yourself from scratch, but this isn’t to say that making games is easy.
The first little game I made, only 20% of the time was spent actually making it. The other 80% was spent debugging, scrapping ideas, detangling code and general frustration. I had started off sloppy, following a trial and error paradigm, telling myself I would go back and ‘clean up’ my code later…which ended up biting me in the butt.
I did learn a lot from this little project, most importantly how planning ahead and writing less code is better than more and I changed my workflow. With this series, I hope to help you avoid making the same mistakes I did starting out.
KISS - Keep It Simple, Stupid.
It’s easy to get carried away dreaming up the next RPG adventure and even easier to become overwhelmed, frustrated and ultimately fail. Start small and go from there. Even something that appears simple at first can be a daunting task (think Tetris or Pacman). Rather than try and do it all at once, look at each little game as an opportunity to hone your skills and try something new.
Next is to think what kind of game you want to make. Something with simple mechanics and a clear win or lose condition. When starting out, dont try and reinvent the wheel - take a game that already exists and recreate it. Maybe a puzzle game, a side-scroller or a shooter.
Each have their own challenges, but are small enough to accomplish in a weekend (or two).
Eureka! An idea is born.
In my case, I wanted to create a small game using the canvas API where the player must pet as many dogs as he can. Dogs zoom across the screen and are only pettable for a short moment in time. Petting dogs increases a happiness meter. This meter decreases over time, so you must continously pet dogs to keep it above 0. If you let your meter run out, the game is over.
Wait, what’s canvas?
Created by Apple as an alternative to Flash, canvas is a simple little api that allows you to draw graphics in the browser using JavaScript. With it, you can draw lines, rectangles, circles, text and pictures. It works like a grid and you specify the position that these elements should be drawn on using X and Y coordinates.
All you need to get started is to create a <canvas> element in HTML and then use JavaScript to tell the canvas what you want to draw.
Ok, cool, but why ?
Because of it’s simplicity. It is stupid easy to setup and get started, with no compilation or updates required. Making games for the web also means your game can be played anywhere, anytime - as long as there is a browser.
This series assumes you are familiar with JavaScript and HTML, but I’ll do my best to explain what is happening as we go along.
If you’d like to read up more on canvas beforehand, you can check it out here.
Defining the MVP
This step is the secret to game development (and development in general). Take your idea and define what the minimal viable product is - in other words - the most basic form of your project. What is the bare bones of your game? If we strip away the graphics and are left with some basic rectangles, what would I need to make the game playable?
Anything can be scaled up and improved upon as long as you make sure to first structure your project around the MVP. Not only will you finish your game a lot quicker (which is a huge motivational boost!) the alternative is a slippery slope to the dreaded spaghetti code.
Simplicity is the key to brilliance ~ Bruce Lee
Good enough for me - let’s break down our game to it’s most basic form!
Here is the first draft. My game is basically made up of a few key components.
- The screen, which we’ll make with the canvas API.
- The player, who has a score and moves up and down on the screen.
- Dogs, who can be pet and move across the screen.
- A meter which starts at a certain width then decreases over time.
Does this seem too simple? Don’t be fooled - we can break each of these components into smaller problems easily enough!
| Screen | Player | Dogs | Meter |
|---|---|---|---|
| scrolling background | determines score | moves across screen | decreases over time |
| randomly places dogs on grid | collision detection | petting increases meter | determines gameover |
| displays current score | smooth movement | leaving screen unpetted causes penalty | has a maximum width |
| defines boundaries | animated sprites | different breed types and values |
Show me the code!
To get started on our project, we first need a little setup. Since we are using the canvas API to make our game, this will be very quick to do. Our project directory will be made up of two files: an HTML file and our JavaScript file.
<!DOCTYPE html>
<html lang="en">
<head>
<!--meta data here-->
<title>Puppy Power!</title>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="module" src="pupper.js"/>
</body>
</html>
Here in our HTML, we’ll create our <canvas> object and give it an ID - as well as link to our javascript file. I’ll explain the script type="module" bit later on.
const canvas = document.getElementById('canvas');
const c = canvas.getContext('2d');
canvas.width = 600;
canvas.height = 500;
In the JavaScript file, we grab the canvas object we created in the browser by the ID we gave it and ask it to create a 2dContext - which is what allows us to draw items on the grid such as rectangles and circles. It is possible to create a 3d context, but not all browsers support it - and it’s not necessary for our 2d game anyway. Then I set the size of the canvas to 600 by 500 pixels.
And there you have it - no installation or third-party programs required. If you open up your file in the browser, you’ll see its blank - this is because the canvas is blank by default.
Opening up the developer tools and inspecting the page, we can see the canvas element is there, with the specified width and height. Huzzah! Now that I’ve setup the canvas and our 2d context it’s time to write some code and get things started.
ProTip: The dev tools are your best friend. They should always be open when developing anything for the web.
The Screen.
For this game I decided to try something I’d never done before - a scrolling background. I picked a nice looking image I found on google to serve as my backdrop.
One of my goals in making this game was to create the artwork myself - but it’s important to start with the game logic, which can dictate how the visuals need to be represented, so I’ll use premade assets for now.
My game is going to have a lot of image files, so it’s good to create some folders in your project to keep everything neatly organized.
Time to add our image! The way I’m going to do that is by creating an HTMLImageElement and tell the canvas to draw it.
let img = new Image(); // creates a new HTMLImageElement.
img.src = 'images/street.gif'; // sets the image's file source.
c.drawImage(img, 0, 0);
The drawImage() method recieves the HTMLImageElement to draw and the x and y coordinate from where it should start drawing. Canvas works like a grid with an X axis and a Y axis, but the uppermost left corner value begins at zero.
So by telling canvas to draw our image starting at the 0 X and Y coordinate, it will start from the top left corner. Provided our image is large enough, this should cover the entire screen.
However, if we open up our file in the browser we see…
A big pile of nothing. What went wrong?
Well, the drawImage() function is working just fine (we can see with the dev tools that no errors have been logged to the console) but the problem is we haven’t given enough time for the image to be loaded before we tried to draw it to the canvas.
There are two ways we can go about this. We can tell JavaScript to only run a block of code once the Image object has been loaded by using onload() or we can continuously redraw the scene.
This is precisely what we’ll need to do to ‘animate’ our game objects - redraw our scenes over and over again in a loop - so we’ll go for option number two!
Game Loops and Animations
A game is nothing more than one big loop that runs until it’s over. It’s how we animate our objects, move them from one place to another and check to see if any win or lose conditions are met.
The illusion of movement and animation on the screen is nothing more than telling objects to redraw themselves in new positions very very quickly.
‘No problem’ you might think, ‘I’ll use a while(true) loop to run my game and break out of it when a win or lose condition is met!’
what happens to your browser when you do this
Basically, JavaScript in browsers is single threaded. Both JavaScript and the browser share this thread, which they use to get stuff done. A while(true) will create an infinite loop, which means JavaScript will run forever and never give back control of this thread to the browser - which causes it to freeze.
What we actually want is a timed-loop which runs really really fast, but stops a set number of milliseconds for the browser to take back control momentarily.
For this, we’re going to use requestAnimationFrame()
What this does is call your game loop recursively for about 60 frames per second, giving us nice and smooth animations - whilst also doing a lot of smart optimizations per browser and neat stuff like stopping animations in inactive tabs. If you want to read more about it here you go.
let img;
function init() {
img = new Image();
img.src = 'images/street.gif';
}
function render() {
requestAnimationFrame(draw);
c.drawImage(img, 0, 0);
}
init();
render();
Now, I’ve created two new functions. init(), which initializes the image object, then render(), which draws the image at 60 frames per second. Calling the init() function will run it just once, but calling the render() function sets the loop in motion.
It’s good practice to separate the initialization of our variables and objects from the loop. We really only want to initialize anything the one time. We will be initializing many objects and variables in this function by the time we reach the end of this tutorial - so it also serves as tidy encapsulation.
And there we are! Our background is all set. We’ve defined an MVP, separated each entity and broken them down into smaller problems and set up our project.
In the next tutorial we will see how to make a sidescrolling background as well as define and write the logic for our player character and place him on the screen.
Disqus comments are disabled.