GameBoard.cpp
上传用户:royluo
上传日期:2007-01-05
资源大小:1584k
文件大小:14k
源码类别:

游戏

开发平台:

Visual C++

  1. /*****************************************************************************
  2. *                                                                             
  3. *   GameBoard.cpp                                                            
  4. *                                                                             
  5. *   Electrical Engineering Faculty - Software Lab                             
  6. *   Spring semester 1998                                                      
  7. *                                                                             
  8. *   Tanks game                                                                
  9. *                                                                             
  10. *   Module description: Implements the game board game object.
  11. *                       
  12. *                                                                             
  13. *   Authors: Eran Yariv - 28484475                                           
  14. *            Moshe Zur  - 24070856                                           
  15. *                                                                            
  16. *                                                                            
  17. *   Date: 23/09/98                                                           
  18. *                                                                            
  19. ******************************************************************************/
  20. #include "stdafx.h"
  21. #include <stdlib.h>
  22. #include <ImageManager.h>
  23. #include <Tanks.h>
  24. #include <GameBoard.h>
  25. #ifdef _DEBUG
  26. #define new DEBUG_NEW
  27. #undef THIS_FILE
  28. static char THIS_FILE[] = __FILE__;
  29. #endif
  30. /*------------------------------------------------------------------------------
  31.   Function: React
  32.   Purpose:  Returns the game board reaction to the given game object. Since the
  33.             game board is a passive object, the reaction can only be blocked or
  34.             non-blocked, and the collision detection is done for every map block
  35.             the object overlaps.
  36.   Input:    pTo - the game object we are reacting to
  37.   Output:   The Reaction object
  38.   Remarks:  
  39. ------------------------------------------------------------------------------*/
  40. CReaction 
  41. CGameBoard::React(CGameObject *pTo)
  42. {
  43.     switch (pTo->GetType()) 
  44.     {   // We only react to moving object in the lower level and upper level:
  45.         case TANK:
  46.         case SHELL:
  47.         case BULLET:
  48.             {
  49.                 CPoint &ObjPos = pTo->GetPos();
  50.                 CSize &ObjSize = pTo->GetDimensions();
  51.                 // Calc the indexes of the map blocks the object is overlapping:
  52.                 UINT ul = ObjPos.x / MAP_BLOCK_SCALE,
  53.                      ur = (ObjPos.x + ObjSize.cx -1) / MAP_BLOCK_SCALE,
  54.                      ut = ObjPos.y / MAP_BLOCK_SCALE,
  55.                      ub = (ObjPos.y + ObjSize.cy -1) / MAP_BLOCK_SCALE;
  56.                 TerrainType ter = TERR_EMPTY;
  57.                 // Init CurrPos and CurrSize to hold the rect we are currently checking against:
  58.                 CPoint CurrPos;
  59.                 CSize CurrSize(MAP_BLOCK_SCALE, MAP_BLOCK_SCALE);
  60.                 UINT x, y;
  61.                 // Check against every rect we are overlapping:
  62.                 for (x = ul, CurrPos.x = ul * MAP_BLOCK_SCALE; 
  63.                      x <= ur; 
  64.                      x++, CurrPos.x += MAP_BLOCK_SCALE)
  65.                     for (y = ut, CurrPos.y = ut * MAP_BLOCK_SCALE;
  66.                          y <= ub;
  67.                          y++, CurrPos.y += MAP_BLOCK_SCALE) {
  68.                         //CRect TempRect(CurrPos, CurrSize);
  69.                         if (CollidesWith(pTo, CRect(CurrPos, CurrSize))) {
  70.                             ter = max (ter, ReadMap (x,y));
  71.                         }
  72.                     }
  73.                 return CReaction (0, ter, BONUS_NONE);
  74.             }
  75.         default:
  76.             return 0;
  77.     }
  78. }
  79. BOOL 
  80. CGameBoard::PickWallSeed (UINT &x, UINT &y)
  81. {
  82.     UINT uMaxTries= MAP_X_CELLS * MAP_Y_CELLS * 3;
  83.     while (uMaxTries-- > 0) 
  84.     {
  85.         x = TANK_BLOCK_WIDTH + Rand (MAP_X_CELLS - 1 - (TANK_BLOCK_WIDTH * 2));
  86.         y = TANK_BLOCK_HEIGHT + Rand (MAP_Y_CELLS - 1 - (TANK_BLOCK_HEIGHT * 2));
  87.         BOOL bFoundPlace = TRUE;
  88.         for (int i = -TANK_BLOCK_WIDTH; i <= TANK_BLOCK_WIDTH && bFoundPlace ; i++)
  89.             for (int j = -TANK_BLOCK_HEIGHT; j <= TANK_BLOCK_HEIGHT && bFoundPlace; j++)
  90.                 if (TERR_EMPTY != ReadMap(UINT(int(x)+i), UINT(int(y)+j)))
  91.                     bFoundPlace = FALSE;
  92.         if (bFoundPlace)
  93.             return TRUE;    // Success
  94.     }
  95.     return FALSE;   // Failure
  96. }
  97. void 
  98. CGameBoard::PickNextWallBlock (UINT &x, UINT &y, BYTE bDirectionOptions)
  99. {
  100.     ASSERT (bDirectionOptions); // You gotta give me something to choose from.....
  101.     BYTE b = m_bPrevDir;    
  102.     if (0 == Rand(8))
  103.         b = BYTE(1 << (Rand(4))); // b = 1, 2, 4, or 8
  104.     for (;;)
  105.     {
  106.         if ((b & bDirectionOptions) == DIRECTION_UP)
  107.         {
  108.             y--;
  109.             m_bPrevDir = b;
  110.             return;
  111.         }
  112.         if ((b & bDirectionOptions) == DIRECTION_DOWN)
  113.         {
  114.             y++;
  115.             m_bPrevDir = b;
  116.             return;
  117.         }
  118.         if ((b & bDirectionOptions) == DIRECTION_LEFT)
  119.         {
  120.             x--;
  121.             m_bPrevDir = b;
  122.             return;
  123.         }
  124.         if ((b & bDirectionOptions) == DIRECTION_RIGHT)
  125.         {
  126.             x++;
  127.             m_bPrevDir = b;
  128.             return;
  129.         }
  130.         b = BYTE(1 << (Rand(4))); // b = 1, 2, 4, or 8
  131.     }
  132. }
  133. BYTE 
  134. CGameBoard::GetNextWallBlockOptions (UINT x, UINT y)
  135. {
  136.     BYTE bRes = 0;
  137.     int i,j;
  138.     BOOL bOK;
  139.     // Check the up option:
  140.     bOK = FALSE;
  141.     if (x     >= TANK_BLOCK_WIDTH  && x     <= (MAP_X_CELLS - 1 - TANK_BLOCK_WIDTH) &&
  142.         (y-1) >= TANK_BLOCK_HEIGHT && (y-1) <= (MAP_Y_CELLS - 1 - TANK_BLOCK_HEIGHT))
  143.     {
  144.         bOK = TRUE;
  145.         for (i = -TANK_BLOCK_WIDTH; i <= TANK_BLOCK_WIDTH && bOK; i++)
  146.             for (j = -(TANK_BLOCK_HEIGHT + 1) ; j <= -1 && bOK; j++)
  147.                 if (TERR_EMPTY != ReadMap(UINT(int(x)+i), UINT(int(y)+j)))
  148.                     bOK = FALSE;
  149.         if (bOK)
  150.             bRes |= DIRECTION_UP;
  151.     }            
  152.     // Check the down option:
  153.     bOK = FALSE;
  154.     if (x     >= TANK_BLOCK_WIDTH  && x     <= (MAP_X_CELLS - 1 - TANK_BLOCK_WIDTH) &&
  155.         (y+1) >= TANK_BLOCK_HEIGHT && (y+1) <= (MAP_Y_CELLS - 1 - TANK_BLOCK_HEIGHT))
  156.     {
  157.         bOK = TRUE;
  158.         for (i = -TANK_BLOCK_WIDTH; i <= TANK_BLOCK_WIDTH && bOK; i++)
  159.             for (j = 1 ; j <= (TANK_BLOCK_HEIGHT + 1) && bOK; j++)
  160.                 if (TERR_EMPTY != ReadMap(UINT(int(x)+i), UINT(int(y)+j)))
  161.                     bOK = FALSE;
  162.         if (bOK)
  163.             bRes |= DIRECTION_DOWN;
  164.     }            
  165.     // Check the left option:
  166.     bOK = FALSE;
  167.     if ((x-1) >= TANK_BLOCK_WIDTH  && (x-1) <= (MAP_X_CELLS - 1 - TANK_BLOCK_WIDTH) &&
  168.         y     >= TANK_BLOCK_HEIGHT && y     <= (MAP_Y_CELLS - 1 - TANK_BLOCK_HEIGHT))
  169.     {
  170.         bOK = TRUE;
  171.         for (i = -(TANK_BLOCK_WIDTH + 1); i <= -1 && bOK; i++)
  172.             for (j = -TANK_BLOCK_HEIGHT ; j <= TANK_BLOCK_HEIGHT && bOK; j++)
  173.                 if (TERR_EMPTY != ReadMap(UINT(int(x)+i), UINT(int(y)+j)))
  174.                     bOK = FALSE;
  175.         if (bOK)
  176.             bRes |= DIRECTION_LEFT;
  177.     }            
  178.     // Check the right option:
  179.     bOK = FALSE;
  180.     if ((x+1) >= TANK_BLOCK_WIDTH  && (x+1) <= (MAP_X_CELLS - 1 - TANK_BLOCK_WIDTH) &&
  181.         y     >= TANK_BLOCK_HEIGHT && y     <= (MAP_Y_CELLS - 1 - TANK_BLOCK_HEIGHT))
  182.     {
  183.         bOK = TRUE;
  184.         for (i = 1; i <= (TANK_BLOCK_WIDTH + 1) && bOK; i++)
  185.             for (j = -TANK_BLOCK_HEIGHT ; j <= TANK_BLOCK_HEIGHT && bOK; j++)
  186.                 if (TERR_EMPTY != ReadMap(UINT(int(x)+i), UINT(int(y)+j)))
  187.                     bOK = FALSE;
  188.         if (bOK)
  189.             bRes |= DIRECTION_RIGHT;
  190.     }            
  191.     return bRes;
  192. }
  193. void 
  194. CGameBoard::ErectWalls (UINT uComplexityLevel)
  195. {
  196.     CDIB dibWallBlock;      // 1 map block of TERR_BLOCKED
  197.     UINT uMaxWalls = 6 + Rand (uComplexityLevel);       // Max number of walls
  198.          
  199.     dibWallBlock.ReadFromResource (IDB_WALLBLOCK);
  200.     CDIB *pDIB = TANKS_APP->m_gImageManager.ExposeDIB (m_hImage);
  201.     while (uMaxWalls--) 
  202.     {   // While there are still wall to erect
  203.         UINT x,y, uCurWallLength = 0,
  204.              uMaxWallLenght = 6 + 2 * Rand (uComplexityLevel);  // Max wall length
  205.         BOOL bWallDeadEnd = FALSE;
  206.         if (FALSE == PickWallSeed (x, y))
  207.             return; // Can't create more walls        
  208.         while (!bWallDeadEnd)
  209.         {
  210.             if (++uCurWallLength >= uMaxWallLenght)
  211.                 bWallDeadEnd = TRUE;   // Length exceeded => fake deadend => stop wall
  212.             WriteMap (x,y, TERR_BLOCKED);
  213.             pDIB->PasteCKRect (&dibWallBlock, 
  214.                                x * MAP_BLOCK_SCALE, 
  215.                                y * MAP_BLOCK_SCALE, 
  216.                                TRANSP_COLOR);
  217.                 // Get optional directions for next wall block
  218.             BYTE bDirectionOptions = GetNextWallBlockOptions (x,y);
  219.             if (bDirectionOptions == 0) // Dead end
  220.                 bWallDeadEnd = TRUE;
  221.             else
  222.                 // Pick direction from options    
  223.                 PickNextWallBlock (x, y, bDirectionOptions);
  224.         }
  225.     }
  226. }
  227. BOOL 
  228. CGameBoard::FindAndMarkBlockLocation (UINT &x, UINT &y, 
  229.                                            UINT uBlocksWidth, UINT uBlocksHeight,
  230.                                            TerrainType ter)
  231. {
  232.     UINT uMaxTries= (MAP_X_CELLS - 2) * (MAP_Y_CELLS - 2) * 3;
  233.     while (uMaxTries-- > 0) 
  234.     {
  235.         BOOL bOccupied = FALSE;
  236.         x = 1 + Rand (MAP_X_CELLS - uBlocksWidth - 1);
  237.         y = 1 + Rand (MAP_Y_CELLS - uBlocksHeight - 1);
  238.         for (int u = -1; u < int(uBlocksWidth+1) && !bOccupied; u++)
  239.             for (int v = -1; v < int(uBlocksHeight+1) && !bOccupied; v++)
  240.                 if (TERR_EMPTY != ReadMap (UINT(x) + u, UINT(y) + v))
  241.                     bOccupied = TRUE;   // Sorry, it's occupied
  242.         if (!bOccupied)
  243.         {
  244.             // Found free spot
  245.             for (UINT z = 0; z < uBlocksWidth; z++)
  246.                 for (UINT w = 0; w < uBlocksHeight; w++)
  247.                     WriteMap (x + z, y + w, ter);
  248.             return TRUE;    // Success
  249.         }
  250.     }
  251.     return FALSE;
  252. }
  253. void 
  254. CGameBoard::PlaceObstacle (UINT uComplexityLevel, 
  255.                            UINT uImageID, 
  256.                            TerrainType ter)
  257. {
  258.     CDIB dibBlocks[7];    // maps of block - 7 variations
  259.     
  260.         // Create all possible block variations:
  261.     dibBlocks[0].ReadFromResource (uImageID);
  262.     dibBlocks[1].CreateRotated (&dibBlocks[0], 90, FALSE, FALSE);
  263.     dibBlocks[2].CreateRotated (&dibBlocks[0],180, FALSE, FALSE);
  264.     dibBlocks[3].CreateRotated (&dibBlocks[0],270, FALSE, FALSE);
  265.     dibBlocks[4].CreateRotated (&dibBlocks[0],  0, TRUE , FALSE);
  266.     dibBlocks[5].CreateRotated (&dibBlocks[0],  0, FALSE, TRUE );
  267.     dibBlocks[6].CreateRotated (&dibBlocks[0],  0, TRUE , TRUE );
  268.     CDIB *pDIB = TANKS_APP->m_gImageManager.ExposeDIB (m_hImage);
  269.     UINT uMaxBlocks = 2 + UINT(0.33 * float(1 + Rand (uComplexityLevel)));
  270.     while (uMaxBlocks--)
  271.     {
  272.             // Pick block image variation
  273.         UINT uBlockImage = Rand (7);   
  274.         UINT x,y, 
  275.              uBlockWidth  = BlockSize(dibBlocks[uBlockImage].Width()),
  276.              uBlockHeight = BlockSize(dibBlocks[uBlockImage].Height());
  277.         if (FALSE == FindAndMarkBlockLocation (x, y, uBlockWidth, uBlockHeight, ter))
  278.             uMaxBlocks = 0;  // Stop placing ponds
  279.         else
  280.             pDIB->PasteCKRect (&dibBlocks[uBlockImage], 
  281.                              x * MAP_BLOCK_SCALE, 
  282.                              y * MAP_BLOCK_SCALE, 
  283.                              TRANSP_COLOR);
  284.     }
  285. }
  286.             
  287. /*------------------------------------------------------------------------------
  288.   Function: GenerateBoard
  289.   Purpose:  Generates this game board depending on the complexity level, and on
  290.             the seed of the random engine. This seed characterize the game board
  291.             thus the same board is generated each time we use the same seed.
  292.   Input:    uRandSeed - the random engine seed number
  293.             uComplexityLevel - the complexity level of this board
  294.   Output:   None.
  295.   Remarks:  The game complexity is read from the registry.
  296.             Passing the same seed and the complexity level to every game client 
  297.             generates the board.
  298. ------------------------------------------------------------------------------*/
  299. void 
  300. CGameBoard::GenerateBoard (UINT uRandSeed, UINT uComplexityLevel)
  301. {
  302.         // obstacles of 75% speed are yet to be implemented....
  303.     srand (uRandSeed);
  304.     ASSERT (uComplexityLevel <= 20 && uComplexityLevel > 0);
  305.         // Ask for board background to be loaded
  306.     TANKS_APP->m_gImageManager.ReloadMap();
  307.     m_hImage = TANKS_APP->m_gImageManager.GetImage (CImageManager::IMG_BOARD);
  308.         // Start with an empty map (no obstacles)
  309.     for (UINT x = 0; x < MAP_X_CELLS; x++)
  310.         for (UINT y = 0; y < MAP_Y_CELLS; y++)
  311.             WriteMap (x,y, TERR_EMPTY);
  312.     PlaceObstacle (uComplexityLevel, IDB_POND, TERR_25SPEED);
  313.     PlaceObstacle (uComplexityLevel, IDB_BOULDERS, TERR_50SPEED);
  314.     ErectWalls (uComplexityLevel);
  315. }
  316. /*------------------------------------------------------------------------------
  317.   Function: IsRectVacant
  318.   Purpose:  Check if the given rectangle intersect with any background object on
  319.             the map.
  320.   Input:    rect - the rectangle to be check.
  321.   Output:   TRUE if the rectangle is vacant = contains no walls or obstacles.
  322.   Remarks:  The background objects consists of blocks - so we check the blocks
  323.             that the given rectangle intersects.
  324. ------------------------------------------------------------------------------*/
  325. BOOL
  326. CGameBoard::IsRectVacant(CRect& rect)
  327. {
  328.         // Calc the indexes of the map blocks the rectangle intersects:
  329.     UINT ul = rect.left / MAP_BLOCK_SCALE,
  330.          ur = rect.right / MAP_BLOCK_SCALE,
  331.          ut = rect.top / MAP_BLOCK_SCALE,
  332.          ub = rect.bottom / MAP_BLOCK_SCALE;
  333.     for (UINT x = ul; x <= ur; x++)
  334.         for (UINT y = ut; y <= ub; y++)
  335.             if (ReadMap (x, y) != TERR_EMPTY)
  336.                 return FALSE;
  337.     return TRUE;
  338. }