⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gameboard.cpp

📁 分布式坦克游戏
💻 CPP
字号:
/*****************************************************************************
*                                                                             
*   GameBoard.cpp                                                            
*                                                                             
*   Electrical Engineering Faculty - Software Lab                             
*   Spring semester 1998                                                      
*                                                                             
*   Tanks game                                                                
*                                                                             
*   Module description: Implements the game board game object.
*                       
*                                                                             
*   Authors: Eran Yariv - 28484475                                           
*            Moshe Zur  - 24070856                                           
*                                                                            
*                                                                            
*   Date: 23/09/98                                                           
*                                                                            
******************************************************************************/

#include "stdafx.h"
#include <stdlib.h>
#include <ImageManager.h>
#include <Tanks.h>
#include <GameBoard.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/*------------------------------------------------------------------------------

  Function: React

  Purpose:  Returns the game board reaction to the given game object. Since the
            game board is a passive object, the reaction can only be blocked or
            non-blocked, and the collision detection is done for every map block
            the object overlaps.

  Input:    pTo - the game object we are reacting to

  Output:   The Reaction object

  Remarks:  
------------------------------------------------------------------------------*/
CReaction 
CGameBoard::React(CGameObject *pTo)
{
    switch (pTo->GetType()) 
    {   // We only react to moving object in the lower level and upper level:
        case TANK:
        case SHELL:
        case BULLET:
            {
                CPoint &ObjPos = pTo->GetPos();
                CSize &ObjSize = pTo->GetDimensions();
                // Calc the indexes of the map blocks the object is overlapping:
                UINT ul = ObjPos.x / MAP_BLOCK_SCALE,
                     ur = (ObjPos.x + ObjSize.cx -1) / MAP_BLOCK_SCALE,
                     ut = ObjPos.y / MAP_BLOCK_SCALE,
                     ub = (ObjPos.y + ObjSize.cy -1) / MAP_BLOCK_SCALE;

                TerrainType ter = TERR_EMPTY;
                // Init CurrPos and CurrSize to hold the rect we are currently checking against:
                CPoint CurrPos;
                CSize CurrSize(MAP_BLOCK_SCALE, MAP_BLOCK_SCALE);
                UINT x, y;
                // Check against every rect we are overlapping:
                for (x = ul, CurrPos.x = ul * MAP_BLOCK_SCALE; 
                     x <= ur; 
                     x++, CurrPos.x += MAP_BLOCK_SCALE)
                    for (y = ut, CurrPos.y = ut * MAP_BLOCK_SCALE;
                         y <= ub;
                         y++, CurrPos.y += MAP_BLOCK_SCALE) {
                        //CRect TempRect(CurrPos, CurrSize);
                        if (CollidesWith(pTo, CRect(CurrPos, CurrSize))) {
                            ter = max (ter, ReadMap (x,y));
                        }
                    }

                return CReaction (0, ter, BONUS_NONE);
            }

        default:
            return 0;
    }
}


BOOL 
CGameBoard::PickWallSeed (UINT &x, UINT &y)
{
    UINT uMaxTries= MAP_X_CELLS * MAP_Y_CELLS * 3;
    while (uMaxTries-- > 0) 
    {
        x = TANK_BLOCK_WIDTH + Rand (MAP_X_CELLS - 1 - (TANK_BLOCK_WIDTH * 2));
        y = TANK_BLOCK_HEIGHT + Rand (MAP_Y_CELLS - 1 - (TANK_BLOCK_HEIGHT * 2));
        BOOL bFoundPlace = TRUE;
        for (int i = -TANK_BLOCK_WIDTH; i <= TANK_BLOCK_WIDTH && bFoundPlace ; i++)
            for (int j = -TANK_BLOCK_HEIGHT; j <= TANK_BLOCK_HEIGHT && bFoundPlace; j++)
                if (TERR_EMPTY != ReadMap(UINT(int(x)+i), UINT(int(y)+j)))
                    bFoundPlace = FALSE;
        if (bFoundPlace)
            return TRUE;    // Success
    }
    return FALSE;   // Failure
}


void 
CGameBoard::PickNextWallBlock (UINT &x, UINT &y, BYTE bDirectionOptions)
{
    ASSERT (bDirectionOptions); // You gotta give me something to choose from.....
    BYTE b = m_bPrevDir;    
    if (0 == Rand(8))
        b = BYTE(1 << (Rand(4))); // b = 1, 2, 4, or 8
    for (;;)
    {
        if ((b & bDirectionOptions) == DIRECTION_UP)
        {
            y--;
            m_bPrevDir = b;
            return;
        }
        if ((b & bDirectionOptions) == DIRECTION_DOWN)
        {
            y++;
            m_bPrevDir = b;
            return;
        }
        if ((b & bDirectionOptions) == DIRECTION_LEFT)
        {
            x--;
            m_bPrevDir = b;
            return;
        }
        if ((b & bDirectionOptions) == DIRECTION_RIGHT)
        {
            x++;
            m_bPrevDir = b;
            return;
        }
        b = BYTE(1 << (Rand(4))); // b = 1, 2, 4, or 8
    }
}


BYTE 
CGameBoard::GetNextWallBlockOptions (UINT x, UINT y)
{
    BYTE bRes = 0;
    int i,j;
    BOOL bOK;

    // Check the up option:
    bOK = FALSE;
    if (x     >= TANK_BLOCK_WIDTH  && x     <= (MAP_X_CELLS - 1 - TANK_BLOCK_WIDTH) &&
        (y-1) >= TANK_BLOCK_HEIGHT && (y-1) <= (MAP_Y_CELLS - 1 - TANK_BLOCK_HEIGHT))
    {
        bOK = TRUE;
        for (i = -TANK_BLOCK_WIDTH; i <= TANK_BLOCK_WIDTH && bOK; i++)
            for (j = -(TANK_BLOCK_HEIGHT + 1) ; j <= -1 && bOK; j++)
                if (TERR_EMPTY != ReadMap(UINT(int(x)+i), UINT(int(y)+j)))
                    bOK = FALSE;
        if (bOK)
            bRes |= DIRECTION_UP;
    }            

    // Check the down option:
    bOK = FALSE;
    if (x     >= TANK_BLOCK_WIDTH  && x     <= (MAP_X_CELLS - 1 - TANK_BLOCK_WIDTH) &&
        (y+1) >= TANK_BLOCK_HEIGHT && (y+1) <= (MAP_Y_CELLS - 1 - TANK_BLOCK_HEIGHT))
    {
        bOK = TRUE;
        for (i = -TANK_BLOCK_WIDTH; i <= TANK_BLOCK_WIDTH && bOK; i++)
            for (j = 1 ; j <= (TANK_BLOCK_HEIGHT + 1) && bOK; j++)
                if (TERR_EMPTY != ReadMap(UINT(int(x)+i), UINT(int(y)+j)))
                    bOK = FALSE;
        if (bOK)
            bRes |= DIRECTION_DOWN;
    }            

    // Check the left option:
    bOK = FALSE;
    if ((x-1) >= TANK_BLOCK_WIDTH  && (x-1) <= (MAP_X_CELLS - 1 - TANK_BLOCK_WIDTH) &&
        y     >= TANK_BLOCK_HEIGHT && y     <= (MAP_Y_CELLS - 1 - TANK_BLOCK_HEIGHT))
    {
        bOK = TRUE;
        for (i = -(TANK_BLOCK_WIDTH + 1); i <= -1 && bOK; i++)
            for (j = -TANK_BLOCK_HEIGHT ; j <= TANK_BLOCK_HEIGHT && bOK; j++)
                if (TERR_EMPTY != ReadMap(UINT(int(x)+i), UINT(int(y)+j)))
                    bOK = FALSE;
        if (bOK)
            bRes |= DIRECTION_LEFT;
    }            

    // Check the right option:
    bOK = FALSE;
    if ((x+1) >= TANK_BLOCK_WIDTH  && (x+1) <= (MAP_X_CELLS - 1 - TANK_BLOCK_WIDTH) &&
        y     >= TANK_BLOCK_HEIGHT && y     <= (MAP_Y_CELLS - 1 - TANK_BLOCK_HEIGHT))
    {
        bOK = TRUE;
        for (i = 1; i <= (TANK_BLOCK_WIDTH + 1) && bOK; i++)
            for (j = -TANK_BLOCK_HEIGHT ; j <= TANK_BLOCK_HEIGHT && bOK; j++)
                if (TERR_EMPTY != ReadMap(UINT(int(x)+i), UINT(int(y)+j)))
                    bOK = FALSE;
        if (bOK)
            bRes |= DIRECTION_RIGHT;
    }            

    return bRes;
}



void 
CGameBoard::ErectWalls (UINT uComplexityLevel)
{
    CDIB dibWallBlock;      // 1 map block of TERR_BLOCKED

    UINT uMaxWalls = 6 + Rand (uComplexityLevel);       // Max number of walls
         

    dibWallBlock.ReadFromResource (IDB_WALLBLOCK);
    CDIB *pDIB = TANKS_APP->m_gImageManager.ExposeDIB (m_hImage);

    while (uMaxWalls--) 
    {   // While there are still wall to erect
        UINT x,y, uCurWallLength = 0,
             uMaxWallLenght = 6 + 2 * Rand (uComplexityLevel);  // Max wall length
        BOOL bWallDeadEnd = FALSE;

        if (FALSE == PickWallSeed (x, y))
            return; // Can't create more walls        
        while (!bWallDeadEnd)
        {
            if (++uCurWallLength >= uMaxWallLenght)
                bWallDeadEnd = TRUE;   // Length exceeded => fake deadend => stop wall
            WriteMap (x,y, TERR_BLOCKED);
            pDIB->PasteCKRect (&dibWallBlock, 
                               x * MAP_BLOCK_SCALE, 
                               y * MAP_BLOCK_SCALE, 
                               TRANSP_COLOR);
                // Get optional directions for next wall block
            BYTE bDirectionOptions = GetNextWallBlockOptions (x,y);
            if (bDirectionOptions == 0) // Dead end
                bWallDeadEnd = TRUE;
            else
                // Pick direction from options    
                PickNextWallBlock (x, y, bDirectionOptions);
        }
    }
}

BOOL 
CGameBoard::FindAndMarkBlockLocation (UINT &x, UINT &y, 
                                           UINT uBlocksWidth, UINT uBlocksHeight,
                                           TerrainType ter)
{
    UINT uMaxTries= (MAP_X_CELLS - 2) * (MAP_Y_CELLS - 2) * 3;
    while (uMaxTries-- > 0) 
    {
        BOOL bOccupied = FALSE;

        x = 1 + Rand (MAP_X_CELLS - uBlocksWidth - 1);
        y = 1 + Rand (MAP_Y_CELLS - uBlocksHeight - 1);
        for (int u = -1; u < int(uBlocksWidth+1) && !bOccupied; u++)
            for (int v = -1; v < int(uBlocksHeight+1) && !bOccupied; v++)
                if (TERR_EMPTY != ReadMap (UINT(x) + u, UINT(y) + v))
                    bOccupied = TRUE;   // Sorry, it's occupied
        if (!bOccupied)
        {
            // Found free spot
            for (UINT z = 0; z < uBlocksWidth; z++)
                for (UINT w = 0; w < uBlocksHeight; w++)
                    WriteMap (x + z, y + w, ter);
            return TRUE;    // Success
        }
    }
    return FALSE;
}

void 
CGameBoard::PlaceObstacle (UINT uComplexityLevel, 
                           UINT uImageID, 
                           TerrainType ter)
{
    CDIB dibBlocks[7];    // maps of block - 7 variations
    
        // Create all possible block variations:
    dibBlocks[0].ReadFromResource (uImageID);
    dibBlocks[1].CreateRotated (&dibBlocks[0], 90, FALSE, FALSE);
    dibBlocks[2].CreateRotated (&dibBlocks[0],180, FALSE, FALSE);
    dibBlocks[3].CreateRotated (&dibBlocks[0],270, FALSE, FALSE);
    dibBlocks[4].CreateRotated (&dibBlocks[0],  0, TRUE , FALSE);
    dibBlocks[5].CreateRotated (&dibBlocks[0],  0, FALSE, TRUE );
    dibBlocks[6].CreateRotated (&dibBlocks[0],  0, TRUE , TRUE );

    CDIB *pDIB = TANKS_APP->m_gImageManager.ExposeDIB (m_hImage);

    UINT uMaxBlocks = 2 + UINT(0.33 * float(1 + Rand (uComplexityLevel)));
    while (uMaxBlocks--)
    {
            // Pick block image variation
        UINT uBlockImage = Rand (7);   
        UINT x,y, 
             uBlockWidth  = BlockSize(dibBlocks[uBlockImage].Width()),
             uBlockHeight = BlockSize(dibBlocks[uBlockImage].Height());

        if (FALSE == FindAndMarkBlockLocation (x, y, uBlockWidth, uBlockHeight, ter))
            uMaxBlocks = 0;  // Stop placing ponds
        else
            pDIB->PasteCKRect (&dibBlocks[uBlockImage], 
                             x * MAP_BLOCK_SCALE, 
                             y * MAP_BLOCK_SCALE, 
                             TRANSP_COLOR);
    }
}
            

/*------------------------------------------------------------------------------

  Function: GenerateBoard

  Purpose:  Generates this game board depending on the complexity level, and on
            the seed of the random engine. This seed characterize the game board
            thus the same board is generated each time we use the same seed.

  Input:    uRandSeed - the random engine seed number
            uComplexityLevel - the complexity level of this board

  Output:   None.

  Remarks:  The game complexity is read from the registry.
            Passing the same seed and the complexity level to every game client 
            generates the board.

------------------------------------------------------------------------------*/
void 
CGameBoard::GenerateBoard (UINT uRandSeed, UINT uComplexityLevel)
{
        // obstacles of 75% speed are yet to be implemented....
    srand (uRandSeed);
    ASSERT (uComplexityLevel <= 20 && uComplexityLevel > 0);
        // Ask for board background to be loaded
    TANKS_APP->m_gImageManager.ReloadMap();
    m_hImage = TANKS_APP->m_gImageManager.GetImage (CImageManager::IMG_BOARD);

        // Start with an empty map (no obstacles)
    for (UINT x = 0; x < MAP_X_CELLS; x++)
        for (UINT y = 0; y < MAP_Y_CELLS; y++)
            WriteMap (x,y, TERR_EMPTY);

    PlaceObstacle (uComplexityLevel, IDB_POND, TERR_25SPEED);
    PlaceObstacle (uComplexityLevel, IDB_BOULDERS, TERR_50SPEED);
    ErectWalls (uComplexityLevel);
}

/*------------------------------------------------------------------------------

  Function: IsRectVacant

  Purpose:  Check if the given rectangle intersect with any background object on
            the map.

  Input:    rect - the rectangle to be check.

  Output:   TRUE if the rectangle is vacant = contains no walls or obstacles.

  Remarks:  The background objects consists of blocks - so we check the blocks
            that the given rectangle intersects.


------------------------------------------------------------------------------*/
BOOL
CGameBoard::IsRectVacant(CRect& rect)
{
        // Calc the indexes of the map blocks the rectangle intersects:
    UINT ul = rect.left / MAP_BLOCK_SCALE,
         ur = rect.right / MAP_BLOCK_SCALE,
         ut = rect.top / MAP_BLOCK_SCALE,
         ub = rect.bottom / MAP_BLOCK_SCALE;

    for (UINT x = ul; x <= ur; x++)
        for (UINT y = ut; y <= ub; y++)
            if (ReadMap (x, y) != TERR_EMPTY)
                return FALSE;

    return TRUE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -