home *** CD-ROM | disk | FTP | other *** search
/ Game Programming - All in One (3rd Edition) / game_prog_all_in_one_3rd_ed.iso / sources / chapter07 / tankwar_r2 / main.c next >
Encoding:
C/C++ Source or Header  |  2006-09-13  |  15.4 KB  |  556 lines

  1. /////////////////////////////////////////////////////////////////////////
  2. // Game Programming All In One, Third Edition
  3. // Chapter 7 - Tank War Game (Enhancement 2)
  4. /////////////////////////////////////////////////////////////////////////
  5.  
  6. #include "tankwar.h"
  7.  
  8. /////////////////////////////////////////////////////////////////////////
  9. // drawtank function
  10. // construct the tank using drawing functions
  11. /////////////////////////////////////////////////////////////////////////
  12. void drawtank(int num)
  13. {
  14.     int x = 15; //tanks[num].x;
  15.     int y = 15; //tanks[num].y;
  16.     int dir = tanks[num].dir;
  17.     
  18.     //draw tank body and turret
  19.     rectfill(tank_bmp[num][dir], x-11, y-11, x+11, y+11, tanks[num].color);
  20.     rectfill(tank_bmp[num][dir], x-6, y-6, x+6, y+6, 7);
  21.     
  22.     //draw the treads based on orientation
  23.     if (dir == 0 || dir == 2)
  24.     {
  25.         rectfill(tank_bmp[num][dir], x-16, y-16, x-11, y+16, 8);
  26.         rectfill(tank_bmp[num][dir], x+11, y-16, x+16, y+16, 8);
  27.     }
  28.     else
  29.     if (dir == 1 || dir == 3)
  30.     {
  31.         rectfill(tank_bmp[num][dir], x-16, y-16, x+16, y-11, 8);
  32.         rectfill(tank_bmp[num][dir], x-16, y+16, x+16, y+11, 8);
  33.     }
  34.     
  35.     //draw the turret based on direction
  36.     switch (dir)
  37.     {
  38.         case 0:
  39.             rectfill(tank_bmp[num][dir], x-1, y, x+1, y-16, 8);
  40.             break;
  41.         case 1:
  42.             rectfill(tank_bmp[num][dir], x, y-1, x+16, y+1, 8);
  43.             break;
  44.         case 2:
  45.             rectfill(tank_bmp[num][dir], x-1, y, x+1, y+16, 8);
  46.             break;
  47.         case 3:
  48.             rectfill(tank_bmp[num][dir], x, y-1, x-16, y+1, 8);
  49.             break;
  50.     }    
  51. }
  52.  
  53. /////////////////////////////////////////////////////////////////////////
  54. // erasetank function
  55. // erase the tank using rectfill
  56. /////////////////////////////////////////////////////////////////////////
  57. void erasetank(int num)
  58. {
  59.     //calculate box to encompass the tank
  60.     int left = tanks[num].x - 17;
  61.     int top = tanks[num].y - 17;
  62.     int right = tanks[num].x + 17;
  63.     int bottom = tanks[num].y + 17;
  64.  
  65.     //erase the tank
  66.     rectfill(screen, left, top, right, bottom, 0);
  67. }
  68.  
  69. /////////////////////////////////////////////////////////////////////////
  70. // movetank function
  71. // move the tank in the current direction
  72. /////////////////////////////////////////////////////////////////////////
  73. void movetank(int num)
  74. {
  75.     int dir = tanks[num].dir;
  76.     int speed = tanks[num].speed;
  77.  
  78.     //update tank position based on direction
  79.     switch(dir)
  80.     {
  81.         case 0:
  82.             tanks[num].y -= speed;
  83.             break;
  84.         case 1:
  85.             tanks[num].x += speed;
  86.             break;
  87.         case 2:
  88.             tanks[num].y += speed;
  89.             break;
  90.         case 3:
  91.             tanks[num].x -= speed;
  92.     }
  93.  
  94.     //keep tank inside the screen
  95.     if (tanks[num].x > SCREEN_W-22)
  96.     {
  97.         tanks[num].x = SCREEN_W-22;
  98.         tanks[num].speed = 0;
  99.     }
  100.     if (tanks[num].x < 22)
  101.     {
  102.         tanks[num].x = 22;
  103.         tanks[num].speed = 0;
  104.     }
  105.     if (tanks[num].y > SCREEN_H-22)
  106.     {
  107.         tanks[num].y = SCREEN_H-22;
  108.         tanks[num].speed = 0;
  109.     }
  110.     if (tanks[num].y < 22)
  111.     {
  112.         tanks[num].y = 22;
  113.         tanks[num].speed = 0;
  114.     }
  115. }
  116.  
  117. /////////////////////////////////////////////////////////////////////////
  118. // explode function
  119. // display random boxes to simulate an explosion
  120. /////////////////////////////////////////////////////////////////////////
  121. void explode(int num, int x, int y)
  122. {
  123.  
  124.     int n;
  125.  
  126.     //retrieve location of enemy tank
  127.     int tx = tanks[!num].x;
  128.     int ty = tanks[!num].y;
  129.     
  130.     //is bullet inside the boundary of the enemy tank?
  131.     if (x > tx-16 && x < tx+16 && y > ty-16 && y < ty+16)
  132.         score(num);
  133.  
  134.     //draw some random circles for the "explosion"
  135.     for (n = 0; n < 10; n++)
  136.     {
  137.         rectfill(screen, x-16, y-16, x+16, y+16, rand() % 16);
  138.         rest(1);
  139.     }
  140.  
  141.     //clear the area of debris
  142.     rectfill(screen, x-16, y-16, x+16, y+16, 0);
  143.    
  144. }
  145.  
  146. /////////////////////////////////////////////////////////////////////////
  147. // updatebullet function
  148. // update the position of a bullet
  149. /////////////////////////////////////////////////////////////////////////
  150. void updatebullet(int num)
  151. {
  152.     int x = bullets[num].x;
  153.     int y = bullets[num].y;
  154.  
  155.     if (bullets[num].alive)
  156.     {
  157.         //erase bullet
  158.         rect(screen, x-1, y-1, x+1, y+1, 0);        
  159.  
  160.         //move bullet
  161.         bullets[num].x += bullets[num].xspd;
  162.         bullets[num].y += bullets[num].yspd;
  163.         x = bullets[num].x;
  164.         y = bullets[num].y;
  165.  
  166.         //stay within the screen
  167.         if (x < 5 || x > SCREEN_W-5 || y < 20 || y > SCREEN_H-5)
  168.         {
  169.             bullets[num].alive = 0;
  170.             return;
  171.         }
  172.  
  173.         //draw bullet
  174.         x = bullets[num].x;
  175.         y = bullets[num].y;
  176.         rect(screen, x-1, y-1, x+1, y+1, 14);        
  177.  
  178.         //look for a hit
  179.         if (getpixel(screen, bullets[num].x, bullets[num].y))
  180.         {
  181.             bullets[num].alive = 0;
  182.             explode(num, x, y);
  183.         }
  184.  
  185.         //print the bullet's position
  186.         textprintf_ex(screen, font, SCREEN_W/2-50, 1, 2, 0,
  187.             "B1 %-3dx%-3d  B2 %-3dx%-3d", 
  188.             bullets[0].x, bullets[0].y, 
  189.             bullets[1].x, bullets[1].y);
  190.  
  191.     }
  192. }
  193.  
  194. /////////////////////////////////////////////////////////////////////////
  195. // checkpath function
  196. // check to see if a point on the screen is black
  197. /////////////////////////////////////////////////////////////////////////
  198. int checkpath(int x1,int y1,int x2,int y2,int x3,int y3)
  199. {
  200.     if (getpixel(screen, x1, y1) || 
  201.         getpixel(screen, x2, y2) ||
  202.         getpixel(screen, x3, y3))
  203.         return 1;
  204.     else
  205.         return 0;
  206. }
  207.  
  208. /////////////////////////////////////////////////////////////////////////
  209. // clearpath function
  210. // verify that the tank can move in the current direction
  211. /////////////////////////////////////////////////////////////////////////
  212. void clearpath(int num)
  213. {
  214.     //shortcut vars
  215.     int dir = tanks[num].dir;
  216.     int speed = tanks[num].speed;
  217.     int x = tanks[num].x;
  218.     int y = tanks[num].y;
  219.     
  220.     switch(dir)
  221.     {
  222.         //check pixels north
  223.         case 0:
  224.             if (speed > 0)
  225.             {
  226.                 if (checkpath(x-16, y-20, x, y-20, x+16, y-20))
  227.                     tanks[num].speed = 0;
  228.             }
  229.             else
  230.                 //if reverse dir, check south
  231.                 if (checkpath(x-16, y+20, x, y+20, x+16, y+20))
  232.                     tanks[num].speed = 0;
  233.             break;
  234.             
  235.         //check pixels east
  236.         case 1:
  237.             if (speed > 0)
  238.             {
  239.                 if (checkpath(x+20, y-16, x+20, y, x+20, y+16))
  240.                     tanks[num].speed = 0;
  241.             }
  242.             else
  243.                 //if reverse dir, check west
  244.                 if (checkpath(x-20, y-16, x-20, y, x-20, y+16))
  245.                     tanks[num].speed = 0;
  246.             break;
  247.             
  248.         //check pixels south
  249.         case 2:
  250.             if (speed > 0)
  251.             {
  252.                 if (checkpath(x-16, y+20, x, y+20, x+16, y+20 ))
  253.                     tanks[num].speed = 0;
  254.             }
  255.             else
  256.                 //if reverse dir, check north
  257.                 if (checkpath(x-16, y-20, x, y-20, x+16, y-20))
  258.                     tanks[num].speed = 0;
  259.             break;
  260.             
  261.         //check pixels west
  262.         case 3:
  263.             if (speed > 0)
  264.             {
  265.                 if (checkpath(x-20, y-16, x-20, y, x-20, y+16))
  266.                     tanks[num].speed = 0;
  267.             }
  268.             else
  269.                 //if reverse dir, check east
  270.                 if (checkpath(x+20, y-16, x+20, y, x+20, y+16))
  271.                     tanks[num].speed = 0;
  272.             break;
  273.     }
  274. }
  275.  
  276. /////////////////////////////////////////////////////////////////////////
  277. // fireweapon function
  278. // configure a bullet's direction and speed and activate it
  279. /////////////////////////////////////////////////////////////////////////
  280. void fireweapon(int num)
  281. {
  282.     int x = tanks[num].x;
  283.     int y = tanks[num].y;
  284.  
  285.     //ready to fire again?
  286.     if (!bullets[num].alive)
  287.     {
  288.         bullets[num].alive = 1;
  289.  
  290.         //fire bullet in direction tank is facing
  291.         switch (tanks[num].dir)
  292.         {
  293.             //north
  294.             case 0:
  295.                 bullets[num].x = x;
  296.                 bullets[num].y = y-22;
  297.                 bullets[num].xspd = 0;
  298.                 bullets[num].yspd = -BULLETSPEED;
  299.                 break;
  300.             //east
  301.             case 1:
  302.                 bullets[num].x = x+22;
  303.                 bullets[num].y = y;
  304.                 bullets[num].xspd = BULLETSPEED;
  305.                 bullets[num].yspd = 0;
  306.                 break;
  307.             //south
  308.             case 2:
  309.                 bullets[num].x = x;
  310.                 bullets[num].y = y+22;
  311.                 bullets[num].xspd = 0;
  312.                 bullets[num].yspd = BULLETSPEED;
  313.                 break;
  314.             //west
  315.             case 3:
  316.                 bullets[num].x = x-22;
  317.                 bullets[num].y = y;
  318.                 bullets[num].xspd = -BULLETSPEED;
  319.                 bullets[num].yspd = 0;
  320.         }
  321.     }
  322. }
  323.  
  324. /////////////////////////////////////////////////////////////////////////
  325. // forward function
  326. // increase the tank's speed
  327. /////////////////////////////////////////////////////////////////////////
  328. void forward(int num)
  329. {
  330.     tanks[num].speed++;
  331.     if (tanks[num].speed > MAXSPEED)
  332.         tanks[num].speed = MAXSPEED;
  333. }
  334.  
  335. /////////////////////////////////////////////////////////////////////////
  336. // backward function
  337. // decrease the tank's speed
  338. /////////////////////////////////////////////////////////////////////////
  339. void backward(int num)
  340. {
  341.     tanks[num].speed--;
  342.     if (tanks[num].speed < -MAXSPEED)
  343.         tanks[num].speed = -MAXSPEED;
  344. }
  345.  
  346. /////////////////////////////////////////////////////////////////////////
  347. // turnleft function
  348. // rotate the tank counter-clockwise
  349. /////////////////////////////////////////////////////////////////////////
  350. void turnleft(int num)
  351. {
  352.     tanks[num].dir--;
  353.     if (tanks[num].dir < 0)
  354.         tanks[num].dir = 3;
  355. }
  356.  
  357. /////////////////////////////////////////////////////////////////////////
  358. // turnright function
  359. // rotate the tank clockwise
  360. /////////////////////////////////////////////////////////////////////////
  361. void turnright(int num)
  362. {
  363.     tanks[num].dir++;
  364.     if (tanks[num].dir > 3)
  365.         tanks[num].dir = 0;
  366. }
  367.  
  368. /////////////////////////////////////////////////////////////////////////
  369. // getinput function
  370. // check for player input keys (2 player support)
  371. /////////////////////////////////////////////////////////////////////////
  372. void getinput()
  373. {
  374.     //hit ESC to quit
  375.     if (key[KEY_ESC])
  376.         gameover = 1;
  377.     
  378.     //WASD / SPACE keys control tank 1
  379.     if (key[KEY_W])
  380.         forward(0);
  381.     if (key[KEY_D])
  382.         turnright(0);
  383.     if (key[KEY_A])
  384.         turnleft(0);
  385.     if (key[KEY_S])
  386.         backward(0);
  387.     if (key[KEY_SPACE])
  388.         fireweapon(0);
  389.             
  390.     //arrow / ENTER keys control tank 2
  391.     if (key[KEY_UP]) 
  392.         forward(1);
  393.     if (key[KEY_RIGHT])
  394.         turnright(1);
  395.     if (key[KEY_DOWN])
  396.         backward(1);
  397.     if (key[KEY_LEFT])
  398.         turnleft(1);
  399.     if (key[KEY_ENTER])
  400.         fireweapon(1);
  401.  
  402.     //short delay after keypress        
  403.     rest(20);
  404. }
  405.  
  406. /////////////////////////////////////////////////////////////////////////
  407. // score function
  408. // add a point to the specified player's score
  409. /////////////////////////////////////////////////////////////////////////
  410. void score(int player)
  411. {
  412.     //update score
  413.     int points = ++tanks[player].score;
  414.  
  415.     //display score
  416.     textprintf_ex(screen, font, SCREEN_W-70*(player+1), 1, BURST, 0,
  417.         "P%d: %d", player+1, points);
  418. }
  419.  
  420. /////////////////////////////////////////////////////////////////////////
  421. // setuptanks function
  422. // set up the starting condition of each tank
  423. /////////////////////////////////////////////////////////////////////////
  424. void setuptanks()
  425. {
  426.     int n;
  427.     
  428.     //player 1
  429.     tanks[0].x = 30;
  430.     tanks[0].y = 40;
  431.     tanks[0].speed = 0;
  432.     tanks[0].color = 9;
  433.     tanks[0].score = 0;
  434.     for (n=0; n<4; n++)
  435.     {
  436.         tank_bmp[0][n] = create_bitmap(32, 32); 
  437.         clear_bitmap(tank_bmp[0][n]);
  438.         tanks[0].dir = n;
  439.         drawtank(0);
  440.     }
  441.     tanks[0].dir = 1;
  442.  
  443.     //player 2
  444.     tanks[1].x = SCREEN_W-30;
  445.     tanks[1].y = SCREEN_H-30;
  446.     tanks[1].dir = 3;
  447.     tanks[1].speed = 0;
  448.     tanks[1].color = 12;
  449.     tanks[1].score = 0;
  450.     for (n=0; n<4; n++)
  451.     {
  452.         tank_bmp[1][n] = create_bitmap(32, 32); 
  453.         clear_bitmap(tank_bmp[1][n]);
  454.         tanks[1].dir = n;
  455.         drawtank(1);
  456.     }
  457. }
  458.  
  459. /////////////////////////////////////////////////////////////////////////
  460. // setupdebris function
  461. // set up the debris on the battlefield
  462. /////////////////////////////////////////////////////////////////////////
  463. void setupdebris()
  464. {
  465.     int n,x,y,size,color;
  466.  
  467.     //fill the battlefield with random debris
  468.     for (n = 0; n < BLOCKS; n++)
  469.     {
  470.         x = BLOCKSIZE + rand() % (SCREEN_W-BLOCKSIZE*2);
  471.         y = BLOCKSIZE + rand() % (SCREEN_H-BLOCKSIZE*2);
  472.         size = (10 + rand() % BLOCKSIZE)/2;
  473.         color = makecol(rand()%255, rand()%255, rand()%255);
  474.         rectfill(screen, x-size, y-size, x+size, y+size, color);
  475.     }
  476.  
  477. }
  478.  
  479. /////////////////////////////////////////////////////////////////////////
  480. // setupscreen function
  481. // set up the graphics mode and game screen
  482. /////////////////////////////////////////////////////////////////////////
  483. void setupscreen()
  484. {
  485.     //set video mode    
  486.     int ret = set_gfx_mode(MODE, WIDTH, HEIGHT, 0, 0);
  487.     if (ret != 0) {
  488.         allegro_message(allegro_error);
  489.         return;
  490.     }
  491.  
  492.     //print title
  493.     textprintf_ex(screen, font, 1, 1, BURST, 0,
  494.         "Tank War - %dx%d", SCREEN_W, SCREEN_H);
  495.  
  496.     //draw screen border        
  497.     rect(screen, 0, 12, SCREEN_W-1, SCREEN_H-1, TAN);
  498.     rect(screen, 1, 13, SCREEN_W-2, SCREEN_H-2, TAN);
  499.    
  500. }
  501.  
  502. /////////////////////////////////////////////////////////////////////////
  503. // main function
  504. // start point of the program
  505. /////////////////////////////////////////////////////////////////////////
  506. int main(void)
  507. {
  508.     //initialize everything
  509.     allegro_init(); 
  510.     install_keyboard(); 
  511.     install_timer();
  512.     srand(time(NULL));
  513.     setupscreen();
  514.     setupdebris();
  515.     setuptanks();
  516.  
  517.     //game loop
  518.     while(!gameover)
  519.     {
  520.         //erase the tanks
  521.         erasetank(0);
  522.         erasetank(1);
  523.         
  524.         //check for collisions
  525.         clearpath(0);
  526.         clearpath(1);
  527.         
  528.         //move the tanks
  529.         movetank(0);
  530.         movetank(1);
  531.         
  532.         //draw the tanks
  533.         blit(tank_bmp[0][tanks[0].dir], screen, 0, 0, 
  534.             tanks[0].x-16, tanks[0].y-16, 32, 32);
  535.         blit(tank_bmp[1][tanks[1].dir], screen, 0, 0, 
  536.             tanks[1].x-16, tanks[1].y-16, 32, 32);
  537.  
  538.         //update the bullets
  539.         updatebullet(0);
  540.         updatebullet(1);
  541.         
  542.         //check for keypresses
  543.         if (keypressed())
  544.             getinput();
  545.  
  546.         //slow the game down (adjust as necessary)
  547.         rest(30);
  548.     }
  549.  
  550.     //end program
  551.     allegro_exit();
  552.     return 0;
  553. }
  554. END_OF_MAIN()
  555.  
  556.