Image may be NSFW.
Clik here to view.This is the second in a series of tutorials on developing a full featured version of Breakout.
In the first tutorial we covered drawing primitive objects on the screen using the Canvas element and developing the basic game screen.
In this tutorial, we will use setInterval() to add some animation and capture keydown and keyup events to respond to user input (so we can move the paddle).
We will use the code from the last tutorial as our starting point.
Lets get started.
To animate objects in the game, we need to draw them, move them a little, and then redraw them. To do this, we create an animate() function and place our calls to the drawing functions inside it. For now, lets focus on only the paddle and the ball.
function animate () { drawPaddle(); drawBall(); }
Now we need to figure out a way to call animate() repeatedly at regular intervals. Luckily, Javascript has a function called setInterval() which keeps calling a given function repeatedly at fixed time intervals until the clearInterval() function is called.
function startGame(){ // call the animate() function every 20ms until clearInterval(gameLoop) is called gameLoop = setInterval(animate,20); } function endGame(){ clearInterval(gameLoop); context.fillText('The End!!!!',canvas.width/2,canvas.height/2); } startGame();
We create two functions called startGame() and endGame() to begin the animation and end it. We can also use startGame() to do any pre-game initialization of variables.
Now that the game loop is setup, we need to start moving the elements during the loop.
We start by creating a moveBall() function and calling it from within animate().
var ballDeltaX; var ballDeltaY; function moveBall(){ // Move the ball ballX = ballX + ballDeltaX; ballY = ballY + ballDeltaY; } function animate () { moveBall(); drawPaddle(); drawBall(); } function startGame(){ ballDeltaY = -4; ballDeltaX = -2; // call the animate() function every 200ms until clearInterval(gameLoop) is called gameLoop = setInterval(animate,20); }
The moveBall() function adjusts the ball coordinates by adding the ball speed. We initalize balldeltaX and ballDeltaY when the game starts.
Now that everything is in place, the ball should start moving.
Image may be NSFW.
Clik here to view.
However when we open the file in a browser, we see something weird.
Instead of a moving ball, we have a long black line. The ball keeps moving, however the old balls stay behind, leaving a long trail along the path. We need to clear the earlier objects before drawing new ones.
To do this, we can use the clearRect() method.
function animate () { context.clearRect(0,0,canvas.width,canvas.height);
This line clears the entire canvas at the beginning of the animation loop. When we run the code now, it looks like a moving ball instead of a long snake.
The next problem is that our ball doesn’t bounce off the walls. It keeps moving past the edge of the canvas and disappears. To fix that, lets add some conditions to check when the ball is moving outside the boundary.
function moveBall(){ // First check if we will bump into something // If top of the ball touches the top then reverse Y direction (move downwards) if (ballY + ballDeltaY - ballRadius < 0){ ballDeltaY = -ballDeltaY; } // If the bottom of the ball touches the bottom of the screen then end the game if (ballY + ballDeltaY + ballRadius > canvas.height){ endGame(); } // If side of ball touches either side of the wall then reverse X direction //left of ball moves too far left if ((ballX + ballDeltaX - ballRadius < 0) || //or right side of ball moves too far right (ballX + ballDeltaX + ballRadius > canvas.width)){ ballDeltaX = -ballDeltaX; } // Move the ball ballX = ballX + ballDeltaX; ballY = ballY + ballDeltaY; }
Great! Now the ball is bouncing off the walls properly and when it touches the ground the game ends.
Now lets animate the paddle. To move the paddle, we need to first track the left and right keys and keep track of where the paddle should move during the next animate(). We do this by using the keydown() and keyup() jQuery methods to assign event handlers for these events.
var paddleMove; function startGame(){ ballDeltaY = -4; ballDeltaX = -2; paddleMove = 'NONE'; paddleDeltaX = 0; // call the animate() function every 200ms until clearInterval(gameLoop) is called gameLoop = setInterval(animate,20); // Start Tracking Keystokes $(document).keydown(function(evt) { if (evt.keyCode == 39) { paddleMove = 'RIGHT'; } else if (evt.keyCode == 37){ paddleMove = 'LEFT'; } }); $(document).keyup(function(evt) { if (evt.keyCode == 39) { paddleMove = 'NONE'; } else if (evt.keyCode == 37){ paddleMove = 'NONE'; } }); }
The event handlers check if the key pressed or key released is Left (key code 39) or Right (key code 37) and stores this in a paddleMove variable. We will check this variable every time we animate to see where the paddle needs to move next.
The next thing we need to do is define another movePaddle() function that is called just like moveBall().
var paddleDeltaX; var paddleSpeedX = 10; function movePaddle(){ if (paddleMove == 'LEFT'){ paddleDeltaX = -paddleSpeedX; } else if (paddleMove == 'RIGHT'){ paddleDeltaX = paddleSpeedX; } else { paddleDeltaX = 0; } // If paddle reaches the side of the screen, then don't let it move any further if (paddleX + paddleDeltaX < 0 || paddleX + paddleDeltaX +paddleWidth >canvas.width){ paddleDeltaX = 0; } paddleX = paddleX + paddleDeltaX; } function animate () { context.clearRect(0,0,canvas.width,canvas.height); moveBall(); movePaddle(); drawPaddle(); drawBall(); }
We now call this new movePaddle() function from animate() as well.
Great! Now the paddle moves to the left and right when we use the cursor keys.
The last thing we need to do is make the ball bounce if it hits the paddle. We just need to add a condition to the other collision checks in moveBall().
// if bottom of ball reaches the top of paddle, if (ballY + ballDeltaY + ballRadius >= paddleY){ // and it is positioned between the two ends of the paddle (is on top) if (ballX + ballDeltaX >= paddleX && ballX + ballDeltaX <= paddleX + paddleWidth){ ballDeltaY = - ballDeltaY; } }
And thats it! The paddle moves perfectly, the ball bounces off the wall and the paddle, and if the ball hits the ground, the game ends.
We have come a long way from an empty rectangle on the browser. Of course, this game is still a little boring with just a ball and paddle.
In the next tutorial, we will bring back the bricks that we drew before, handle the ball colliding with these bricks, and finally increase the score when a brick gets destroyed.
You can download the finished source code for this tutorial below.
Continue to part 3 of this series. HTML5 Game Development Tutorial: Breakout Part III – Collisions, Scoring and Sound