home *** CD-ROM | disk | FTP | other *** search
/ Media Share 13 / mediashare_13.zip / mediashare_13 / ZIPPED / PROGRAM / WTJ9403.ZIP / BARNHART / SO_PLAY.CPP < prev    next >
C/C++ Source or Header  |  1993-11-21  |  10KB  |  400 lines

  1.  
  2. // so_play.cpp - Implements the Player class
  3.  
  4. // Andy Barnhart
  5. // This program is provided as a sample to accompany an article on graphics
  6. //    animation using C++
  7. // This seems to work for me and I hope it works for you. No other warranty
  8. //    is expressed or implied.
  9.  
  10. #include <so_all.hpp>
  11.                                             
  12. // The states a player can be in to determine which frame to show
  13. //   Still or running are slight misnomers sometimes; more specifically,
  14. //   while running, the Player goes through "still" state to show the
  15. //   "legs straight" bitmap.
  16. #define PL_STILL_R 0  // Still, facing right  
  17. #define PL_RUN_R 1    // Running to the right
  18. #define PL_STILL_L 2  // Still, facing left
  19. #define PL_RUN_L 3    // Running to the left
  20.  
  21. #define PL_JMP_NO 0   // Not jumping
  22. #define PL_JMP_UP 1   // Jumping, and on the way up
  23. #define PL_JMP_DN 2   // Falling (he doesn't really "jump down") 
  24.  
  25. // We look at the screen size in case we need to pan the screen. I added this
  26. //  and was disappointed with the speed, so the default size keeps panning
  27. //  from being necessary, but I left the pan code in anyway.
  28.  
  29. extern int WinX, WinY, WinSX, WinSY;
  30.  
  31. // Create our hero
  32. Player::Player( char *res, int ix, int iy) : ScreenItem( NULL, ix, iy)
  33.     {
  34.     char aci[36];
  35.     int i;
  36.  
  37.     onrungs = FALSE;
  38.     still = TRUE;    
  39.     SOType = TYPE_PLAYER;
  40.                   
  41.     // Get some ammo                   
  42.     for ( i =0; i < 3; i++)
  43.         shots[i] = new Missile("fireball");
  44.     strcpy( aci, res);
  45.     
  46.     // The bitmaps are numbered for the possible Player positions
  47.     strcat( aci,"1");
  48.     Items[0] = LoadBitmap(hInst, aci);
  49.  
  50.     strcpy( aci, res);
  51.     strcat( aci,"2");
  52.     Items[1] = LoadBitmap(hInst, aci);
  53.  
  54.     strcpy( aci, res);
  55.     strcat( aci,"3");
  56.     Items[2] = LoadBitmap(hInst, aci);
  57.  
  58.     strcpy( aci, res);
  59.     strcat( aci,"4");
  60.     Items[3] = LoadBitmap(hInst, aci);
  61.  
  62.     state = PL_STILL_R;
  63.     jmpdir = PL_JMP_DN;
  64.     jmpadj = 40;
  65.     SelectBM( Items[state]);
  66.     }
  67.  
  68. // Get rid of Player - free up resources
  69. Player::~Player( void)
  70.     {
  71.     int i;
  72.     for ( i =0; i < 3; i++)
  73.         delete (shots[i]);
  74.     if( Items[0]) DeleteObject( Items[0]);
  75.     if( Items[1]) DeleteObject( Items[1]);
  76.     if( Items[2]) DeleteObject( Items[2]);
  77.     if( Items[3]) DeleteObject( Items[3]);
  78.     hbmImage = NULL;
  79.     }
  80.  
  81. // Fire a shot wherever we are faced
  82. void Player::Fire()
  83.     {
  84.     int i;  
  85.     
  86.     // see if we have any ammo available
  87.     for( i=0; i < 3; i++)
  88.         if( !shots[i]->inuse) break;
  89.     if( shots[i]->inuse) return;        
  90.     
  91.     // Always fire horizontal from current position to edge of window
  92.     switch (state)
  93.         {
  94.         case PL_STILL_R:
  95.         case PL_RUN_R:
  96.             shots[i]->Fire( x+width, y + (height/2), GMX-shots[i]->width,
  97.                     y + (height/2));
  98.             break;
  99.         case PL_STILL_L:
  100.         case PL_RUN_L:
  101.             shots[i]->Fire( x, y + (height/2), 0, y + (height/2));
  102.             break;
  103.         }
  104.     }
  105.  
  106. // Update - with a keystroke value
  107. //   This is a fairly complex state machine. There are a couple of minor
  108. //   glitches to iron out, but hey - the article is about graphics, not
  109. //   complex state machines. If you want to see a glitch, jump up against
  110. //   a wall at a lower left corner in the second scene. You won't get 
  111. //   stuck permenantly. You're welcome to expend your energy working out
  112. //   my glitches...
  113. BOOL Player::Update( int keystate)
  114.     {
  115.     int oldstate;
  116.     oldstate = state;
  117.     ScreenObj * SOHit = NULL;
  118.     ScreenObj * WallHit = NULL;
  119.  
  120.     if( keystate & KEY_RIGHT)
  121.         {
  122.         if( (state == PL_RUN_R))
  123.             state = PL_STILL_R;
  124.         else
  125.             state = PL_RUN_R;
  126.         // Move smaller amounts from a dead stop for precise movement
  127.         if( still)
  128.             {
  129.             x += 4;
  130.             still = FALSE;
  131.             }
  132.         else
  133.             x += xinc;
  134.         }
  135.     else if( keystate & KEY_LEFT)
  136.         {
  137.         if( state == PL_RUN_L)
  138.             state = PL_STILL_L;
  139.         else
  140.             state = PL_RUN_L;
  141.         if( still)
  142.             {
  143.             x -= 4;
  144.             still = FALSE;
  145.             }
  146.         else
  147.             x -= xinc;
  148.         }
  149.     else if( state == PL_RUN_L)
  150.         state = PL_STILL_L;
  151.     else if( state == PL_RUN_R)
  152.         state = PL_STILL_R;
  153.     if( (keystate & KEY_DOWN) && (jmpdir == PL_JMP_UP) )
  154.          jmpdir = PL_JMP_DN;
  155.     if( (keystate & KEY_UP) && (jmpdir == PL_JMP_NO) )
  156.         {
  157.         if( ! onrungs)
  158.             jmptop = y - (height * 2);
  159.         else
  160.             jmptop = y - 8;
  161.         if( jmptop < 0) jmptop = 0;
  162.         jmpdir = PL_JMP_UP;
  163.         }
  164.     if( jmpdir != PL_JMP_NO)
  165.         {
  166.         if( jmpdir == PL_JMP_UP)
  167.             {
  168.             y -= jmpadj;
  169.             if(y <= jmptop)
  170.                 {
  171.                 if( !onrungs)
  172.                     jmpdir = PL_JMP_DN;
  173.                 else
  174.                     jmpdir = PL_JMP_NO;
  175.                 y = jmptop;
  176.                 }
  177.             }
  178.         else
  179.             {
  180.             y += jmpadj;
  181.             }
  182.         }
  183.     if( state != oldstate)
  184.         SelectBM( Items[state]);
  185.     if( (x == oldx) && ( y == oldy) )
  186.         still = TRUE;
  187.     else
  188.         still = FALSE;
  189.     if( (state != oldstate) || (! still) )
  190.         {
  191.         RECT rc;
  192.         ScreenObj * SONxt;
  193.         int wallbelow = FALSE;
  194.  
  195.         if( y < 0) y = 0;
  196.         if( x < 0) x = 0;
  197.         if( (y+height) > Background->height) y = Background->height - height;
  198.         if( (x + width) > Background->width) x = Background->width - width;
  199.         SetRect( &rc);  
  200.         
  201.         // we reset then set this value each time through if we are climbing
  202.         onrungs = FALSE;                                                    
  203.         
  204.         // Look for Walls which we are walking on or will run into during
  205.         //    this move
  206.         for (SONxt = FirstWall(); SONxt != NULL; SONxt = NextWall())
  207.             {
  208.             if( (SONxt->shown) && (SONxt->InRect( &rc)))
  209.                 {
  210.                 if( x !=  oldx)
  211.                     {
  212.                     if( x > oldx)
  213.                         {
  214.                         if( ((x + width) > SONxt->x) && ((oldx + width) < SONxt->x))
  215.                             x = (SONxt->x - width) - 1;
  216.                         }
  217.                     else
  218.                         {
  219.                         if( (x < (SONxt->x + (SONxt->width * SONxt->wmult)) ) &&
  220.                                 ( oldx > (SONxt->x + (SONxt->width * SONxt->wmult)) ))
  221.                             x = SONxt->x + (SONxt->width * SONxt->wmult) + 1;
  222.                         }
  223.                     }
  224.                 if( y != oldy)
  225.                     {
  226.                     if( y > oldy)
  227.                         {
  228.                         if( ((y + height) > SONxt->y) && (oldy < SONxt->y) )
  229.                             {
  230.                             y = (SONxt->y - height) - 1;
  231.                             jmpdir = PL_JMP_NO;
  232.                             // We track this so we know we aren't falling
  233.                             wallbelow = TRUE;
  234.                             }
  235.                         }
  236.                     else
  237.                         {
  238.                         if( (y < (SONxt->y + (SONxt->height * SONxt->hmult)) ) &&
  239.                             ( oldy > (SONxt->y + (SONxt->height * SONxt->hmult)) ))
  240.                             {
  241.                             y = SONxt->y + (SONxt->height * SONxt->hmult) + 1;
  242.                             jmptop = y;
  243.                             jmpdir = PL_JMP_DN;
  244.                             }
  245.                         }
  246.                     }
  247.                 }
  248.             else if( (SONxt->y == (height +y + 1)))
  249.                 {
  250.                 RECT rc;
  251.  
  252.                 rc.top = y;
  253.                 rc.bottom = y + height + 1;
  254.                 rc.left = x;
  255.                 rc.right = x + width;
  256.                 if( SONxt->InRect( &rc) )
  257.                     wallbelow = TRUE;
  258.                 }
  259.             }
  260.         SetRect( &rc);
  261.         // See if we hit anything while moving
  262.         for( SONxt = Background->Next(); SONxt != NULL; SONxt = SONxt->Next())
  263.             {
  264.             if( (SONxt != this) && (SONxt->shown) && (SONxt->InRect( &rc)))
  265.                 {
  266.                 if( SOHit == NULL)
  267.                     SOHit = SONxt;
  268.                 else
  269.                     {
  270.                     if( (abs(oldy - SONxt->y) < abs(oldy - SOHit->y) ) ||
  271.                             (abs(oldx - SONxt->x) < abs(oldx - SOHit->x) ) )
  272.                         SOHit = SONxt;
  273.                     }
  274.                 }
  275.             }    
  276.         // If we hit anything, see what it was
  277.         if( SOHit != NULL)
  278.                 {
  279.                 int hit;
  280.  
  281.                 hit = SOHit->Type();
  282.                 switch (hit)
  283.                     {
  284.                     case TYPE_MISSILE:
  285.                     case TYPE_HAZARD:
  286.                         Hit( hit);
  287.                         break;    
  288.                         
  289.                     // If we hit a prize, we hide it. If you added scoring,
  290.                     //    this is where you could add the Info value from
  291.                     //    the prize to the score
  292.                     case TYPE_PRIZE:
  293.                         if( SOHit->shown)
  294.                             {
  295.                             SOHit->Show(FALSE);
  296.                             }
  297.                         break;                  
  298.                         
  299.                     // Exit, stage left! The Info value for a Door is the next 
  300.                     //     scene number to go to
  301.                     case TYPE_DOOR:
  302.                         {
  303.                         long next;
  304.                         next = SOHit->Info;
  305.                         Move( 0, 0);
  306.                         InitScene( (int) next);
  307.                         jmpdir = PL_JMP_DN;
  308.                         return( TRUE);
  309.                         }
  310.                         break;                  
  311.                         
  312.                     // If we hit a ladder, set the flag
  313.                     case TYPE_RUNGS:
  314.                         onrungs = TRUE;
  315.                         break;
  316.                     }
  317.             }
  318.                                                       
  319.         // If there is no Wall (floors are horizontal Walls) beneath us and
  320.         //   we aren't jumping up and aren't on a ladder, then we are falling!
  321.         if(( ! wallbelow) && ( jmpdir != PL_JMP_UP) && (!onrungs) )
  322.             {
  323.             jmpdir = PL_JMP_DN;
  324.             }
  325.             
  326.         // Here's that really slow panning action
  327.         if( (Background->width > WinX) ||  (Background->height > WinY) )
  328.             {
  329.             int oldsx = WinSX;
  330.             int oldsy = WinSY;
  331.             if( x != oldx)
  332.                 {
  333.                 if( x > oldx)
  334.                     {
  335.                     if( ( (WinSX + WinX) < Background->width) &&
  336.                             ( x > (WinSX + (WinX / 3 * 2) )) )
  337.                         {
  338.                         WinSX += x - (WinSX + (WinX / 3 * 2) );
  339.                         if( (WinSX + WinX) > Background->width)
  340.                             WinSX = Background->width - WinX;
  341.                         }
  342.                     }
  343.                 else
  344.                     {
  345.                     if( (WinSX > 0) && (x < (WinSX + (WinX / 3)  ) ) )
  346.                         {
  347.                         WinSX += x - (WinSX + (WinX / 3)  );
  348.                         if( WinSX < 0) WinSX = 0;
  349.                         }
  350.                     }
  351.                 }
  352.             if( y != oldy)
  353.                 {
  354.                 if( y > oldy)
  355.                     {
  356.                     if( ( (WinSY + WinY) < Background->height) &&
  357.                             ( y > (WinSY + (WinY / 3 * 2) )) )
  358.                         {
  359.                         WinSY += y - (WinSY + (WinY / 3 * 2) );
  360.                         if( (WinSY + WinY) > Background->height)
  361.                             WinSY = Background->height - WinY;
  362.                         }
  363.                     }
  364.                 else
  365.                     {
  366.                     if( (WinSY > 0) && (y < (WinSY + (WinY / 3 )  ) ) )
  367.                         {
  368.                         WinSY += y - (WinSY + (WinY / 3)  );
  369.                         if( WinSY < 0) WinSY = 0;
  370.                         }
  371.                     }
  372.                 }
  373.             if( (oldsx != WinSX) || (oldsy != WinSY) )
  374.                 {
  375.                 ScrollWindow( hWnd, oldsx - WinSX, oldsy - WinSY, NULL, NULL);
  376.                 SetWindowOrg( hDC, WinSX, WinSY);
  377.                 }
  378.             }
  379.         Paint();
  380.         }
  381.     return( TRUE);
  382.     }
  383.  
  384. // This is where we know we have been hit. Currently we just hop up to the upper
  385. //   left of the screen. If you want to make this a "real" game, you might track
  386. //   lives and use some logic to determine where to place him
  387. BOOL Player::Hit( int type)
  388.     {
  389.     if(type == TYPE_HAZARD)
  390.         {
  391.         Move( 0, 0);
  392.         WinSX = 0;
  393.         WinSY = 0;
  394.         InvalidateRect( hWnd, NULL, FALSE);
  395.         SetWindowOrg( hDC, WinSX, WinSY);
  396.         jmpdir = PL_JMP_DN;
  397.         return( TRUE);
  398.         }
  399.     return( FALSE);
  400.     }