1. //////////////////////// HEADERS /////////////////
  2.  
  3. #include <iostream>
  4. #include <iomanip>
  5. #include <cstdio>
  6. #include <cstdlib>
  7. #include <ctime>
  8. #include <fstream>
  9. #include <allegro5/allegro.h>
  10. #include <allegro5/allegro_font.h>
  11. #include <allegro5/allegro_image.h>
  12.  
  13. using namespace std;
  14.  
  15. /////////// GLOBAL VARIABLES //////////////////////////////////
  16. const float FPS = 60;
  17. const int SCREEN_W = 640;
  18. const int SCREEN_H = 480;
  19. const int BOUNCER_SIZE = 32;
  20. const int PADDLE_SIZE_X = 15;
  21. const int PADDLE_SIZE_Y = 160;
  22. const double SPEED = 2.0;
  23. const double PADSPEED = 2.0;
  24. enum MYKEYS{KEY_W, KEY_S, KEY_SPACE};
  25.  
  26. /////////////////// MAIN --- PROGRAM ENTRY /////////////////////////////////////////////////
  27. int main(int argc, char **argv)
  28. {
  29.     /////////////////////////// LOCAL VARIABLES ///////////////////////////////////////////////////
  30.     ALLEGRO_DISPLAY *display = NULL;
  31.     ALLEGRO_EVENT_QUEUE *event_queue = NULL;
  32.     ALLEGRO_TIMER *timer = NULL;
  33.     ALLEGRO_BITMAP *bouncer = NULL;
  34.     ALLEGRO_BITMAP *p1Paddle = NULL;
  35.     ALLEGRO_BITMAP *p2Paddle = NULL;
  36.     ALLEGRO_FONT *font_bitmap = NULL;
  37.     int p1Score = 0, p2Score = 0, misses = 0;
  38.     float bouncer_x = SCREEN_W / 2.0 - BOUNCER_SIZE / 2.0;
  39.     float bouncer_y = SCREEN_H / 2.0 - BOUNCER_SIZE / 2.0;
  40.     float p1Paddle_x = 10;
  41.     float p1Paddle_y = SCREEN_H /  2.0 - PADDLE_SIZE_Y / 2.0;
  42.     float p2Paddle_x = SCREEN_W - 10 - PADDLE_SIZE_X;
  43.     float p2Paddle_y = SCREEN_H /  2.0 - PADDLE_SIZE_Y / 2.0;
  44.     float bouncer_dx = -SPEED, bouncer_dy = SPEED;
  45.     float pad_dy = PADSPEED;
  46.     bool key[3] = {false, false, false};
  47.     bool doexit = false;
  48.     bool redraw = true;
  49.  
  50.     ///////////////////////////////////////////////////////////////////////////////////
  51.     ///////////////////////////////////////////////////////////////////////////////////
  52.     // REMEMBER TO REMOVE THIS ONCE DONE!!!!!!!!!!!
  53.     // Debugging output file
  54.     ofstream dosFile;
  55.     dosFile.open("debug/pongDebug.txt");
  56.     dosFile << "Ball Pos (x, y)            Player 1 Pos (x, y)                Player 2 Pos(x, y)" << endl;
  57.    
  58.     // intialize allegro , if it fails return error message
  59.     if (!al_init())
  60.     {
  61.         fprintf(stderr, "failed to initialize allegro!\n");
  62.         return -1;
  63.     }
  64.     // initialize image and font addons
  65.     al_init_image_addon();
  66.     al_init_font_addon();
  67.    
  68.     // install the keyboard, if it fails return error message
  69.     if(!al_install_keyboard())
  70.     {
  71.         fprintf(stderr, "failed to initialize the keyboard!\n");
  72.         return -1;
  73.     }
  74.     // create timer
  75.     timer = al_create_timer(1.0 / FPS);
  76.     // if timer fails to create, return error message
  77.     if (!timer)
  78.     {
  79.         fprintf(stderr, "failed to create timer!\n");
  80.         return -1;
  81.     }
  82.     // create display
  83.     display = al_create_display(SCREEN_W, SCREEN_H);
  84.     // if display fails to create, return error message
  85.     if (!display)
  86.     {
  87.         fprintf(stderr, "failed to create display!\n");
  88.         return -1;
  89.     }
  90.    
  91.     // create bouncer bitmap
  92.     bouncer = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE);
  93.     // if it fails then return error and destroy the display bitmap and timer
  94.     if (!bouncer)
  95.     {
  96.         fprintf(stderr, "failed to create bouncer bitmap!\n");
  97.         al_destroy_display(display);
  98.         al_destroy_timer(timer);
  99.         return -1;
  100.     }
  101.    
  102.     // create bitmap for paddle
  103.     p1Paddle = al_create_bitmap(PADDLE_SIZE_X, PADDLE_SIZE_Y);
  104.     // if creating paddle fails return error message
  105.     if (!p1Paddle)
  106.     {
  107.         fprintf(stderr, "failed to create player one paddle bitmap!\n");
  108.         al_destroy_display(display);
  109.         al_destroy_timer(timer);
  110.         return -1;
  111.     }
  112.     // create bitmap for paddle 2
  113.     p2Paddle = al_create_bitmap(PADDLE_SIZE_X, PADDLE_SIZE_Y);
  114.     // if creating paddle fails return error message
  115.     if (!p2Paddle)
  116.     {
  117.         fprintf(stderr, "failed to create player two paddle bitmap!\n");
  118.         al_destroy_display(display);
  119.         al_destroy_timer(timer);
  120.         return -1;
  121.     }
  122.     // create and load the font used
  123.     font_bitmap = al_load_font("data/bmpfont.tga",  0, 0);
  124.     // if create/load fails return error message
  125.     if(!font_bitmap)
  126.     {
  127.         fprintf(stderr, "failed to create font!\n");
  128.         return -1;
  129.     }
  130.     // set players paddle image
  131.     al_set_target_bitmap(p1Paddle);
  132.     // set paddle to color
  133.     al_clear_to_color(al_map_rgb(0, 191, 255));
  134.     // set player 2 paddle
  135.     al_set_target_bitmap(p2Paddle);
  136.     // set player 2 paddle to color
  137.     al_clear_to_color(al_map_rgb(0, 255, 191));
  138.     // set bouncer sprite
  139.     al_set_target_bitmap(bouncer);
  140.     // set ball/bouncer sprite to color
  141.     al_clear_to_color(al_map_rgb(255, 0, 255));
  142.     // set target bitmap to the backbuffer which is the display
  143.     al_set_target_bitmap(al_get_backbuffer(display));
  144.     // create the event queue for checking for events
  145.     event_queue = al_create_event_queue();
  146.     // if event queue fails to be created return error message and destroy proper assets
  147.     if (!event_queue)
  148.     {
  149.         fprintf(stderr, "failed to create event_queue!\n");
  150.         al_destroy_bitmap(bouncer);
  151.         al_destroy_display(display);
  152.         al_destroy_timer(timer);
  153.         return -1;
  154.     }
  155.     // register the display, timer and keyboard with allegro, has to know about them to keep track of them
  156.     al_register_event_source(event_queue, al_get_display_event_source(display));
  157.     al_register_event_source(event_queue, al_get_timer_event_source(timer));
  158.     al_register_event_source(event_queue, al_get_keyboard_event_source());
  159.     // clear color to black
  160.     al_clear_to_color(al_map_rgb(0, 0, 0));
  161.     // flip the display otherwise your screen will never update
  162.     al_flip_display();
  163.     // start the timer
  164.     al_start_timer(timer);
  165.     // game loop
  166.     while(!doexit)
  167.     {
  168.         ////////////////////REMOVE THIS dosFile code when done!!!!!!!!!!!! ///////////////////////////////////
  169.         // debugging data.......
  170.         // pos & pos + size
  171.         // "Ball Pos (x, y - x, y)   Player 1 Pos (x, y)    Player 2 Pos(x, y)"
  172.         dosFile << "( " << bouncer_x << ", " << bouncer_y << " - " << bouncer_x + BOUNCER_SIZE << ", " << bouncer_y + BOUNCER_SIZE << " )";
  173.         dosFile << "      " << "( " << p1Paddle_x << ", " << p1Paddle_y << " - " << p1Paddle_x + PADDLE_SIZE_X << ", " << p1Paddle_y + PADDLE_SIZE_Y << ")";
  174.         dosFile << "      " << "( " << p2Paddle_x << ", " << p2Paddle_y << " - " << p2Paddle_x + PADDLE_SIZE_X << ", " << p2Paddle_y + PADDLE_SIZE_Y << ")" << endl;
  175.         // make allegro event variable
  176.         ALLEGRO_EVENT ev;
  177.         // wait for an event to happen
  178.         al_wait_for_event(event_queue, &ev);
  179.         // check to see if you have a timer event
  180.         if (ev.type == ALLEGRO_EVENT_TIMER)
  181.         {
  182.             // if bouncer x goes off screen reset the ball sprite to middle of screen
  183.             // increment player 2 score by one and increment misses by one
  184.             if (bouncer_x < 0)
  185.             {
  186.                 bouncer_x = SCREEN_W / 2.0 - BOUNCER_SIZE / 2.0;
  187.                 bouncer_y = SCREEN_H / 2.0 - BOUNCER_SIZE / 2.0;
  188.                 ++p2Score;
  189.                 misses += 1;
  190.             }
  191.             // if bouncer x is greater screen reset the ball to middle of screen
  192.             // increment player one score (unlikely to happen)
  193.             if(bouncer_x + BOUNCER_SIZE > SCREEN_W)
  194.             {
  195.                 bouncer_x = SCREEN_W / 2.0 - BOUNCER_SIZE / 2.0;
  196.                 bouncer_y = SCREEN_H / 2.0 - BOUNCER_SIZE / 2.0;
  197.                 p1Score += 1;
  198.             }
  199.             // if the ball hits the top or bottom of the screen bounce back
  200.             if (bouncer_y < 0 || bouncer_y + BOUNCER_SIZE > SCREEN_H)
  201.             {
  202.                 bouncer_dy = -bouncer_dy;
  203.             }
  204.             // set ball coordinates to the ball movement (make the ball move)
  205.             bouncer_x += bouncer_dx;
  206.             bouncer_y += bouncer_dy;
  207.             p2Paddle_y += pad_dy;
  208.            
  209.             //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;
  210.             if (bouncer_y + PADDLE_SIZE_Y / 2 >= SCREEN_H)
  211.             {
  212.                 p2Paddle_y = SCREEN_H - PADDLE_SIZE_Y / 2;
  213.             }
  214.             else if(bouncer_y - PADDLE_SIZE_Y / 2 < 0)
  215.             {
  216.                 p2Paddle_y = PADDLE_SIZE_Y / 2;
  217.             }
  218.             else
  219.             {
  220.                 p2Paddle_y = bouncer_y;
  221.             }
  222.             // collision detection - player 1 - check if bouncer x is less than or equal to paddle  AND bouncer y is within the paddle bounce back
  223.             if (bouncer_x <= p1Paddle_x + PADDLE_SIZE_X && (bouncer_y >= p1Paddle_y) && (bouncer_y + BOUNCER_SIZE <= p1Paddle_y + PADDLE_SIZE_Y))
  224.             {
  225.                     bouncer_dx++;
  226.                     dosFile << "( " << bouncer_x << ", " << bouncer_y << " - " << bouncer_x + BOUNCER_SIZE << ", " << bouncer_y + BOUNCER_SIZE << " )";
  227.                     dosFile << "      " << "( " << p1Paddle_x << ", " << p1Paddle_y << " - " << p1Paddle_x + PADDLE_SIZE_X << ", " << p1Paddle_y + PADDLE_SIZE_Y << ")";
  228.                     dosFile << "      " << "( " << p2Paddle_x << ", " << p2Paddle_y << " - " << p2Paddle_x + PADDLE_SIZE_X << ", " << p2Paddle_y + PADDLE_SIZE_Y << ")" << " XX P1" << endl;
  229.             }
  230.            
  231.             // collision detection - player 2 - check if bouncer x is greater paddle 2 AND bouncer inside paddle  2 region bounce back
  232.             if(bouncer_x + BOUNCER_SIZE >= p2Paddle_x && (bouncer_y >= p2Paddle_y) && (bouncer_y + BOUNCER_SIZE <= p2Paddle_y + PADDLE_SIZE_Y))
  233.             {
  234.                     bouncer_dx--;              
  235.                     dosFile << right << "( " << bouncer_x << ", " << bouncer_y << " - " << bouncer_x + BOUNCER_SIZE << ", " << bouncer_y + BOUNCER_SIZE << " )";
  236.                     dosFile << "      " << "( " << p1Paddle_x << ", " << p1Paddle_y << " - " << p1Paddle_x + PADDLE_SIZE_X << ", " << p1Paddle_y + PADDLE_SIZE_Y << ")";
  237.                     dosFile << "      " << "( " << p2Paddle_x << ", " << p2Paddle_y << " - " << p2Paddle_x + PADDLE_SIZE_X << ", " << p2Paddle_y + PADDLE_SIZE_Y << ")" << " XX P2" << endl;
  238.             }
  239.            
  240.             if(key[KEY_W] && p1Paddle_y > 0 )
  241.             {
  242.                 p1Paddle_y -= pad_dy;
  243.             }
  244.  
  245.             if(key[KEY_S] && p1Paddle_y < SCREEN_H - PADDLE_SIZE_Y)
  246.             {
  247.                 p1Paddle_y += pad_dy;
  248.             }
  249.            
  250.             if(key[KEY_SPACE])
  251.             {
  252.                 dosFile << right << "( " << bouncer_x << ", " << bouncer_y << " - " << bouncer_x + BOUNCER_SIZE << ", " << bouncer_y + BOUNCER_SIZE << " )";
  253.                 dosFile << "      " << "( " << p1Paddle_x << ", " << p1Paddle_y << " - " << p1Paddle_x + PADDLE_SIZE_X << ", " << p1Paddle_y + PADDLE_SIZE_Y << ")";
  254.                 dosFile << "      " << "( " << p2Paddle_x << ", " << p2Paddle_y << " - " << p2Paddle_x + PADDLE_SIZE_X << ", " << p2Paddle_y + PADDLE_SIZE_Y << ")" << " XX MISS" << endl;
  255.             }
  256.  
  257.             redraw = true;
  258.         }
  259.         else if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
  260.         {
  261.             break;
  262.         }
  263.         else if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
  264.         {
  265.             switch(ev.keyboard.keycode)
  266.             {
  267.                 case ALLEGRO_KEY_W:
  268.                     key[KEY_W] = true;
  269.                     break;
  270.                 case ALLEGRO_KEY_S:
  271.                     key[KEY_S] = true;
  272.                     break;
  273.                 case ALLEGRO_KEY_SPACE:
  274.                     key[KEY_SPACE] = true;
  275.                     break;
  276.             }
  277.         }
  278.         else if(ev.type == ALLEGRO_EVENT_KEY_UP)
  279.         {
  280.             switch(ev.keyboard.keycode)
  281.             {
  282.                 case ALLEGRO_KEY_W:
  283.                     key[KEY_W] = false;
  284.                     break;
  285.                 case ALLEGRO_KEY_S:
  286.                     key[KEY_S] = false;
  287.                     break;
  288.                 case ALLEGRO_KEY_SPACE:
  289.                     key[KEY_SPACE]  = false;
  290.                     break;
  291.                 case ALLEGRO_KEY_ESCAPE:
  292.                     doexit = true;
  293.                     break;
  294.             }
  295.         }
  296.        
  297.        
  298.  
  299.         if (redraw && al_is_event_queue_empty(event_queue))
  300.         {
  301.             redraw = false;
  302.             al_clear_to_color(al_map_rgb(0, 0, 0));
  303.             al_draw_textf(font_bitmap, al_map_rgb(255, 255, 255), 30, 15, 0, "%d", p1Score);
  304.             al_draw_textf(font_bitmap, al_map_rgb(255, 255, 255), 550, 15, 0, "%d", p2Score);
  305.             al_draw_bitmap(p1Paddle, p1Paddle_x, p1Paddle_y, 0);
  306.             al_draw_bitmap(p2Paddle, p2Paddle_x, p2Paddle_y - PADDLE_SIZE_Y / 2, 0);
  307.             al_draw_bitmap(bouncer, bouncer_x, bouncer_y, 0);
  308.             if (misses == 5)
  309.             {
  310.                 al_draw_text(font_bitmap, al_map_rgb(255, 0, 0),30, SCREEN_H / 2, 0, "TOO MANY MISSES!!!");
  311.                 al_draw_text(font_bitmap, al_map_rgb(255, 0, 0), 64, (SCREEN_H / 2) + 40, 0, "PLAYER 2WINS!");
  312.                 al_flip_display();
  313.                 al_rest(10.0);
  314.                 doexit = true;
  315.            
  316.             }
  317.             al_flip_display();
  318.         }
  319.     }
  320.  
  321.     al_destroy_bitmap(bouncer);
  322.     al_destroy_bitmap(p1Paddle);
  323.     al_destroy_bitmap(p2Paddle);
  324.     al_destroy_timer(timer);
  325.     al_destroy_display(display);
  326.     al_destroy_event_queue(event_queue);
  327.  
  328.     dosFile.close();
  329.  
  330.     return 0;
  331. }
  332.  
  333.