//////////////////////// HEADERS /////////////////
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <allegro5/allegro.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_image.h>
using namespace std;
/////////// GLOBAL VARIABLES //////////////////////////////////
const float FPS = 60;
const int SCREEN_W = 640;
const int SCREEN_H = 480;
const int BOUNCER_SIZE = 32;
const int PADDLE_SIZE_X = 15;
const int PADDLE_SIZE_Y = 160;
const double SPEED = 2.0;
const double PADSPEED = 2.0;
enum MYKEYS{KEY_W, KEY_S, KEY_SPACE};
/////////////////// MAIN --- PROGRAM ENTRY /////////////////////////////////////////////////
int main(int argc, char **argv)
{
/////////////////////////// LOCAL VARIABLES ///////////////////////////////////////////////////
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
ALLEGRO_TIMER *timer = NULL;
ALLEGRO_BITMAP *bouncer = NULL;
ALLEGRO_BITMAP *p1Paddle = NULL;
ALLEGRO_BITMAP *p2Paddle = NULL;
ALLEGRO_FONT *font_bitmap = NULL;
int p1Score = 0, p2Score = 0, misses = 0;
float bouncer_x = SCREEN_W / 2.0 - BOUNCER_SIZE / 2.0;
float bouncer_y = SCREEN_H / 2.0 - BOUNCER_SIZE / 2.0;
float p1Paddle_x = 10;
float p1Paddle_y = SCREEN_H / 2.0 - PADDLE_SIZE_Y / 2.0;
float p2Paddle_x = SCREEN_W - 10 - PADDLE_SIZE_X;
float p2Paddle_y = SCREEN_H / 2.0 - PADDLE_SIZE_Y / 2.0;
float bouncer_dx = -SPEED, bouncer_dy = SPEED;
float pad_dy = PADSPEED;
bool key[3] = {false, false, false};
bool doexit = false;
bool redraw = true;
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
// REMEMBER TO REMOVE THIS ONCE DONE!!!!!!!!!!!
// Debugging output file
ofstream dosFile;
dosFile.open("debug/pongDebug.txt");
dosFile << "Ball Pos (x, y) Player 1 Pos (x, y) Player 2 Pos(x, y)" << endl;
// intialize allegro , if it fails return error message
if (!al_init())
{
fprintf(stderr, "failed to initialize allegro!\n");
return -1;
}
// initialize image and font addons
al_init_image_addon();
al_init_font_addon();
// install the keyboard, if it fails return error message
if(!al_install_keyboard())
{
fprintf(stderr, "failed to initialize the keyboard!\n");
return -1;
}
// create timer
timer = al_create_timer(1.0 / FPS);
// if timer fails to create, return error message
if (!timer)
{
fprintf(stderr, "failed to create timer!\n");
return -1;
}
// create display
display = al_create_display(SCREEN_W, SCREEN_H);
// if display fails to create, return error message
if (!display)
{
fprintf(stderr, "failed to create display!\n");
return -1;
}
// create bouncer bitmap
bouncer = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE);
// if it fails then return error and destroy the display bitmap and timer
if (!bouncer)
{
fprintf(stderr, "failed to create bouncer bitmap!\n");
al_destroy_display(display);
al_destroy_timer(timer);
return -1;
}
// create bitmap for paddle
p1Paddle = al_create_bitmap(PADDLE_SIZE_X, PADDLE_SIZE_Y);
// if creating paddle fails return error message
if (!p1Paddle)
{
fprintf(stderr, "failed to create player one paddle bitmap!\n");
al_destroy_display(display);
al_destroy_timer(timer);
return -1;
}
// create bitmap for paddle 2
p2Paddle = al_create_bitmap(PADDLE_SIZE_X, PADDLE_SIZE_Y);
// if creating paddle fails return error message
if (!p2Paddle)
{
fprintf(stderr, "failed to create player two paddle bitmap!\n");
al_destroy_display(display);
al_destroy_timer(timer);
return -1;
}
// create and load the font used
font_bitmap = al_load_font("data/bmpfont.tga", 0, 0);
// if create/load fails return error message
if(!font_bitmap)
{
fprintf(stderr, "failed to create font!\n");
return -1;
}
// set players paddle image
al_set_target_bitmap(p1Paddle);
// set paddle to color
al_clear_to_color(al_map_rgb(0, 191, 255));
// set player 2 paddle
al_set_target_bitmap(p2Paddle);
// set player 2 paddle to color
al_clear_to_color(al_map_rgb(0, 255, 191));
// set bouncer sprite
al_set_target_bitmap(bouncer);
// set ball/bouncer sprite to color
al_clear_to_color(al_map_rgb(255, 0, 255));
// set target bitmap to the backbuffer which is the display
al_set_target_bitmap(al_get_backbuffer(display));
// create the event queue for checking for events
event_queue = al_create_event_queue();
// if event queue fails to be created return error message and destroy proper assets
if (!event_queue)
{
fprintf(stderr, "failed to create event_queue!\n");
al_destroy_bitmap(bouncer);
al_destroy_display(display);
al_destroy_timer(timer);
return -1;
}
// register the display, timer and keyboard with allegro, has to know about them to keep track of them
al_register_event_source(event_queue, al_get_display_event_source(display));
al_register_event_source(event_queue, al_get_timer_event_source(timer));
al_register_event_source(event_queue, al_get_keyboard_event_source());
// clear color to black
al_clear_to_color(al_map_rgb(0, 0, 0));
// flip the display otherwise your screen will never update
al_flip_display();
// start the timer
al_start_timer(timer);
// game loop
while(!doexit)
{
////////////////////REMOVE THIS dosFile code when done!!!!!!!!!!!! ///////////////////////////////////
// debugging data.......
// pos & pos + size
// "Ball Pos (x, y - x, y) Player 1 Pos (x, y) Player 2 Pos(x, y)"
dosFile << "( " << bouncer_x << ", " << bouncer_y << " - " << bouncer_x + BOUNCER_SIZE << ", " << bouncer_y + BOUNCER_SIZE << " )";
dosFile << " " << "( " << p1Paddle_x << ", " << p1Paddle_y << " - " << p1Paddle_x + PADDLE_SIZE_X << ", " << p1Paddle_y + PADDLE_SIZE_Y << ")";
dosFile << " " << "( " << p2Paddle_x << ", " << p2Paddle_y << " - " << p2Paddle_x + PADDLE_SIZE_X << ", " << p2Paddle_y + PADDLE_SIZE_Y << ")" << endl;
// make allegro event variable
ALLEGRO_EVENT ev;
// wait for an event to happen
al_wait_for_event(event_queue, &ev);
// check to see if you have a timer event
if (ev.type == ALLEGRO_EVENT_TIMER)
{
// if bouncer x goes off screen reset the ball sprite to middle of screen
// increment player 2 score by one and increment misses by one
if (bouncer_x < 0)
{
bouncer_x = SCREEN_W / 2.0 - BOUNCER_SIZE / 2.0;
bouncer_y = SCREEN_H / 2.0 - BOUNCER_SIZE / 2.0;
++p2Score;
misses += 1;
}
// if bouncer x is greater screen reset the ball to middle of screen
// increment player one score (unlikely to happen)
if(bouncer_x + BOUNCER_SIZE > SCREEN_W)
{
bouncer_x = SCREEN_W / 2.0 - BOUNCER_SIZE / 2.0;
bouncer_y = SCREEN_H / 2.0 - BOUNCER_SIZE / 2.0;
p1Score += 1;
}
// if the ball hits the top or bottom of the screen bounce back
if (bouncer_y < 0 || bouncer_y + BOUNCER_SIZE > SCREEN_H)
{
bouncer_dy = -bouncer_dy;
}
// set ball coordinates to the ball movement (make the ball move)
bouncer_x += bouncer_dx;
bouncer_y += bouncer_dy;
p2Paddle_y += pad_dy;
//if bouncer_y+paddle_h/2 >= screen_h then paddle_y=screen_h-bouncer_h/2 else if bouncer_y-paddle_h/2 < 0 then paddle_y = paddle_h/2 else paddle_h = bouncer_y;
if (bouncer_y + PADDLE_SIZE_Y / 2 >= SCREEN_H)
{
p2Paddle_y = SCREEN_H - PADDLE_SIZE_Y / 2;
}
else if(bouncer_y - PADDLE_SIZE_Y / 2 < 0)
{
p2Paddle_y = PADDLE_SIZE_Y / 2;
}
else
{
p2Paddle_y = bouncer_y;
}
// collision detection - player 1 - check if bouncer x is less than or equal to paddle AND bouncer y is within the paddle bounce back
if (bouncer_x <= p1Paddle_x + PADDLE_SIZE_X && (bouncer_y >= p1Paddle_y) && (bouncer_y + BOUNCER_SIZE <= p1Paddle_y + PADDLE_SIZE_Y))
{
bouncer_dx++;
dosFile << "( " << bouncer_x << ", " << bouncer_y << " - " << bouncer_x + BOUNCER_SIZE << ", " << bouncer_y + BOUNCER_SIZE << " )";
dosFile << " " << "( " << p1Paddle_x << ", " << p1Paddle_y << " - " << p1Paddle_x + PADDLE_SIZE_X << ", " << p1Paddle_y + PADDLE_SIZE_Y << ")";
dosFile << " " << "( " << p2Paddle_x << ", " << p2Paddle_y << " - " << p2Paddle_x + PADDLE_SIZE_X << ", " << p2Paddle_y + PADDLE_SIZE_Y << ")" << " XX P1" << endl;
}
// collision detection - player 2 - check if bouncer x is greater paddle 2 AND bouncer inside paddle 2 region bounce back
if(bouncer_x + BOUNCER_SIZE >= p2Paddle_x && (bouncer_y >= p2Paddle_y) && (bouncer_y + BOUNCER_SIZE <= p2Paddle_y + PADDLE_SIZE_Y))
{
bouncer_dx--;
dosFile << right << "( " << bouncer_x << ", " << bouncer_y << " - " << bouncer_x + BOUNCER_SIZE << ", " << bouncer_y + BOUNCER_SIZE << " )";
dosFile << " " << "( " << p1Paddle_x << ", " << p1Paddle_y << " - " << p1Paddle_x + PADDLE_SIZE_X << ", " << p1Paddle_y + PADDLE_SIZE_Y << ")";
dosFile << " " << "( " << p2Paddle_x << ", " << p2Paddle_y << " - " << p2Paddle_x + PADDLE_SIZE_X << ", " << p2Paddle_y + PADDLE_SIZE_Y << ")" << " XX P2" << endl;
}
if(key[KEY_W] && p1Paddle_y > 0 )
{
p1Paddle_y -= pad_dy;
}
if(key[KEY_S] && p1Paddle_y < SCREEN_H - PADDLE_SIZE_Y)
{
p1Paddle_y += pad_dy;
}
if(key[KEY_SPACE])
{
dosFile << right << "( " << bouncer_x << ", " << bouncer_y << " - " << bouncer_x + BOUNCER_SIZE << ", " << bouncer_y + BOUNCER_SIZE << " )";
dosFile << " " << "( " << p1Paddle_x << ", " << p1Paddle_y << " - " << p1Paddle_x + PADDLE_SIZE_X << ", " << p1Paddle_y + PADDLE_SIZE_Y << ")";
dosFile << " " << "( " << p2Paddle_x << ", " << p2Paddle_y << " - " << p2Paddle_x + PADDLE_SIZE_X << ", " << p2Paddle_y + PADDLE_SIZE_Y << ")" << " XX MISS" << endl;
}
redraw = true;
}
else if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
{
break;
}
else if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_W:
key[KEY_W] = true;
break;
case ALLEGRO_KEY_S:
key[KEY_S] = true;
break;
case ALLEGRO_KEY_SPACE:
key[KEY_SPACE] = true;
break;
}
}
else if(ev.type == ALLEGRO_EVENT_KEY_UP)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_W:
key[KEY_W] = false;
break;
case ALLEGRO_KEY_S:
key[KEY_S] = false;
break;
case ALLEGRO_KEY_SPACE:
key[KEY_SPACE] = false;
break;
case ALLEGRO_KEY_ESCAPE:
doexit = true;
break;
}
}
if (redraw && al_is_event_queue_empty(event_queue))
{
redraw = false;
al_clear_to_color(al_map_rgb(0, 0, 0));
al_draw_textf(font_bitmap, al_map_rgb(255, 255, 255), 30, 15, 0, "%d", p1Score);
al_draw_textf(font_bitmap, al_map_rgb(255, 255, 255), 550, 15, 0, "%d", p2Score);
al_draw_bitmap(p1Paddle, p1Paddle_x, p1Paddle_y, 0);
al_draw_bitmap(p2Paddle, p2Paddle_x, p2Paddle_y - PADDLE_SIZE_Y / 2, 0);
al_draw_bitmap(bouncer, bouncer_x, bouncer_y, 0);
if (misses == 5)
{
al_draw_text(font_bitmap, al_map_rgb(255, 0, 0),30, SCREEN_H / 2, 0, "TOO MANY MISSES!!!");
al_draw_text(font_bitmap, al_map_rgb(255, 0, 0), 64, (SCREEN_H / 2) + 40, 0, "PLAYER 2WINS!");
al_flip_display();
al_rest(10.0);
doexit = true;
}
al_flip_display();
}
}
al_destroy_bitmap(bouncer);
al_destroy_bitmap(p1Paddle);
al_destroy_bitmap(p2Paddle);
al_destroy_timer(timer);
al_destroy_display(display);
al_destroy_event_queue(event_queue);
dosFile.close();
return 0;
}