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

📄 tankobj.cpp

📁 分布式坦克大战游戏,多机运行
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*****************************************************************************
*                                                                             
*   TankObj.cpp                                                            
*                                                                             
*   Electrical Engineering Faculty - Software Lab                             
*   Spring semester 1998                                                      
*                                                                             
*   Tanks game                                                                
*                                                                             
*   Module description: Implements the characteristics of the tank object.
*                                                                             
*   Authors: Eran Yariv - 28484475                                           
*            Moshe Zur  - 24070856                                           
*                                                                            
*                                                                            
*   Date: 23/09/98                                                           
*                                                                            
******************************************************************************/
#include "stdafx.h"
#include <math.h>
#include "tanks.h"
#include "TankObj.h"
#include "GameManager.h"
#include "Bullet.h"
#include "Shell.h"
#include "Mine.h"
#include "Message.h"
#include "Bomber.h"

// Regular delay between shells and bullets:
const UINT BULLET_FIRE_DELAY        =   UINT(1000.0 / double(BULLET_FIRE_RATE));    
const UINT SHELL_FIRE_DELAY         =   UINT(1000.0 / double(SHELL_FIRE_RATE));
// Extra short delay, when bonus is effective:
const UINT RAPID_BULLET_FIRE_DELAY  =   UINT(1000.0 / double(BULLET_FIRE_RATE)) / FIRE_RATE_BONUS;
const UINT RAPID_SHELL_FIRE_DELAY   =   UINT(1000.0 / double(SHELL_FIRE_RATE)) / FIRE_RATE_BONUS;

const DirOffsetType CTankObj::m_SpawnOffsets [24] =
{ //   Bullet    Shell     Mine
    {   0, 20,  -6,  17,  37,  16 },      //   0     ( <-- )
    {   1, 25,  -4,  22,  37,   8 },      //  15
    {   2, 29,  -3,  28,  35,   3 },      //  30
    {   6, 33,   2,  32,  30,  -3 },      //  45
    {   9, 36,   5,  36,  26,  -5 },      //  60
    {  15, 38,  11,  38,  21,  -7 },      //  75
    {  20, 38,  17,  38,  16,  -9 },      //  90     (  up )
    {  25, 38,  23,  38,   9,  -6 },      // 105     
    {  30, 36,  28,  36,   4,  -4 },      // 120     
    {  32, 32,  32,  32,  -2,   1 },      // 135     
    {  36, 29,  36,  27,  -5,   2 },      // 150    
    {  37, 24,  37,  22,  -7,  10 },      // 165     
    {  37, 18,  37,  16,  -9,  15 },      // 180     ( --> )     
    {  37, 13,  37,  10,  -7,  20 },      // 195     
    {  36,  9,  36,   5,  -4,  26 },      // 210     
    {  32,  5,  32,   1,  -2,  30 },      // 225     
    {  28,  2,  26,  -2,   3,  33 },      // 240     
    {  24,  0,  22,  -5,   9,  36 },      // 255     
    {  17, -1,  15,  -5,  15,  38 },      // 270     ( down )     
    {  13, -1,  10,  -6,  20,  38 },      // 285   
    {   8,  2,   5,  -2,  26,  36 },      // 300   
    {   4,  5,   0,   1,  32,  31 },      // 315   
    {   2,  9,  -3,   6,  34,  26 },      // 330   
    {   0, 14,  -5,  11,  37,  21 }       // 345   
};

const PosEntry UNUSED_POS_ENTRY;


CTankObj::CTankObj ( UINT uID, UINT uXPos, UINT uYPos, UINT uDirIndex, BOOL bLocal, UINT uShieldLevel, UINT uShells, 
                     UINT uBullets, UINT uMines, BYTE bFireRateBonusSecsLeft) :
        CMovingGameObject(uXPos, uYPos, TANK_WIDTH, TANK_HEIGHT, uDirIndex, double(TANK_MAX_VELOCITY)),
        m_uTankID(uID),
        m_uShieldLevel(uShieldLevel),
        m_uShells(uShells),
        m_uBullets(uBullets),
        m_uMines(uMines),
        m_pDlgWnd ((CTanksDlg*)(TANKS_APP->m_pMainWnd)),
        m_ManouverSet(TANKS_APP->m_gManouverSets[uID & 0x3]),
        m_ImageManager(TANKS_APP->m_gImageManager),
        m_ObjList(TANKS_APP->m_gGameManager.ExposeObjects()),
        m_MsgQueue(TANKS_APP->m_gIncomingMsgQueue),
        m_CommManager(TANKS_APP->m_gCommManager),
        m_Timer(TANKS_APP->m_gTimer),
        m_dwLastBulletFiredTick(0),
        m_dwLastShellFiredTick(0),
        m_dwLastMineDropTick(0),
        m_dwBulletFireDelay(BULLET_FIRE_DELAY),
        m_dwShellFireDelay(SHELL_FIRE_DELAY),
        m_bLocal (bLocal),
        m_dwLastRotationTime (0),
        m_bUseManouverSet (TRUE),
        m_bBomberInSetup (FALSE),
        m_bBomberAvail (FALSE),
        m_bForceNewPos (FALSE),
        m_bZombie (FALSE),
        m_PosTable (UNUSED_POS_ENTRY)
{
    ASSERT (uID < MAX_TANKS);
    
    m_hTankImage = m_ImageManager.GetImage ((CImageManager::ImageType)uID);
    m_hExplodedTankImage = m_ImageManager.GetImage (CImageManager::IMG_TANK_EXPLODE);
    m_hZombieOverlay = m_ImageManager.GetImage (CImageManager::IMG_TANK_ZOMBIE);

    // Test code  **************:
    m_ImageManager.RotateImage (m_hTankImage, m_uDirectionIndex);
    // End of test code **************
    m_pCurrentImage = &m_hTankImage;

    m_dwFireRateBonusLastTick = DWORD(bFireRateBonusSecsLeft) * 1000 + GetTickCount();

    if (m_bLocal) {
        m_pDlgWnd->SetShieldLevel (m_uShieldLevel);
        m_pDlgWnd->SetShellsCount (m_uShells);
        m_pDlgWnd->SetBulletsCount (m_uBullets);
        m_pDlgWnd->SetMinesCount (m_uMines);
        m_pDlgWnd->SetAerialSupport (FALSE);
        m_pDlgWnd->SetFastFireRate (m_dwFireRateBonusLastTick != 0);
    }
}

CReaction
CTankObj::React(CGameObject *pTo)
{
    ASSERT(pTo);

    CReaction res;

    switch (pTo->GetType())
    {
    case TANK:      // detect collision, and block the other object movement:
    case SHELL:     
    case BULLET:    
    case BOMB:
        if (CollidesWith(pTo))
        {
            res = CReaction(0, HIT_TANK, BONUS_NONE, m_uTankID);
        }
        break;
    }
    return res;
}

#pragma warning (disable : 4701)
/* warning C4701: local variable 'CurObjHImg', 'himgLastImage', 'uLastDir'
   may be used without having been initialized
   God damn it, trust me on this one - I know what I'm doing here....
*/


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

  Function: CalcState

  Purpose:  The main Tank object function. Called every game loop, the function
            collects the tank's maneuver, calculates the new position, and gathers
            the other game objects reaction to the new position. Upon return the
            tanks status (shield, ammo, bonuses) are updated.

  Input:    The local game time of the current game loop.

  Output:   Tank's new state.

  Remarks:  There's a difference between local and remote tanks behavior:
            The local tanks are allowed to set their state to dead, they need to
            update the game display (ammo etc.) and to dispatch the maneuver that
            was in use. Remote tanks don't need to do the above.

------------------------------------------------------------------------------*/
StateType 
CTankObj::CalcState (DWORD dwCurTime)
{ 
    m_bImageChanged = FALSE;    // Assume no change since last CalcState

    if (m_pCurrentImage == &m_hExplodedTankImage) 
    {   // if state==exploded - advance explosion or terminate
        if (m_ImageManager.ImageEnded(*m_pCurrentImage))  // That's it - we are done :-(
        {   // Explosion is over
            if (m_bLocal)   // It's the local tank that dies
            {
                // Go to game over animation mode
                m_pDlgWnd->GameOver ();
            }
            return STATE_DEAD;
        }
        return STATE_ALIVE; // Still exploding
    } 

    if (m_bZombie && !m_bForceNewPos)
        return STATE_ALIVE; // Zombie tank reacts to nothing !!

    // From here on starts the normal tank behaviour:
    
    CManouverSet ms;        // Detect manouver set (for network messages)
    BOOL bTryToRotate;      // Did the user dare to rotate ?
    HIMAGE himgLastImage;   // Current image, for undo purposes
    UINT uLastDir;          // Current rotation index, for undo purposes
    UINT ManouverSet;

    if (m_bUseManouverSet)
    {   // Can we use the manouver set to react to the user's whim
        //
        // Save movement params (for Undo option)
        //
        SaveMovement ();
        //
        //  handle manouver set:
        //
        ManouverSet = m_ManouverSet.GetAll();   
            // Each time we call GetAll on the MS we need to reset its values:
        TANKS_APP->m_gKbdManager.RefreshManouverSet();

        //
        // Calc new direction:
        //
        bTryToRotate = FALSE;              
        himgLastImage = m_hTankImage;
        uLastDir = m_uDirectionIndex;

        //
        // In cases of remote tanks, we occasionally get an absolute
        // direction from the net.
        //
        if (! m_bLocal && TANKS_APP->m_guRemoteTanksDirs[m_uTankID] != INVALID_DIRECTION)
        {   // We just got an absolute direction from a remote tank
            m_uDirectionIndex = TANKS_APP->m_guRemoteTanksDirs[m_uTankID];

            TANKS_APP->m_guRemoteTanksDirs[m_uTankID] = INVALID_DIRECTION;

            bTryToRotate = TRUE;
        } 
        else 
        {    
            // Normal game play - Either a local tank, or a remote w/o absolute direction:
            if (ManouverSet & CManouverSet::TURN_RIGHT_MASK)
            {   // Rotate right
                ms.SetBit (CManouverSet::TURN_RIGHT);   
                if (dwCurTime - m_dwLastRotationTime >= TANK_ROTATION_DELAY) 
                {   // enough time has passed sine last rotation
                    m_uDirectionIndex = (m_uDirectionIndex + 1) % MAX_DIRECTIONS;
                    bTryToRotate = TRUE;
                    ASSERT (m_uDirectionIndex < MAX_DIRECTIONS);
                } 
            }
            else if (ManouverSet & CManouverSet::TURN_LEFT_MASK)
            {   // Rotate left
                ms.SetBit (CManouverSet::TURN_LEFT);
                if (dwCurTime - m_dwLastRotationTime >= TANK_ROTATION_DELAY)
                {   // enough time has passed sine last rotation
                    m_uDirectionIndex = (m_uDirectionIndex == 0) ? 
                        (MAX_DIRECTIONS - 1) : (m_uDirectionIndex - 1);
                    bTryToRotate = TRUE;
                    ASSERT (m_uDirectionIndex < MAX_DIRECTIONS);
                }
            }
        } // end of local tank or remote w/o absolute direction

        if (bTryToRotate)
        {   // There's an attmept to rotate - Rotate the image
            m_ImageManager.RotateImage (m_hTankImage, m_uDirectionIndex);
            // Check if we're out of the map now
            if (GetMapPosition(m_Pos) != (X_FULL_IN_MAP | Y_FULL_IN_MAP)) 
            {   // Out of map situation - undo rotation
                m_uDirectionIndex = uLastDir;
                m_hTankImage = himgLastImage;
                ms.UnsetBit (CManouverSet::TURN_RIGHT);   // Cancel roations
                ms.UnsetBit (CManouverSet::TURN_LEFT);
            }
            else
            {   // Rotation o.k. - apply changes
                m_dwLastRotationTime = dwCurTime;
                m_bImageChanged = TRUE;
            }
        } // End of rotation attempt

        //
        // Calc new position: 
        //
        BOOL bTryToMove = FALSE;
        if (m_bForceNewPos)

⌨️ 快捷键说明

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