Breakout Tutorial 4

From SwinGame

This page contains a Tutorial. Tutorials are designed to walk you through the development of a small game.
Breakout in SwinGame

This tutorial will show you how to build a clone of Breakout [1] in Pascal using the SwinGame SDK. Breakout is the successor to Pong, making it one of the first few computer games. It took Steve Wozniak [2] four days to build the first prototype of Breakout, however in SwinGame you can make it in a couple of hours. By the end of this tutorial you will have a fully functional Breakout game, with different levels, sound effects, and completely addictive gameplay.


Warning: You must have completed the previous tutorial(s) to go through this tutorial


We are now going to create the bricks. The bricks are going to be represented in memory with an array of brick types, as we defined in the first part of this tutorial.

Contents

Before we begin

We need to add a reference to the SGSDK_Shapes library in order to be able to get to some extra parts of the SwinGame library. At the beginning of GameLogic.Pas, change the line beginning with “SGSDK,KeyCodes” to:

SGSDK_KeyCodes, SGSDK_Shapes;

Adding resources

Firstly we need to open up GameResources.pas and add the brick images. Modify the LoadImages() procedure to include these lines:

NewImage('brick1','brick1.png');
NewImage('brick2','brick2.png');
NewImage('brick3','brick3.png');

Make sure brick1-3.png are in the Resources\Images folder.

Creating the brick data structure

Open up GameLogic.pas and add the following lines to the ‘’’const’’’ section:

// Brick properties
	brickWidth = 80;
	brickHeight = 20;

These constants are used in calculating the positions of the bricks. Now add the following record to the ‘’’type’’’ section:

// brick: used for bricks
	brick = record
		brickColor : integer;		// brickcolor: this also controls what score the player will get when this brick is hit
		brickSprite : Sprite;		// brick sprite
		hit : boolean;				// has the brick been hit?
		end;

Now we need to create the array of bricks. Add the following code to the ‘’’var’’’ section:

bricks : array [1..bricksPerRow * bricksRows] of brick;		// The bricks 

Note that this is a single-dimensional array. The way we will address each brick in the grid will be with a single ID number. How is it possible to go from a brick number to a brick’s coordinates in the grid? We can do this by using the divide and modulus functions like this:

GridX := ((i-1) mod bricksPerRow) ;
GridY := ((i-1) div bricksPerRow);

This code will give the X and Y coordinate ‘’’in the grid’’’ of the brick. For instance if the grid is 7 blocks wide, and i = 5, then GridX is 4 and GridY is 0, since (0,0) is the first brick. If i=16, then GridX is 1 and GridY is 2 (ie. it’s the second brick in the third row). From this, we can create a function that gets the coordinate of the brick with regards to pixels:

function GetBrickCoordinatesFromGridPosition(i : integer) : Point2D;
  var
	GridX, GridY : integer;
	brickPoint : Point2D;
  begin
	// Get the grid coordinates of this brick (ie. row 3 brick 4)
	GridX := ((i-1) mod bricksPerRow) ;
	GridY := ((i-1) div bricksPerRow);
	
	brickPoint.X := GridX * (brickWidth+10);
	brickPoint.Y := GridY * (brickHeight+10);
	
	result := brickPoint;
  end;

Copy this function into the code block before procedure Main(). Underneath this function, add the following code:

// Resets the array of bricks
  procedure InitialiseBricks();
  var
	i : integer;
	brickPoint : Point2D;
  begin
	for i:= 1 to bricksPerRow*bricksRows do
		begin
			// Get the row number / brick color number
			bricks[i].brickColor := ((i-1) div bricksPerRow) + 1;
			// Load the sprite depending on the brick number
			bricks[i].brickSprite := CreateSprite(GameImage('brick' + IntToStr(bricks[i].brickColor)));
	 		// Create the sprite position
			brickPoint := GetBrickCoordinatesFromGridPosition(i);
			bricks[i].brickSprite.X := (screenWidth/2-(bricksPerRow*90)/2) + brickPoint.X;
			bricks[i].brickSprite.Y := 32 + brickPoint.Y;
 
			bricks[i].hit := false;
		end;
  end;

This code initializes the bricks. It creates a sprite for each brick, and generates the coordinates from the GetBrickCoordinatesFromGridPosition. BrickColor is set to the row number of the brick (starting at one), which is used to choose the sprite that is used to represent the brick. The idea is that each brick sprite (brick1.png, brick2.png, brick3.png etc..) is a different color, so each row of bricks is the same color. Later on when we add scoring to the game, the brickColor will be used to calculate the number of points added to the player’s score when the brick is hit. Finally, the brick’s hit value is set to false. When the brick is hit, this is set to true, so the brick isn’t shown on screen anymore.

Finally, to initialize the bricks, go to the Main procedure, and after InitialiseBall, add the following code:

InitialiseBricks();

Drawing the bricks

Now we will add the code to draw the bricks, and to check if they have been hit. We first need to create an integer so we can iterate through the bricks. Directly under “procedure Main();”, add the following:

var
	i : integer;

Scroll down to the game loop, and underneath the code which checks if the ball has hit the paddle, add the following code:

// Check if the ball has hit any bricks
	  for i := 1 to bricksPerRow * bricksRows do
		begin
			if HaveSpritesCollided(ball, bricks[i].brickSprite) and (bricks[i].hit = false) then
			begin
			    //  Hit a brick!
				bricks[i].hit := true;
				// Take from the number of bricks remaining
				player.bricksRemaining := player.bricksRemaining -1;
				// Bounce the ball off the brick
				ball.Movement.Y := -ball.Movement.Y;
			end;
		end;

w This code loops through each brick and checks if the ball has collided with it. If it has, the ball will bounce off, and the number of bricks remaining will decrease by one. Later on we will add the code for scoring to this part of the loop. Now we need to add the code to draw the bricks. After the code which draws the player, add this code:

// Draw the bricks
	  for i := 1 to bricksPerRow*bricksRows do
		begin
			if bricks[i].hit = false then
				begin
					DrawSprite(bricks[i].brickSprite);
					UpdateSprite(bricks[i].brickSprite);
				end;
		end;
Breakout so far: Now you can hit the bricks with the ball using the paddle

This loops though the bricks and draws each one which hasn’t been hit. Now when you run the code, you will be able to bounce the ball off the bricks, and the bricks will disappear.

Summary

In this tutorial, we have created the bricks, and the code so that the bricks will break when hit. In the next tutorial, we will implement scoring and levels.

List of Tutorials