Sign in to follow this  
ISDCaptain01

Revew my pong clone: game and code!

Recommended Posts

Well I've finally did it. Ive made my very first game, and it does look quite good! I am posting a pic of it, source code, and download link to the project. Tools used: C++, Allegro 4.2

 

 

Heres the picture

http://www.sendspace.com/file/nd9ncs

 

Heres the code:

 

header file

#pragma once
#include <allegro.h>
#include <iostream>
using namespace std;

//color macros
#define WHITE (255, 255, 255)
#define BLUE (5, 209, 255)

//Sprite Variables
BITMAP *background;
BITMAP *buffer;

//Player scores
int player1 = 0; //LEFT
int player2 = 0; //RIGHT

//Sounds
SAMPLE *maintheme;
SAMPLE *impact;








class Paddle
{
public:
	int x, y;
	int width, height;
	BITMAP *paddleSprite;

};

//Create two paddles
Paddle paddle1;
Paddle paddle2;

class Star
{
public:
	int x, y;
	int dirx;
	int diry;
	int width, height;
	float angle;
	BITMAP *starSprite;
};

//Create a star ball
Star starball;


//Gives the star a rotation effect
void rotateStar(Star &star)
{
	

	//draw star to screen
	rotate_sprite(buffer, star.starSprite, star.x, star.y, star.angle);

	//rotate star in 256 angles
	if(star.angle > 256)
	{
		star.angle = 0;
	}
	else
	{
		star.angle += 1;
	    rotate_sprite(buffer, star.starSprite, star.x, star.y, itofix(star.angle));
	}
		
}


void moveStar(Star &star, Paddle &paddle1, Paddle &paddle2)
{
	//update star x postion
	star.x += star.dirx;

	//Hits the left side of the screen
	if(star.x < 0)
	{
		star.x = 1;
		star.dirx = rand()%2 + 6;

		//decrement score for player 2
		if(player2 < 0)
		{
		    player2 = 0;
		}
		else
		{
			player2--;
		}

	}

	//Hits the right side of the screen
	if(star.x > SCREEN_W - star.width - 1)
	{
		star.x = SCREEN_W - star.width - 1;
		star.dirx = rand()%2 - 6;

		//decrement score for player 1
		if(player1 < 0 )
		{
		    player1 = 0;
		}
		else
		{
			player1--;
		}
	}

	//update star y position
	star.y += star.diry;

	//Hits the top of the screen
	if(star.y < 0)
	{
		star.y = 2;
		star.diry = rand()%2 + 6;
	}
	//Hits the bottom of the screen
	if(star.y > SCREEN_H - star.height - 2)
	{
		star.y = SCREEN_H - star.height - 2;
		star.diry = rand()%2 - 6;
	}

	//Check if it hits paddle1
	if (star.x > paddle1.x && star.x < paddle1.x+paddle1.width &&
        star.y > paddle1.y && star.y < paddle1.y+paddle1.height)
    {
		play_sample(impact, 128, 128, 1000, FALSE);
        player1++;
		star.x = paddle1.x - star.height - 1;
        star.dirx = rand() % 2 - 6;
		
    }

	//check if it hits paddle2;
	if(star.x > paddle2.x && star.x < paddle2.x+paddle2.width &&
	   star.y > paddle2.y && star.y < paddle2.y+paddle2.height)
	{
		play_sample(impact, 128, 128, 1000, FALSE);
		player2++;
		star.x = paddle2.x + star.height + 1;
		star.dirx = rand() % 2 + 6;
	}
}

void moveup(Paddle &paddle)
{
	paddle.y-=5;
	if(paddle.y < 0)
	{
		paddle.y = 0;
	}
}

void movedown(Paddle &paddle)
{
	paddle.y+=5;
	if(paddle.y > SCREEN_H-paddle.height)
	{
		paddle.y = SCREEN_H - paddle.height;
	}
}



//Checks for key presses
void getinput()
{
	//paddle1 controls
	if(key[KEY_DOWN])
	{
		movedown(paddle1);
	}

	if(key[KEY_UP])
	{
		moveup(paddle1);
	}


	//paddle2 controls
	if(key[KEY_W])
	{
		moveup(paddle2);
	}

	if(key[KEY_S])
	{
		movedown(paddle2);
	}
}




	

void drawpaddle(Paddle &paddle)
{
	blit(paddle.paddleSprite, buffer, 0, 0, paddle.x, paddle.y, paddle.width, paddle.height);
}




//Draws the court line
void drawborder(BITMAP *dest)
{
	int n;
	int y1 = 1;
    int y2 = 4;

	for(n = 0; y2 < SCREEN_H; n++)
	{
	   rectfill(dest, (SCREEN_W/2)-2, y1, (SCREEN_W/2)+2, y2, BLUE);
	   y1 += 5;
	   y2 += 5;
	}
}

void setuppaddles()
{

	//Set up paddles for drawing time
	paddle1.paddleSprite = load_bitmap("paddle1.bmp", NULL);
	paddle1.width = paddle1.paddleSprite->w;
	paddle1.height = paddle1.paddleSprite->h;
    paddle1.x = 740;
	paddle1.y = SCREEN_H/2;


	paddle2.paddleSprite = load_bitmap("paddle.bmp", NULL);
	paddle2.width = paddle2.paddleSprite->w;
	paddle2.height = paddle2.paddleSprite->h;
	paddle2.x = 30;
	paddle2.y = SCREEN_H/2;
}

void setupstar()
{
	    starball.starSprite = load_bitmap("star.bmp", NULL);
		starball.x =  SCREEN_W/2;
		starball.y =  SCREEN_H/2;
		starball.dirx = 1;
		starball.diry = 2;
		starball.angle = 0;
		starball.width = starball.starSprite->w;
		starball.height = starball.starSprite->h;
}

main.cpp

#include "functions.h"


int main()
{
	//Initialize Allegro
	allegro_init();

	//Install subsystems
	install_keyboard();
	install_timer();
	srand(time(NULL));

	//Set graphics bit mode
	set_color_depth(24);

	//set the screen
	int ret = set_gfx_mode(GFX_SAFE, 800, 600, 0, 0);
	//failure check
	if(ret != 0)
	{
		allegro_message(allegro_error);
		return 1;
	}

	//Set up the sound system
	if((install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, "") != 0))
	{
		allegro_message("Failed to Initialize Sound System!");
		return 1;
	}

	

	//create the buffer
	buffer = create_bitmap(SCREEN_W, SCREEN_H);

	//load the background
	background = load_bitmap("bluespace.bmp", NULL);
	
	//set up paddle
	setuppaddles();

	//set up the starball
	setupstar();

	//load main theme
	maintheme = load_sample("wing_mario.wav");
	play_sample(maintheme, 128, 128, 1000, TRUE);

	//load the impact sound
    impact = load_sample("impact.wav");

	//Main game loop
	while(!key[KEY_ESC])
	{
		
		//Erase the entire screen really fast by blitting the
		//entire background onto it
		blit(background, buffer, 0, 0, 0, 0, background->w, background->h);

		//Show scores
		textprintf_ex(buffer, font, 30, 590, BLUE, -1, "Player 2 Score: %d", player2);
		textprintf_ex(buffer, font, 640, 590, BLUE, -1, "Player 1 Score: %d", player1);

		//Draw a border between players
		drawborder(buffer);
		
		//Draw the paddles
		drawpaddle(paddle1);
		drawpaddle(paddle2);

		//Draw the rotating star
		rotateStar(starball);

		//move the star
		moveStar(starball, paddle1, paddle2);

		//check for control inputs
		if(keypressed())
		{
			getinput();
		}
		
		//Lock screen
		acquire_screen();
		
		//draw the screen
		blit(buffer, screen, 0, 0, 0, 0, buffer->w, buffer->h);

		//unlock screen
		release_screen();

		rest(10); 
	}

	destroy_bitmap(background);
	destroy_bitmap(buffer);
	destroy_bitmap(paddle1.paddleSprite);
	destroy_bitmap(paddle2.paddleSprite);
	destroy_bitmap(starball.starSprite);

	remove_sound();

	allegro_exit();
	return 0;
}
END_OF_MAIN()


Heres the download to the project:

http://www.sendspace.com/file/qs6w0b

 

 

The game is fully functional, although the paddle collision is somewhat buggy.  But I Tried my best for my first game. Please critique my code and game.

Edited by ISDCaptain01

Share this post


Link to post
Share on other sites

This code's not bad for a first project; it's organized reasonably well and is pretty easy to read. As far as structure goes, you'd need only a few tweaks to make it more solid:
 
The functions that manipulate the ball and paddles could be moved into the classes as methods, like so:
 

class Paddle
{
public:
	int x, y;
	int width, height;
	BITMAP *paddleSprite;

	void moveUp() {
		y-=5;
		if(y < 0)
		{
			y = 0;
		}
	}

	void moveDown() { /* ... */ }
	void draw() { /* ... */ }
};

Then instead of calling moveup(paddle1), you would call paddle1.moveUp().
 
You could also take advantage of the similarities between the paddles and the ball. They are both game entities with coordinates, width, height, and an image, so you can pull those similarities into a base class:
 

class Entity
{
	int x, y;
	int width, height;
	BITMAP* sprite;

	void draw()
	{
		blit(sprite, buffer, 0, 0, x, y, width, height);
	}
}

//Has all the fields from Entity plus whatever we add here:
class Paddle: Entity {
	//moveUp(), moveDown, etc.
}

class Star: Entity {
	void rotate() { /* ... */ }

	//etc., etc.
}

I can think of a few more things you might want to tweak, but I'll leave you with that for now because it's getting late, and this post will probably take a little while to "digest" if you're not already familiar with methods and inheritance.

Share this post


Link to post
Share on other sites

I'm trying to figure out why you even have a header. Headers are for what you want to share between cpp files. With only one cpp file, there isn't really any point.

 

If you want to practice, put publicly available data structures into headers, with simple inline functions and function prototypes for more complex functions. Keep normal functions in cpp files. I generally start out by coding every function as a static function in a cpp file and then promote them into member functions or global functions as necessary, but most people are less extreme about static function use in c++ as I am, and probably make more private member functions instead. Whatever works for you is fine.

 

You definitely do not want global variables in your header. Each global variable should only live in one compilation unit.

 

You should work on removing the global variables. They should really be the last resort. Learn to program without them. Start with the easiest ones. For example, your background sprite is only referenced within your main function, it's loaded, blitted, and destroyed all in the same function, so it can be local to main.

 

Also, I notice that your text color macro is BLUE, but the screenshot has red text. You should probably just delete those macros, which do not make very much sense, and use whatever color function is in your API to create the proper color int. Macros are best as a last resort.

 

Anyway, congratulations on making a pong game.

 

Share this post


Link to post
Share on other sites

Things to put in a header:

 

Macros (Only if you really need a macro, and it needs to go in a header. Conditional compilation switches/include guards are ok).

Extern globals (minimise globals though)

Type definitions (class/struct) which need to be seen from other files. This is mainly what you should use headers for.

Global function prototypes which are called from other files.

Const globals if they need to be shared between compilation units.

Inline functions/template classes. They need to be visible to every compilation unit which uses them.

 

Things not to put in a header:

 

everything else

 

I think that covers it?

Edited by Paradigm Shifter

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this