Está en la página 1de 47

The Breakout game

In this part of the Qt4 C++ programming tutorial we will create a simple Breakout
game clone.

The Breakout is an arcade game developed by Atari Inc. The game was created in
1976. In this game, the player moves a paddle on the screen and bounces a ball/balls.
The objective is to destroy bricks in the top of the window.

The development

In our game, we have one paddle, one ball and 30 bricks. I have created an image for
a ball, paddle and a brick in Inkscape. We use a timer to create a game cycle. We do
not work with angles, we simply change directions. Top, bottom, left and right. I was
inspired by the pybreakout game. It was developed in PyGame library by Nathan
Dawson.

The game is intentionally simple. There are no bonuses, levels, score. So that it is
easier to understand.

The Qt4 C++ programming library is developed for creating computer applications.
Nevertheless, it can be used to create games as well. Developing a computer game is
a great way to learn the Qt4 programming library.

paddle.h

#ifndef PADDLE_H

#define PADDLE_H

#include <QImage>

#include <QRect>
class Paddle

public:

Paddle();

~Paddle();

public:

void resetState();

void moveLeft(int);

void moveRight(int);

QRect getRect();

QImage & getImage();

private:

QImage image;

QRect rect;

};
#endif

This is a header file for the paddle object.

paddle.cpp

#include "paddle.h"

Paddle::Paddle()

image.load("paddle.png");

rect = image.rect();

resetState();

Paddle::~Paddle()

printf("paddle deleted\n");

void Paddle::moveLeft(int left)


{

if (rect.left() >= 2)

rect.moveTo(left, rect.top());

void Paddle::moveRight(int right)

if (rect.right() <= 298)

rect.moveTo(right, rect.top());

void Paddle::resetState()

rect.moveTo(200, 360);

QRect Paddle::getRect()

return rect;

}
QImage & Paddle::getImage()

return image;

The paddle can be moved to the right or to the left.

Paddle::Paddle()

image.load("paddle.png");

rect = image.rect();

resetState();

In the constructor, we load our paddle image. Get the image rectangle and move the
image to it's starting position.

void Paddle::moveLeft(int left)

if (rect.left() >= 2)

rect.moveTo(left, rect.top());

}
The moveLeft() method moves the rectangle to the left.

brick.h

#ifndef BRICK_H

#define BRICK_H

#include <QImage>

#include <QRect>

class Brick

public:

Brick(int, int);

~Brick();

public:

void resetState();

bool isDestroyed();

void setDestroyed(bool);

QRect getRect();
void setRect(QRect);

QImage & getImage();

private:

QImage image;

QRect rect;

int position;

bool destroyed;

};

#endif

This is the header file for the brick object.

brick.cpp

#include "brick.h"

Brick::Brick(int x, int y)

image.load("brickie.png");
destroyed = FALSE;

rect = image.rect();

rect.translate(x, y);

Brick::~Brick() {

printf("Brick deleted\n");

QRect Brick::getRect()

return rect;

void Brick::setRect(QRect rct)

rect = rct;

QImage & Brick::getImage()


{

return image;

bool Brick::isDestroyed()

return destroyed;

void Brick::setDestroyed(bool destr)

destroyed = destr;

bool Brick::isDestroyed()

return destroyed;

The brick has a destroyed flag. If the destroyed flag is set, the brick is not drawn on
the window.

ball.h
#ifndef BALL_H

#define BALL_H

#include <QImage>

#include <QRect>

class Ball

public:

Ball();

~Ball();

public:

void resetState();

void moveBottom(int);

void moveTop(int);

void moveLeft(int);

void moveRight(int);

void autoMove();
void setXDir(int);

void setYDir(int);

int getXDir();

int getYDir();

QRect getRect();

QImage & getImage();

private:

int angle;

int speed;

int xdir;

int ydir;

bool stuck;

QImage image;

QRect rect;

};

#endif

The header file for the ball object.

ball.cpp
#include "ball.h"

Ball::Ball()

xdir = 1;

ydir = -1;

image.load("ball.png");

rect = image.rect();

resetState();

Ball::~Ball() {

printf("Ball deleted\n");

}
void Ball::autoMove()

rect.translate(xdir, ydir);

if (rect.left() == 0) {

xdir = 1;

if (rect.right() == 300) {

xdir = -1;

if (rect.top() == 0) {

ydir = 1;

void Ball::resetState()

rect.moveTo(230, 355);
}

void Ball::moveBottom(int bottom)

rect.moveBottom(bottom);

void Ball::moveTop(int top)

rect.moveTop(top);

void Ball::moveLeft(int left)

rect.moveLeft(left);

void Ball::moveRight(int right)

rect.moveRight(right);

}
void Ball::setXDir(int x)

xdir = x;

void Ball::setYDir(int y)

ydir = y;

int Ball::getXDir()

return xdir;

int Ball::getYDir()

return ydir;

}
QRect Ball::getRect()

return rect;

QImage & Ball::getImage()

return image;

The autoMove() method is called each game cycle to move the ball on the screen. If
it hists the boudaries, the ball direction changes.

breakout.h

#ifndef BREAKOUT_H

#define BREAKOUT_H

#include "ball.h"

#include "brick.h"

#include "paddle.h"

#include <QWidget>

#include <QKeyEvent>
class Breakout : public QWidget

Q_OBJECT

public:

Breakout(QWidget *parent = 0);

~Breakout();

protected:

void paintEvent(QPaintEvent *event);

void timerEvent(QTimerEvent *event);

void keyPressEvent(QKeyEvent *event);

void startGame();

void pauseGame();

void stopGame();

void victory();

void checkCollision();

private:
int x;

int timerId;

Ball *ball;

Paddle *paddle;

Brick * bricks[30];

bool gameOver;

bool gameWon;

bool gameStarted;

bool paused;

};

#endif

This is the header file for the breakout object.

int x;

int timerId;

The x value stores the current x position of the paddle. The timerId is used for
identifying of the timer object. This is necessary, when we pause the game.

breakout.cpp

#include "breakout.h"
#include <QPainter>

#include <QApplication>

Breakout::Breakout(QWidget *parent)

: QWidget(parent)

x = 0;

gameOver = FALSE;

gameWon = FALSE;

paused = FALSE;

gameStarted = FALSE;

ball = new Ball();

paddle = new Paddle();

int k = 0;

for (int i=0; i<5; i++) {

for (int j=0; j<6; j++) {

bricks[k] = new Brick(j*40+30, i*10+50);

k++;
}

Breakout::~Breakout() {

delete ball;

delete paddle;

for (int i=0; i<30; i++) {

delete bricks[i];

void Breakout::paintEvent(QPaintEvent *event)

QPainter painter(this);

if (gameOver) {

QFont font("Courier", 15, QFont::DemiBold);

QFontMetrics fm(font);

int textWidth = fm.width("Game Over");


painter.setFont(font);

int h = height();

int w = width();

painter.translate(QPoint(w/2, h/2));

painter.drawText(-textWidth/2, 0, "Game Over");

else if(gameWon) {

QFont font("Courier", 15, QFont::DemiBold);

QFontMetrics fm(font);

int textWidth = fm.width("Victory");

painter.setFont(font);

int h = height();

int w = width();

painter.translate(QPoint(w/2, h/2));

painter.drawText(-textWidth/2, 0, "Victory");

else {

painter.drawImage(ball->getRect(),
ball->getImage());

painter.drawImage(paddle->getRect(),

paddle->getImage());

for (int i=0; i<30; i++) {

if (!bricks[i]->isDestroyed())

painter.drawImage(bricks[i]->getRect(),

bricks[i]->getImage());

void Breakout::timerEvent(QTimerEvent *event)

ball->autoMove();

checkCollision();

repaint();

}
void Breakout::keyPressEvent(QKeyEvent *event)

switch (event->key()) {

case Qt::Key_Left:

int x = paddle->getRect().x();

for (int i=1; i<=5; i++)

paddle->moveLeft(x--);

break;

case Qt::Key_Right:

int x = paddle->getRect().x();

for (int i=1; i<=5; i++)

paddle->moveRight(x++);

break;

case Qt::Key_P:

pauseGame();

}
break;

case Qt::Key_Space:

startGame();

break;

case Qt::Key_Escape:

qApp->exit();

break;

default:

QWidget::keyPressEvent(event);

void Breakout::startGame()

if (!gameStarted) {

ball->resetState();

paddle->resetState();
for (int i=0; i<30; i++) {

bricks[i]->setDestroyed(FALSE);

gameOver = FALSE;

gameWon = FALSE;

gameStarted = TRUE;

timerId = startTimer(10);

void Breakout::pauseGame()

if (paused) {

timerId = startTimer(10);

paused = FALSE;

} else {

paused = TRUE;

killTimer(timerId);

}
void Breakout::stopGame()

killTimer(timerId);

gameOver = TRUE;

gameStarted = FALSE;

void Breakout::victory()

killTimer(timerId);

gameWon = TRUE;

gameStarted = FALSE;

void Breakout::checkCollision()

if (ball->getRect().bottom() > 400)

stopGame();
for (int i=0, j=0; i<30; i++) {

if (bricks[i]->isDestroyed()) {

j++;

if (j==30)

victory();

if ((ball->getRect()).intersects(paddle->getRect())) {

int paddleLPos = paddle->getRect().left();

int ballLPos = ball->getRect().left();

int first = paddleLPos + 8;

int second = paddleLPos + 16;

int third = paddleLPos + 24;

int fourth = paddleLPos + 32;

if (ballLPos < first) {

ball->setXDir(-1);

ball->setYDir(-1);
}

if (ballLPos >= first && ballLPos < second) {

ball->setXDir(-1);

ball->setYDir(-1*ball->getYDir());

if (ballLPos >= second && ballLPos < third) {

ball->setXDir(0);

ball->setYDir(-1);

if (ballLPos >= third && ballLPos < fourth) {

ball->setXDir(1);

ball->setYDir(-1*ball->getYDir());

if (ballLPos > fourth) {

ball->setXDir(1);

ball->setYDir(-1);

}
}

for (int i=0; i<30; i++) {

if ((ball->getRect()).intersects(bricks[i]->getRect())) {

int ballLeft = ball->getRect().left();

int ballHeight = ball->getRect().height();

int ballWidth = ball->getRect().width();

int ballTop = ball->getRect().top();

QPoint pointRight(ballLeft + ballWidth + 1, ballTop);

QPoint pointLeft(ballLeft - 1, ballTop);

QPoint pointTop(ballLeft, ballTop -1);

QPoint pointBottom(ballLeft, ballTop + ballHeight + 1);

if (!bricks[i]->isDestroyed()) {

if(bricks[i]->getRect().contains(pointRight)) {

ball->setXDir(-1);
}

else if(bricks[i]->getRect().contains(pointLeft)) {

ball->setXDir(1);

if(bricks[i]->getRect().contains(pointTop)) {

ball->setYDir(1);

else if(bricks[i]->getRect().contains(pointBottom)) {

ball->setYDir(-1);

bricks[i]->setDestroyed(TRUE);

Here is the game logic.


int k = 0;

for (int i=0; i<5; i++) {

for (int j=0; j<6; j++) {

bricks[k] = new Brick(j*40+30, i*10+50);

k++;

In the constructor of the Breakout object, we create 30 bricks.

painter.drawImage(ball->getRect(),

ball->getImage());

painter.drawImage(paddle->getRect(),

paddle->getImage());

for (int i=0; i<30; i++) {

if (!bricks[i]->isDestroyed())

painter.drawImage(bricks[i]->getRect(),

bricks[i]->getImage());

}
If the game is not won or lost, we draw the ball, paddle and the bricks in
the paintEvent().

void Breakout::timerEvent(QTimerEvent *event)

ball->autoMove();

checkCollision();

repaint();

In the timerEvent(), we move the ball, check if the ball collided with the paddle or a
brick and generate a paint event.

case Qt::Key_Left:

int x = paddle->getRect().x();

for (int i=1; i<=5; i++)

paddle->moveLeft(x--);

break;

If we press the left cursor key, we call the moveLeft() method of the paddle object.
We call the method five times, so that the movement is smooth.
void Breakout::stopGame()

killTimer(timerId);

gameOver = TRUE;

gameStarted = FALSE;

In the stopGame() method, we kill the timer and set the appropriate flags.

if (ball->getRect().bottom() > 400)

stopGame();

If the ball hits the bottom, we stop the game.

for (int i=0, j=0; i<30; i++) {

if (bricks[i]->isDestroyed()) {

j++;

if (j==30)

victory();

We check how many bricks are destroyed. If we destroyed all 30 bricks, we win the
game.
if (ballLPos < first) {

ball->setXDir(-1);

ball->setYDir(-1);

If the ball hits the first part of the paddle, we change the direction of the ball to north
east.

if(bricks[i]->getRect().contains(pointTop)) {

ball->setYDir(1);

If the ball hits the bottom of the brick, we change the y direction of the ball. It goes
down.
Figure: The Breakout game

So this was the Breakout game in C++ and Qt4 library.


001./*******************************************************
002.*     MYCPLUS Sample Code - http://www.mycplus.com
003.*   This code is made available as a service to our
004.*      visitors and is provided strictly for the
005.*               purpose of illustration.
006.*
007.* Please direct all inquiries to saqib at mycplus.com *
008.*******************************************************/
009. 
010.# include "process.h"
011.# include "dos.h"
012.# include "stdlib.h"
013.# include "graphics.h"
014.# include "stdio.h"
015. 
016.# define NULL 0
017.# define YES 1
018.# define NO 0
019. 
020.int maxx, maxy, midx, midy ;
021.int bri[5][20] ;
022. 
023.main()
024.{
025.union REGS ii, oo ;
026.int ballx, bally, paddlex, paddley, dx = 1, dy = -1, oldx, oldy ;
027.int gm = CGAHI, gd = CGA, playerlevel ;
028.int i, flag = 0, speed = 25, welldone = NO, score = 0, chance = 4, area ;
029.int layer[5] = { 10, 20, 30, 40, 50 }, limit = 50, currentlayer = 4 ;
030.char *p1, *p2 ;
031. 
032./* initialise the graphics system */
033.initgraph ( &gd, &gm, "D:\\TC\\BGI" ) ;
034. 
035./* get the maximum x and y screen coordinates */
036.maxx = getmaxx() ;
037.maxy = getmaxy() ;
038. 
039./* calculate center of screen */
040.midx = maxx / 2 ;
041.midy = maxy / 2 ;
042. 
043./* display opening screen and receive player's level */
044.playerlevel = mainscreen() ;
045. 
046./* set speed of ball as per the level chosen */
047.switch ( playerlevel )
048.{
049.case 'A' :
050.case 'a' :
051.speed = 15 ;
052.break ;
053. 
054.case 'E' :
055.case 'e' :
056.speed = 10 ;
057.}
058. 
059./* draw the bricks, the paddle and the ball */
060.rectangle ( 0, 0, maxx, maxy - 12 ) ;
061.bricks() ;
062.rectangle ( midx - 25, maxy - 7 - 12, midx + 25, maxy - 12 ) ;
063.floodfill ( midx, maxy - 1 - 12, 1 ) ;
064.circle ( midx, maxy - 13 - 12, 12 ) ;
065.floodfill ( midx, maxy - 10 - 12, 1 ) ;
066. 
067./* allocate memory for storing the image of the paddle */
068.area = imagesize ( midx - 12, maxy - 18, midx + 12, maxy - 8 ) ;
069.p1 = malloc ( area ) ;
070. 
071./* allocate memory for storing the image of the ball */
072.area = imagesize ( midx - 25, maxy - 7, midx + 25, maxy - 1 ) ;
073.p2 = malloc ( area ) ;
074. 
075./* if memory allocation unsuccessful */
076.if ( p1 == NULL || p2 == NULL )
077.{
078.puts ( "Insufficient memory!!" ) ;
079.exit ( 1 ) ;
080.}
081. 
082./* store the image of the paddle and the ball into allocated memory */
083.getimage ( midx - 12, maxy - 7 - 12 - 12 + 1, midx + 12, maxy - 8 - 12, p1 )
;
084.getimage ( midx - 25, maxy - 7 - 12, midx + 25, maxy - 1 - 12, p2 ) ;
085. 
086./* store current position of the paddle and ball */
087.paddlex = midx - 25 ;
088.paddley = maxy - 7 - 12 ;
089.ballx = midx - 12 ;
090.bally = maxy - 7 - 12 + 1 - 12 ;
091. 
092./* display balls in hand ( initially 3 ) */
093.gotoxy ( 45, 25 ) ;
094.printf ( "Balls Remaining:" ) ;
095.for ( i = 0 ; i < 3 ; i++ )
096.{
097.circle ( 515 + i * 35, maxy - 5, 12 ) ;
098.floodfill ( 515 + i * 35, maxy - 5, 1 ) ;
099.}
100. 
101./* display initial score */
102.gotoxy ( 1, 25 ) ;
103.printf ( "Your Score:   %4d", score ) ;
104. 
105./* select font and alignment for displaying text */
106.settextjustify ( CENTER_TEXT, CENTER_TEXT ) ;
107.settextstyle ( SANS_SERIF_FONT, HORIZ_DIR, 4 ) ;
108. 
109.while ( 1 )
110.{
111.flag = 0 ;
112. 
113./* save the current x and y coordinates of the ball */
114.oldx = ballx ;
115.oldy = bally ;
116. 
117./* update ballx and bally to move the ball in appropriate direction */
118.ballx = ballx + dx ;
119.bally = bally + dy ;
120. 
121./* as per the position of ball determine the layer of bricks to check */
122.if ( bally > 40 )
123.{
124.limit = 50 ;
125.currentlayer = 4 ;
126.}
127.else
128.{
129.if ( bally > 30 )
130.{
131.limit = 40 ;
132.currentlayer = 3 ;
133.}
134.else
135.{
136.if ( bally > 20 )
137.{
138.limit = 30 ;
139.currentlayer = 2 ;
140.}
141.else
142.{
143.if ( bally > 10 )
144.{
145.limit = 20 ;
146.currentlayer = 1 ;
147.}
148.else
149.{
150.limit = 10 ;
151.currentlayer = 0 ;
152.}
153.}
154.}
155.}
156. 
157./* if the ball hits the left boundary, deflect it to the right */
158.if ( ballx < 1 )
159.{
160.music ( 5 ) ;
161.ballx = 1 ;
162.dx = -dx ;
163.}
164. 
165./* if the ball hits the right boundary, deflect it to the left */
166.if ( ballx > ( maxx - 24 - 1 ) )
167.{
168.music ( 5 ) ;
169.ballx = maxx - 24 - 1 ;
170.dx = -dx ;
171.}
172. 
173./* if the ball hits the top boundary, deflect it down */
174.if ( bally < 1 )
175.{
176.music ( 5 ) ;
177.bally = 1 ;
178.dy = -dy ;
179.}
180. 
181./* if the ball is in the area occupied by the bricks */
182.if ( bally < limit )
183.{
184./* if there is no brick present exactly at the top of the ball */
185.if ( bri[currentlayer][ ( ballx + 10 ) / 32 ] == 1 )
186.{
187./* determine if the boundary of the ball touches a brick */
188.for ( i = 1 ; i <= 6 ; i++ )
189.{
190./* check whether there is a brick to the right of the ball */
191.if ( bri[currentlayer][ ( ballx + i + 10 ) / 32 ] == 0 )
192.{
193./* if there is a brick */
194.ballx = ballx + i ;
195.flag = 1 ;
196.break ;
197.}
198. 
199./* check whether there is a brick to the left of the ball */
200.if ( bri[currentlayer][ ( ballx - i + 10 ) / 32 ] == 0 )
201.{
202.ballx = ballx - i ;
203.flag = 1 ;
204.break ;
205.}
206.}
207. 
208./* if the ball does not touch a brick at the top, left or right */
209.if ( !flag )
210.{
211./* check if the ball has moved above the current layer */
212.if ( bally < layer[currentlayer - 1] )
213.{
214./* if so, change current layer appropriately */
215.currentlayer-- ;
216.limit = layer[currentlayer] ;
217.}
218. 
219./* put the image of the ball at the old coordinates */
220.putimage ( oldx, oldy, p1, OR_PUT ) ;
221. 
222./* erase the image at the old coordinates */
223.putimage ( oldx, oldy, p1, XOR_PUT ) ;
224. 
225./* place the image of the ball at the new coordinates */
226.putimage ( ballx, bally, p1, XOR_PUT ) ;
227. 
228./* introduce delay */
229.delay ( speed ) ;
230. 
231./* carry on with moving the ball */
232.continue ;
233.}
234.}
235. 
236./* control comes to this point only if the ball is touching a brick */
237.music ( 4 ) ;  /* play music */
238. 
239./* erase the brick hit by the ball */
240.erasebrick ( ( ballx + 10 ) / 32, currentlayer ) ;
241. 
242./* if the brick hit happens to be on the extreme right */
243.if ( ( ballx + 10 ) / 32 == 19 )
244.line ( maxx, 0, maxx, 50 ) ;  /* redraw right boundary */
245. 
246./* if the brick hit happens to be on the extreme left */
247.if ( ( ballx + 10 ) / 32 == 0 )
248.line ( 0, 0, 0, 50 ) ;  /* redraw left boundary */
249. 
250./* if the brick hit happens to be in the topmost layer */
251.if ( currentlayer == 0 )
252.line ( 0, 0, maxx, 0 ) ;  /* redraw top boundary */
253. 
254./* set appropriate array element to 1 to indicate absence of brick */
255.bri[currentlayer][ ( ballx + 10 ) / 32 ] = 1 ;
256. 
257.bally = bally + 1 ;  /* update the y coordinate */
258.dy = -dy ;  /* change the direction of the ball */
259.score += 5 ;  /* increment score */
260.gotoxy ( 16, 25 ) ;
261.printf ( "%4d", score ) ;  /* print latest score */
262. 
263./* if the first brick is hit during a throw */
264.if ( welldone == NO )
265.welldone = YES ;
266.else
267.{
268./* for the consecutive bricks hit during the same throw */
269.outtextxy ( midx, midy, "Well done!" ) ;
270.music ( 1 ) ;
271.}
272.}
273. 
274./* clear part of the screen used for displaying Well done message */
275.if ( bally > 50 && welldone == YES )
276.{
277.setviewport ( midx - 32 * 2.5, midy - 32 / 2, midx + 32 * 2.5, midy + 32 /
2, 1 ) ;
278.clearviewport() ;
279.setviewport ( 0, 0, maxx, maxy, 1 ) ;
280.welldone = NO ;
281.}
282. 
283./* if the ball has reached the bottom */
284.if ( bally > 180 - 12 )
285.{
286.welldone = NO ;
287. 
288./* if the paddle has missed the ball */
289.if ( ballx < paddlex - 20 || ballx > paddlex + 50 )
290.{
291./* continue the descent of the ball */
292.while ( bally < 177 )
293.{
294./* erase the image of the ball at the old coordinates */
295.putimage ( oldx, oldy, p1, XOR_PUT ) ;
296. 
297./* put the image of the ball at the updated coordinates */
298.putimage ( ballx, bally, p1, XOR_PUT ) ;
299. 
300./* introduce delay */
301.delay ( speed ) ;
302. 
303./* save the current x and y coordinates of the ball */
304.oldx = ballx ;
305.oldy = bally ;
306. 
307./* update ballx and bally to move the ball in appropriate direction */
308.ballx = ballx + dx ;
309.bally = bally + dy ;
310.}
311. 
312.chance-- ;  /* decrement the number of chances */
313.score -= 20 ;  /* decrement 20 points for each ball lost */
314.gotoxy ( 16, 25 ) ;
315.printf ( "%4d", score ) ;  /* print latest score */
316.music ( 2 ) ;
317. 
318./* erase one out of the available balls */
319.if ( chance )
320.putimage ( 515 + ( chance - 1 ) * 35 - 12 , maxy - 10, p1, XOR_PUT ) ;
321. 
322./* if the last ball is being played */
323.if ( chance == 1 )
324.{
325.gotoxy ( 45, 25 ) ;
326.printf ( "Your last ball... Be careful!" ) ;
327.}
328. 
329./* if all the balls are lost */
330.if ( !chance )
331.{
332.gotoxy ( 45, 25 ) ;
333.printf ( "Press any key...              " ) ;
334.outtextxy ( midx, midy, "I warned you! Try again" ) ;
335.music ( 3 ) ;
336. 
337.closegraph() ;
338.restorecrtmode() ;
339.exit ( 0 ) ;
340.}
341.}
342. 
343./* if ball is collected on paddle */
344.music ( 5 ) ;
345.bally = 180 - 12 ;  /* restore the y coordinate of ball */
346.dy = -dy ;  /* deflect the ball upwards */
347.}
348. 
349./* put the image of the ball at the old coordinates */
350.putimage ( oldx, oldy, p1, OR_PUT ) ;
351. 
352./* erase the image of the ball at the old coordinates */
353.putimage ( oldx, oldy, p1, XOR_PUT ) ;
354. 
355./* put the image of the ball at the upadted coordinates */
356.putimage ( ballx, bally, p1, XOR_PUT ) ;
357. 
358./* if all the bricks have been destroyed */
359.if ( score == 500 - ( ( 4 - chance ) * 20 ) )
360.{
361.outtextxy ( midx, midy, "You win !!!" ) ;
362. 
363.if ( score < 500 )
364.outtextxy ( midx, midy + 30, "Try scoring 500" ) ;
365.else
366.outtextxy ( midx, midy + 30, "You are simply GREAT!" ) ;
367. 
368.music ( 3 ) ;
369. 
370.closegraph() ;
371.restorecrtmode() ;
372.exit ( 0 ) ;
373.}
374. 
375./* introduce delay */
376.delay ( speed ) ;
377. 
378./* if the user has pressed a key to move the paddle */
379.if ( kbhit() )
380.{
381./* issue interrupt to obtain the ascii and scan codes of key hit */
382.ii.h.ah = 0 ;
383.int86 ( 22, &ii, &oo ) ;
384. 
385./* put the image of the paddle at the old coordinates */
386.putimage ( paddlex, paddley, p2, OR_PUT ) ;
387. 
388./* erase the image of the paddle at the old coordinates */
389.putimage ( paddlex, paddley, p2, XOR_PUT ) ;
390. 
391./* if Esc key has been pressed */
392.if ( oo.h.ah == 1 )
393.exit ( 0 ) ;
394. 
395./* right arrow key */
396.if ( oo.h.ah == 75 )
397.paddlex = paddlex - 20 ;
398. 
399./* left arrow key */
400.if ( oo.h.ah == 77 )
401.paddlex = paddlex + 20 ;
402. 
403./* if paddle goes beyond left boundary */
404.if ( paddlex < 0 )
405.paddlex = 0 ;
406. 
407./* if paddle goes beyond right boundary */
408.if ( paddlex > 589 )
409.paddlex = 589 ;
410. 
411./* put the image of the paddle at the proper position */
412.putimage ( paddlex, paddley, p2, XOR_PUT ) ;
413.}
414.}
415.}
416. 
417./* creates opening screen */
418.mainscreen()
419.{
420./* array showing the positions where a brick is needed to form the figure
BRICKS */
421.int ff[12][40] = {
422.1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,1,1,0,0,1,0,0,0,0,1,0,0,0,1,1,
1,0,
423.1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,
0,1,
424.1,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,
0,0,
425.1,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,
0,0,
426.1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,
0,0,
427.1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,
0,0,
428.1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,
1,0,
429.1,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,
0,1,
430.1,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,
0,1,
431.1,0,0,0,1,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,
0,1,
432.1,1,1,1,0,0,0,1,0,0,0,0,1,0,1,1,1,1,1,0,0,0,1,1,1,0,0,1,0,0,0,0,1,0,0,1,1,1,
1,0,
433.0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,
434.} ;
435.int i, j, lx = 0, ly = 0, ch ;
436. 
437./* draw boundary */
438.rectangle ( 0, 0, maxx, maxy ) ;
439. 
440./* form the word BRICKS */
441.for ( i = 0 ; i < 12 ; i++ )
442.{
443.for ( j = 0 ; j < 40 ; j++ )
444.{
445.if ( ff[i][j] )
446.rectangle ( lx, ly, lx + 15, ly + 9 ) ;
447.lx = lx + 16 ;
448.}
449.lx = 0 ;
450.ly = ly + 10 ;
451.}
452. 
453./* draw pattern at the bottom of the screen */
454.line ( 0, maxy - 12, maxx, maxy - 12 ) ;
455.setfillstyle ( XHATCH_FILL, WHITE ) ;
456.floodfill ( 2, maxy - 2, WHITE ) ;
457. 
458./* draw the paddle and the ball */
459.setfillstyle ( SOLID_FILL, WHITE ) ;
460.rectangle ( midx - 25, maxy - 7 - 12, midx + 25, maxy - 12 ) ;
461.floodfill ( midx, maxy - 1 - 12, 1 ) ;
462.circle ( midx, maxy - 13 - 12, 12 ) ;
463.floodfill ( midx, maxy - 10 - 12, 1 ) ;
464. 
465.music ( 3 ) ;  /* play music */
466. 
467./* display menu */
468.while ( 1 )
469.{
470./* clear the region below the word BRICKS */
471.setviewport ( 1, 125 - 12, maxx - 1, maxy - 1, 1 ) ;
472.clearviewport() ;
473. 
474.setviewport ( 0, 0, maxx, maxy, 1 ) ;
475.outtextxy ( 20, 135, "Select any of the following:" ) ;
476.outtextxy ( 20, 155, "Play ( P )" ) ;
477.outtextxy ( 20, 165, "Instructions ( I )" ) ;
478.outtextxy ( 20, 175, "Exit ( E )" ) ;
479. 
480.ch = 0 ;
481. 
482./* continue till the correct choice is made */
483.while ( ! ( ch == 'E' || ch == 'I' || ch == 'P' ) )
484.{
485.fflush ( stdin ) ;
486. 
487./* if a special key is hit, flush the keyboard buffer */
488.if ( ( ch = getch() ) == 0 )
489.getch() ;
490.else
491.ch = toupper ( ch ) ;
492.}
493. 
494.if ( ch == 'P' )
495.break ;
496. 
497.switch ( ch )
498.{
499.case 'I' :
500.setviewport ( 1, 125 - 12, maxx - 1, maxy - 1, 1 ) ;
501.clearviewport() ;
502. 
503.setviewport ( 0, 0, maxx, maxy, 1 ) ;
504.settextstyle ( DEFAULT_FONT, HORIZ_DIR, 1 ) ;
505.outtextxy ( 20, 125, "         Instructions        " ) ;
506.settextstyle ( DEFAULT_FONT, HORIZ_DIR, 0 ) ;
507.outtextxy ( 20, 140, "Use left and right arrow keys to move paddle." ) ;
508.outtextxy ( 20, 150, "If you don't collect the ball on the paddle, you lose
the ball." ) ;
509.outtextxy ( 20, 160, "On loosing a ball you loose 20 points." ) ;
510.outtextxy ( 20, 170, "On taking a brick you gain 5 points." ) ;
511.outtextxy ( 20, 185, "Press any key..." ) ;
512.fflush ( stdin ) ;
513.if ( getch() == 0 )
514.getch() ;
515.break ;
516. 
517.case 'E' :
518.closegraph() ;
519.restorecrtmode() ;
520.exit ( 0 ) ;
521.}
522.}
523. 
524.setviewport ( 1, 125 - 12, maxx - 1, maxy - 1, 1 ) ;
525.clearviewport() ;
526. 
527./* prompt the user for the level desired */
528.setviewport ( 0, 0, maxx, maxy, 1 ) ;
529.outtextxy ( 20, 135, "Select any of the following levels:" ) ;
530.outtextxy ( 20, 155, "Novice ( N )" ) ;
531.outtextxy ( 20, 165, "Advanced ( A )" ) ;
532.outtextxy ( 20, 175, "Expert ( E )" ) ;
533. 
534./* get user's choice */
535.fflush ( stdin ) ;
536.if ( ( ch = getch() ) == 0 )
537.getch() ;
538. 
539.clearviewport() ;
540. 
541./* return the choice made by the user */
542.return ( ch ) ;
543.}
544. 
545./* draws bricks at the start of the game */
546.bricks()
547.{
548.int i, j, lx = 0, ly = 0 ;
549. 
550.for ( i = 0 ; i < 5 ; i++ )  /* 5 rows */
551.{
552.for ( j = 0 ; j < 20 ; j++ )  /* 20 columns */
553.{
554./* draw a brick at appropriate coordinates */
555.drawbrick ( lx, ly ) ;
556. 
557.lx = lx + 32 ;
558.}
559. 
560.lx = 0 ;
561.ly = ly + 10 ;
562.}
563.}
564. 
565./* draws a brick at the proper position */
566.drawbrick ( int lx, int ly )
567.{
568.rectangle ( lx, ly, lx + 31, ly + 9 ) ;
569.rectangle ( lx + 2, ly - 2, lx + 31 - 2, ly + 9 - 2 ) ;
570.floodfill ( lx + 1, ly + 1, 2 ) ;
571.}
572. 
573./* erases the specified brick */
574.erasebrick ( int b, int l )
575.{
576./* b - brick number, l - layer */
577. 
578.setcolor ( BLACK ) ;
579.rectangle ( b * 32, l * 10, ( b * 32 ) + 31 , ( l * 10 ) + 9 ) ;
580.rectangle ( b * 32 + 1, l * 10, ( b * 32 ) + 31 - 1, ( l * 10 ) + 9 - 1 ) ;
581.rectangle ( b * 32 + 2, l * 10, ( b * 32 ) + 31 - 2, ( l * 10 ) + 9 - 2 ) ;
582.setcolor ( WHITE ) ;
583.}
584. 
585./* plays different types of music */
586.music ( int type )
587.{
588./* natural frequencies of 7 notes */
589.float octave[7] = { 130.81, 146.83, 164.81, 174.61, 196, 220, 246.94 } ;
590.int n, i ;
591. 
592.switch ( type )
593.{
594.case 1 :
595.for ( i = 0 ; i < 7 ; i++ )
596.{
597.sound ( octave[i] * 8 ) ;
598.delay ( 30 ) ;
599.}
600.nosound() ;
601.break ;
602. 
603.case 2 :
604.for ( i = 0 ; i < 15 ; i++ )
605.{
606.n = random ( 7 ) ;
607.sound ( octave[n] * 4 ) ;
608.delay ( 100 ) ;
609.}
610.nosound() ;
611.break ;
612. 
613.case 3 :
614.while ( !kbhit() )
615.{
616.n = random ( 7 ) ;
617.sound ( octave[n] * 4 ) ;
618.delay ( 100 ) ;
619.}
620.nosound() ;
621. 
622./* flush the keyboard buffer */
623.if ( getch() == 0 )
624.getch() ;
625. 
626.break ;
627. 
628.case 4 :
629.for ( i = 4 ; i >= 0 ; i-- )
630.{
631.sound ( octave[i] * 4 ) ;
632.delay ( 15 ) ;
633.}
634.nosound() ;
635.break ;
636. 
637.case 5 :
638.sound ( octave[6] * 2 ) ;
639.delay ( 50 ) ;
640.nosound() ;
641.}
642.}

También podría gustarte