Breakout Tutorial 4
This tutorial will show you how to build a clone of Breakout  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  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.
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.
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:
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:
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;
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.
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.