One Simple Game
Interested in game programming? Not sure? Let's make one simple game and find out.
Press the Next button on the bottom right of the screen to begin.
Interested in game programming? Not sure? Let's make one simple game and find out.
Press the Next button on the bottom right of the screen to begin.
We are going to learn the absolute basics of making a video game.
When you are playing a game it repeatedly goes through a game loop, which involves handling updates to game values and drawing the current game screen.
First we need something to draw on. This is our game canvas.
Let's decide how big we want our game to be. Enter a width and height (in pixels). Let's make each at least 200 pixels so we can see.
Now do the same thing to draw a rectangle inside our canvas. Try entering a few numbers for the width and height here.
Okay, now that you've decided how wide and tall our rectangle is, let's toy with its position on the screen. A game object's x value is its position (in pixels) from the left side of the game canvas.
The y value is a little trickier. It describes the vertical position, but measures from the top of the game canvas rather than the bottom! Try some x and y values to see what I mean.
Great! You made a rectangle that we can draw and move.
But we want the game itself to do all that work of moving the rectangle around.
Let's store the the rectangle's position as variables, which can be different values. You can use the standard names of x and y (or left and top) or really, anything you want. Just avoid spaces or weird symbols (except an underscore _ if it makes it easier to read).
I'm going to make the rectangle a variable itself, called myRect.
Now we can change the position by changing these variables. (You can try changing them below if you want.)
myRect.
myRect.
Now, let's use the game's update() function to automatically move the rectangle. This function is used to handle any changes between game animation frames. Let's see how the "next frame" of the game changes things.
*Note: you can use a positive number to move one way, and a negative number to move the other way. Using zero means you won't move in either direction.
current frame
// The update() function might look something like this
function update()
{
myRect.x = myRect.x +
myRect.y = myRect.y +
}
next frame (preview)
Okay, let's back up a little. Once a game is started, the game loop basically looks like this:
update()
draw()
// Then repeat...
Well... that handles the animation. A real game will also need to deal with player input (from a controller, keyboard, etc.), which we will discuss later, and will look like this:
handle_input()
update()
draw()
// Then repeat...
Let's see our game loop in action. Enter how much you want the values to change on each update(). Then press Restart to see the resulting animation. (Hint: start with something small.)
// Be sure to also try NEGATIVE numbers!
function update()
{
myRect.x = myRect.x +
myRect.y = myRect.y +
}
Ok, but we don't always want to move the same way. Hm... let's use variables again! This will give us a new way to change the update() function.
Name a variable
describing how much we'll
move horizontally (along
the "x" axis):
... and a variable
describing how much we'll
move vertically (along
the "y" axis):
Now we can change these anywhere in our code, and our update() function will look like:
function update()
{
myRect.x = myRect.x + myRect.x_speed
myRect.y = myRect.y + myRect.y_speed
}
Let's see what that update function does now, when we set these variable values somewhere else in the code. Change the two new variables below to see how it affects movement in the game loop.
Press Restart to begin animating (or to reset your position).
// Now we can change these from anywhere, not just inside update()
Hooray! You have learned to use variables for animations. And since we can set movement now from anywhere, we can do it inside that handle_input() function I mentioned, letting the player control the movement.
I'll handle the code setup (below), you just decide what happens when the user presses up, down, left, or right.
// Positive and NEGATIVE numbers will determine movement
function handle_input( direction )
{
// Btw, the == checks if two things are equal
if( direction == "right" )
if( direction == "left" )
if( direction == "up" )
if( direction == "down" )
}
Looking good... let's put it together and see if it works. See what pressing (or swiping) up, down, left, and right do. You can alway go back with the Previous button if this doesn't look right.
You can use the Restart button if you get lost offscreen.
Nice! Almost done. Now we need a goal for our player (to make it a game).
To keep it simple, let's just have the player try to grab something. We'll call it a "trophy" and we can just use a gold rectangle for it.
As you did with the player, decide how big your trophy is.
(preview)
We use "collision detection" to determine when two game objects overlap, like checking if the player has reached the trophy.
I'll spare you the extra code involved. Let's just say we have a colliding_with_trophy() function that will always give us true or false.
We'll add this into our udpate() function, so we can check for collision within each game loop.
But what happens if colliding_with_trophy() gives us true
(so the rectangle and trophy are overlapping)?
Well, then the game is won. Let's
use a variable called
gameOver to represent that.
function update()
{
myRect.x = myRect.x + myRect.x_speed
myRect.y = myRect.y + myRect.y_speed
// The "if" here means: only look at the next line if colliding_with_trophy() gives us 'true'
if( colliding_with_trophy() == true )
gameOver = true
}
When the game is over, we want to let the player know they have won. One way to do this is change the draw() function.
Fill in the boxes below to decide what you'll say, and what x and y values the writing will start at.
function draw()
{
// Btw, other drawing code would be up here...
if( gameOver == true )
{
drawText(,
,
)
}
}
(preview)
Congratulations!
You've learned the main concepts of creating one simple game.
Admittedly simple, but that was the point. Hopefully this helped you determine if you would find game programming interesting. (If so, go online and look for more in-depth tutorials!)
Now, press Next to play your simple masterpiece. NOTE: you can always go back through these pages to change the basics of your game. Have fun!
Wow, you made it all the way here!
If you want to keep learning, click the button below to download the code for the game you just made.
It will be a file called mygame.html. You can double-click/open it in your browser to play it.
Open it in a text editor (like Notepad, TextEdit, or Notepad++) to edit the code.
Have fun learning!
// Start here
// Hello! We're going to keep this simple. You've already seen a lot of this.
// Btw, you can write single-line comments after two forward slashes. Comments don't affect the code at all.
// We will store our game canvas and its "drawing context" as variables
var canvas
var context
// You can make a variable "object" whose properties are variables
var myRect = {
x: 0,
y: 0,
width: 1,
height: 1,
x_speed: 0,
y_speed: 0
}
// Now you can access myRect's properties with a . for instance by writing myRect.width = 10
// Our trophy is a little more simple
var trophy = {
x: 0,
y: 0,
width: 0,
height: 0
}
var gameOver = false
// You can also use negative numbers!
function update()
{
myRect.x = myRect.x + myRect.x_speed
myRect.y = myRect.y + myRect.y_speed
// The "if" here means: only look at the next line if colliding_with_trophy() gives us 'true'
if( colliding_with_trophy() == true )
gameOver = true
}
function draw()
{
// We need to erase the last frame or weird stuff happens (comment this line out to see what I mean)
context.clearRect(0, 0, canvas.width, canvas.height)
// This is how we draw the player's rectangle
context.fillStyle = "red"
context.fillRect( myRect.x, myRect.y, myRect.width, myRect.height )
// This is how we draw the trophy rectangle
context.fillStyle = "gold"
context.fillRect( trophy.x, trophy.y, trophy.width, trophy.height )
if( gameOver == true )
{
context.fillStyle = "blue"
context.textBaseline = "top" // makes it write from the top left
context.font = "20px Arial" // you can set the text size and font here
// I know, I used "drawText" before for simplicity, but this is the real code
context.fillText("Game Over", 0, 0)
}
}
// Positive and negative numbers will determine movement
function handle_input( direction )
{
// Btw, the == checks if two things are equal
if( direction == "right" )
myRect.x_speed = 1
if( direction == "left" )
myRect.x_speed = 1
if( direction == "up" )
myRect.y_speed = -1
if( direction == "down" )
myRect.y_speed = 1
}
// ************************
// ************************
//
// Try messing around with the code. Here are some ideas for you.
//
// Try changing the color of the player rectangle and the trophy.
//
// Try renaming any variable - just remember to change its name EVERYWHERE.
//
// Make a new variable that will count how many times you touch the trophy.
// Now, change the code so that gameOver only becomes true after
// you touch the trophy 100 times.
//
// Make the trophy move to a random location any time you reload the page.
// You can use Math.random() to get a random number between 0 and 1, like:
// var myRandomNumber = Math.random()
// Multiply that by a bigger number to get a bigger random number.
// (Use the asterisk * to multiply)
//
// Make something happen when the player's rectangle goes off the screen.
// (You can use canvas.width to get the game canvas's width and
// canvas.height to get the game canvas's height.)
//
// Use `if` statements to make it so that you stop when you press
// the opposite direction.
//
// Example:
//
// if( myRect.x_speed > 0 )
// myRect.x_speed = 0
//
// Be careful - the order in which you put the `if` statements might matter.
//
// ************************
// ************************
// ************************
// ************************
//
// You can ignore all the stuff below (unless you are really curious and learning programming)
//
// ************************
// ************************
// This is one way to check for collision between the player's rectangle and the trophy.
// Usually we have a more general function to check any two objects, like check_collision( object1, object2 )
function colliding_with_trophy()
{
if(myRect.x < trophy.x + trophy.width && myRect.x + myRect.width > trophy.x) {
if(myRect.y < trophy.y + trophy.height && myRect.y + myRect.height > trophy.y) {
return true;
}
}
return false;
}
// This code waits for the webpage to load before setting some variables or adding events
window.addEventListener("DOMContentLoaded", function() {
canvas = document.getElementById("myCanvas");
context = canvas.getContext("2d");
// This connects the game to the user interactions (pressing a key or swiping a screen)
window.addEventListener("keydown", handleInputs);
window.addEventListener("touchstart", handleInputs);
window.addEventListener("touchmove", handleInputs);
setInterval(function() {
// handle_input() is handled with other functions
update();
draw();
}, 30);
});
// Just a messy way to try and deal with all user interactions
let latestTouchX = 0;
let latestTouchY = 0;
function handleInputs(e)
{
if(e.type === "touchstart") {
latestTouchX = e.targetTouches[0].clientX;
latestTouchY = e.targetTouches[0].clientY;
return;
}
// convert a swipe/touchmove to look like a keyboard entry
if(e.type === "touchmove") {
if(e.preventDefault)
e.preventDefault();
let newTouchX = e.changedTouches[0].clientX;
let newTouchY = e.changedTouches[0].clientY;
// handle horizontal
if(newTouchX - latestTouchX > 5)
{
e.keyCode = 39; // right
}
else
if(latestTouchX - newTouchX > 5)
{
e.keyCode = 37; // left
}
// handle vertical
if(newTouchY - latestTouchY > 5)
{
e.keyCode = 40; // down
}
else
if(latestTouchY - newTouchY > 5)
{
e.keyCode = 38; // up
}
latestTouchX = newTouchX;
latestTouchY = newTouchY;
}
switch(e.keyCode) {
case 38: // Up arrow
case 87: // W
handle_input("up");
break;
case 40: // Down arrow
case 83: // S
handle_input("down");
break;
case 37: // Left
case 65: // A
handle_input("left");
break;
case 39: // Right
case 68: // D
handle_input("right");
break;
default: {
}
}
}