www.pudn.com > dx9_2d_demo_game.zip > sprite.cpp


//----------------------------------------------------------------------------- 
//           Name: sprite.cpp 
//         Author: Kevin Harris (kevin@codesampler.com) 
//  Last Modified: 10/04/04 
//    Description: Implementation of Sprite class for gathering together all  
//                 properties and methods related to managing D3DXSprite based  
//                 game objects. 
//----------------------------------------------------------------------------- 
 
#include "sprite.h" 
 
//----------------------------------------------------------------------------- 
// Name: CSprite() 
// Desc: Constructor of the CSprite class 
//----------------------------------------------------------------------------- 
CSprite::CSprite() : 
m_pSpriteTexture( NULL ), 
m_pD3DXSprite( NULL ), 
m_nWidth( 0 ), 
m_nHeight( 0 ), 
m_nID( 0 ), 
m_nState( 0 ), 
m_fPosition_x( 0.0f ), 
m_fPosition_y( 0.0f ), 
m_fVelocity_x( 0.0f ), 
m_fVelocity_y( 0.0f ), 
m_bVisible( true ), 
m_bCollide( true ), 
m_bAutoAnimate( true ), 
m_bActive( true ), 
m_bScripting( false ), 
m_bModifyCollision( false ), 
m_bSingleFrame( false ), 
m_bDestroy( false ), 
m_nFrameRateModifier( 0 ), 
m_nFrameSkipCount( 0 ), 
m_nFrameWidth( 0 ), 
m_nFrameHeight( 0 ), 
m_nFramesAcross( 1 ), 
m_nFrameOffset_x( 0 ), 
m_nFrameOffset_y( 0 ), 
m_nWidthScaling( 0 ), 
m_nHeightScaling( 0 ), 
m_nCurrentAnimation( 0 ), 
m_nCurrentFrame( 0 ), 
m_nCurrentScript( 0 ), 
m_nCollisionTop( 0 ), 
m_nCollisionBottom( 0 ), 
m_nCollisionLeft( 0 ), 
m_nCollisionRight( 0 ) 
{ 
    for( int i = 0; i < TOTAL_ANIMATIONS; i++ ) 
        m_nAnimations[i] = NULL; 
 
    for( i = 0; i < MAX_SIZE; i++ ) 
    { 
        m_chType[i]   = NULL; 
        m_chName[i]   = NULL; 
        m_chSpriteTextureName[i] = NULL; 
    } 
} 
 
//----------------------------------------------------------------------------- 
// Name: ~CSprite() 
// Desc: Destructor of the CSprite class 
//----------------------------------------------------------------------------- 
CSprite::~CSprite() 
{ 
    if( m_pSpriteTexture != NULL )  
        m_pSpriteTexture->Release(); 
 
    if( m_pD3DXSprite != NULL )  
        m_pD3DXSprite->Release(); 
} 
 
//----------------------------------------------------------------------------- 
// Name: zeroSpriteValues() 
// Desc: Resets all member variables to their default values 
//----------------------------------------------------------------------------- 
void CSprite::zeroSpriteValues() 
{ 
    m_nWidth             = 0; 
    m_nHeight            = 0; 
    m_nID                = 0; 
    m_nState             = 0; 
    m_fPosition_x        = 0; 
    m_fPosition_y        = 0; 
    m_fVelocity_x        = 0; 
    m_fVelocity_y        = 0; 
    m_bVisible           = true; 
    m_bCollide           = true; 
    m_bAutoAnimate       = true; 
    m_bActive            = true; 
    m_bScripting         = false; 
    m_bModifyCollision   = false; 
    m_bSingleFrame       = false; 
    m_bDestroy           = false; 
    m_nFrameRateModifier = 0; 
    m_nFrameSkipCount    = 0; 
    m_nFrameWidth        = 0; 
    m_nFrameHeight       = 0; 
    m_nFramesAcross      = 1; 
    m_nFrameOffset_x     = 0; 
    m_nFrameOffset_y     = 0; 
    m_nWidthScaling      = 0; 
    m_nHeightScaling     = 0; 
    m_nCurrentAnimation  = 0; 
    m_nCurrentFrame      = 0; 
    m_nCurrentScript     = 0; 
    m_nCollisionTop      = 0; 
    m_nCollisionBottom   = 0; 
    m_nCollisionLeft     = 0; 
    m_nCollisionRight    = 0; 
 
    for( int i = 0; i < TOTAL_ANIMATIONS; i++ ) 
        m_nAnimations[i] = NULL; 
 
    for( i = 0; i < MAX_SIZE; i++ ) 
    { 
        m_chType[i]   = NULL; 
        m_chName[i]   = NULL; 
        m_chSpriteTextureName[i] = NULL; 
    } 
} 
 
 
//----------------------------------------------------------------------------- 
// Name: releaseMemory() 
// Desc: Releases memory allocated for the sprite's animation arrays 
//----------------------------------------------------------------------------- 
void CSprite::releaseMemory() 
{ 
    // This function releases any memory that was allocated  
    // from the heap for this sprite object. 
 
    for( int i = 0; i < TOTAL_ANIMATIONS; i++ ) 
    { 
        // Deallocate the memory that was previously  
        // reserved for each animation sequence. 
        if( m_nAnimations[i] != NULL ) 
        { 
            delete [] m_nAnimations[i]; 
            m_nAnimations[i] = NULL; 
        } 
    } 
} 
 
//----------------------------------------------------------------------------- 
// Name: loadAnimation() 
// Desc: Creates an array of frame numbers to display so animation effects  
//       can be created. 
//----------------------------------------------------------------------------- 
void CSprite::loadAnimation( int nAnimeNumber, int nStartFrame, int nEndFrame,  
                             AnimeEndOption nOption, int nNextAnimation ) 
{ 
    // This function loads the frame numbers that make up an animation  
    // sequence into an array by calculating the frame number values  
    // that exist between the nStartFrame and nEndFrame values passed in.  
    // After it determines how big the array will need to be, it then  
    // creates the array  dynamically on the heap. The pointer to the new  
    // array is then stored in the Animations[] array where it can be  
    // accessed later by specifying the proper index value. The frame  
    // numbers are then pulled from the number range between nStartFrame  
    // and nEndFrame and loaded into the new array. 
 
    bool bOverFlow = false; 
    int  nFrameNumber = 0; 
    int  nTotalFrames = 0; 
    int  i = 0; 
 
    if( nAnimeNumber >= 0 &&  
        nAnimeNumber < TOTAL_ANIMATIONS &&  
        m_nAnimations[nAnimeNumber] == NULL ) 
    { 
        if( nStartFrame < nEndFrame ) 
            nTotalFrames = (nEndFrame - nStartFrame); 
 
        if( nStartFrame > nEndFrame  ) 
            nTotalFrames = (nStartFrame - nEndFrame); 
 
        // Make room for the control codes that  
        // will be added later 
        nTotalFrames += 3;  
 
        m_nAnimations[nAnimeNumber] = new int[nTotalFrames]; 
        m_nFrameCount[nAnimeNumber] = nTotalFrames; 
 
        nFrameNumber = nStartFrame; 
 
        if( nAnimeNumber >= 0 && nAnimeNumber < TOTAL_ANIMATIONS ) 
        { 
            while( nFrameNumber != (nEndFrame + 1) ) 
            { 
                if( i <= (nTotalFrames - 1) ) 
                    m_nAnimations[nAnimeNumber][i] = nFrameNumber; 
                else 
                    bOverFlow = true; 
 
                if( nStartFrame < nEndFrame ) 
                    {++nFrameNumber;} 
                else if( nStartFrame > nEndFrame ) 
                    {--nFrameNumber;} 
 
                ++i; 
            } 
         
            // We now need to attach the control code stored in nOptions 
            // so the sprite object will know how to react when it reaches  
            // the last frame in thwe animation sequence. 
            if( nOption == LOOP_ANIMATION ) 
                m_nAnimations[nAnimeNumber][i] = LOOP_ANIMATION; 
 
            if( nOption == MAINTAIN_LAST_FRAME ) 
                m_nAnimations[nAnimeNumber][i] = MAINTAIN_LAST_FRAME; 
 
            if( nOption == GOTO_NEXT_ANIMATION ) 
            { 
                m_nAnimations[nAnimeNumber][i] = GOTO_NEXT_ANIMATION; 
                m_nAnimations[nAnimeNumber][i+1] = nNextAnimation; 
            } 
 
            if( nOption == GO_INACTIVE ) 
                m_nAnimations[nAnimeNumber][i] = GO_INACTIVE; 
        } 
    } 
} 
 
//----------------------------------------------------------------------------- 
// Name: loadAnimationString() 
// Desc: Creates an array of frame numbers to display so animation effects  
//       can be created. 
//----------------------------------------------------------------------------- 
void CSprite::loadAnimationString( int nAnimeNumber, char *chString,  
                                   AnimeEndOption nOption, int nNextAnimation ) 
{ 
    // This function loads the frame numbers that make up an animation  
    // sequence into an array by parsing a string that's passed in. 
    // After it determines how big the array will need to be, it then  
    // creates it dynamically on the heap. The pointer to the new array  
    // is then stored in the Animations[] array where it can be accessed  
    // later by specifying the proper index value. The frame numbers are  
    // then parsed out and loaded into the new array. 
 
    char *token = NULL; 
    char chDelimiters[] = " "; 
    char chBuffer[200] = { NULL }; 
    bool bOverFlow = false; 
    int  nFrameNumber = 0; 
    int  nTotalFrames = 0; 
    int  i = 0; 
     
    if( nAnimeNumber >= 0 &&  
        nAnimeNumber < TOTAL_ANIMATIONS &&  
        m_nAnimations[nAnimeNumber] == NULL ) 
    { 
        // Count the avaible tokens to find out how  
        // many frames have been listed. 
        strcpy( chBuffer, chString ); 
        token = strtok( chBuffer, chDelimiters ); 
 
        while( token != NULL ) 
        { 
            ++nTotalFrames; 
            token = strtok( NULL, chDelimiters ); 
        } 
 
        // Make room for the control codes that  
        // will be added later 
        nTotalFrames += 3;  
 
        m_nAnimations[nAnimeNumber] = new int[nTotalFrames]; 
        m_nFrameCount[nAnimeNumber] = nTotalFrames; 
 
        // Now, tokenize the string and convert the  
        // substrings into integer values. 
        strcpy( chBuffer, chString ); 
        token = strtok( chBuffer, chDelimiters ); 
 
        while( token != NULL ) 
        { 
            nFrameNumber = atoi( token ); 
 
            if( i <= (nTotalFrames - 1) ) 
                m_nAnimations[nAnimeNumber][i] = nFrameNumber; 
            else 
                bOverFlow = true; 
 
            ++i; 
            token = strtok( NULL, chDelimiters ); 
        } 
     
        // We now need to attach the control code stored in nOptions 
        // so the sprite object will know how to react when it reaches  
        // the last frame in the animation sequence. 
        if( nOption == LOOP_ANIMATION ) 
            m_nAnimations[nAnimeNumber][i] = LOOP_ANIMATION; 
 
        if( nOption == MAINTAIN_LAST_FRAME ) 
            m_nAnimations[nAnimeNumber][i] = MAINTAIN_LAST_FRAME; 
 
        if( nOption == GOTO_NEXT_ANIMATION ) 
        { 
            m_nAnimations[nAnimeNumber][i] = GOTO_NEXT_ANIMATION; 
            m_nAnimations[nAnimeNumber][i+1] = nNextAnimation; 
        } 
 
        if( nOption == GO_INACTIVE ) 
            m_nAnimations[nAnimeNumber][i] = GO_INACTIVE; 
    } 
} 
 
//----------------------------------------------------------------------------- 
// Name: incFrame() 
// Desc: Increments the current animation to the next frame 
//----------------------------------------------------------------------------- 
void CSprite::incFrame( bool bUseModifier ) 
{ 
    // This function allows the programmer to manually animate the sprite 
    // through an animationn sequence by incrementing the sprite's  
    // nCurrentFrame member variable in a safe manner. 
 
    DWORD dwNextNumber; 
    int   nTempHolder = 0; 
 
    if( bUseModifier == false ) 
    { 
        nTempHolder = m_nFrameRateModifier; 
        m_nFrameRateModifier = 0; 
    } 
 
    if( m_nFrameRateModifier > 0 ) 
    { 
        // The frame rate for animations has been speeded up! 
        // Skip ahead the number of frames given  
        // by nFrameRateModifier 
        for( int i = 0; i < m_nFrameRateModifier; ++i ) 
        { 
            // Check and see if the current frame number is a special control code! 
            dwNextNumber = m_nAnimations[m_nCurrentAnimation][m_nCurrentFrame + 1]; 
 
            if( dwNextNumber == LOOP_ANIMATION ) 
                m_nCurrentFrame = -1; 
 
            if( dwNextNumber == GOTO_NEXT_ANIMATION ) 
                return; 
 
            if( dwNextNumber == MAINTAIN_LAST_FRAME ) 
                return; 
 
            if( dwNextNumber == GO_INACTIVE ) 
                return; 
 
            ++m_nCurrentFrame; 
        } 
    } 
    else if( m_nFrameRateModifier < 0 ) 
    { 
        // The frame rate for animations has been slowed! 
        // Keep skipping cycles until we can move on to 
        // the next frame 
        --m_nFrameSkipCount; 
 
        if( m_nFrameRateModifier == m_nFrameSkipCount ) 
        { 
            // Check and see if the current frame number is a special control code! 
            dwNextNumber = m_nAnimations[m_nCurrentAnimation][m_nCurrentFrame + 1]; 
 
            if( dwNextNumber == LOOP_ANIMATION ) 
                m_nCurrentFrame = -1; 
 
            if( dwNextNumber == GOTO_NEXT_ANIMATION ) 
                return; 
 
            if( dwNextNumber == MAINTAIN_LAST_FRAME ) 
                return; 
 
            if( dwNextNumber == GO_INACTIVE ) 
                return; 
 
            ++m_nCurrentFrame; 
            m_nFrameSkipCount = 0; 
        } 
    } 
    else if( m_nFrameRateModifier == 0 ) 
    { 
        // Check and see if the current frame number is a special control code! 
        dwNextNumber = m_nAnimations[m_nCurrentAnimation][m_nCurrentFrame + 1]; 
 
        if( dwNextNumber == LOOP_ANIMATION ) 
            m_nCurrentFrame = -1; 
 
        if( dwNextNumber == GOTO_NEXT_ANIMATION ) 
            return; 
 
        if( dwNextNumber == MAINTAIN_LAST_FRAME ) 
            return; 
 
        if( dwNextNumber == GO_INACTIVE ) 
            return; 
 
        ++m_nCurrentFrame; 
    } 
 
    if( bUseModifier == false ) 
        m_nFrameRateModifier = nTempHolder; 
} 
 
//----------------------------------------------------------------------------- 
// Name: decFrame() 
// Desc: Decrements the current animation to the frame that comes before the  
//       current frame number. 
//----------------------------------------------------------------------------- 
void CSprite::decFrame( bool bUseModifier ) 
{ 
    // This function allows the programmer to manually animate the sprite 
    // through an animationn sequence by decrementing the sprite's  
    // nCurrentFrame member variable in a safe manner. 
 
    DWORD dwNextNumber; 
    int   nTempHolder = 0; 
 
    if( bUseModifier == false ) 
    { 
        nTempHolder = m_nFrameRateModifier; 
        m_nFrameRateModifier = 0; 
    } 
 
    if( m_nFrameRateModifier > 0 ) 
    { 
        // The frame rate for animations has been speeded up! 
        // Skip ahead the number of frames given  
        // by nFrameRateModifier 
        for( int i = 0; i < m_nFrameRateModifier; ++i ) 
        { 
            if( m_nCurrentFrame <= 0 ) 
            { 
                for( int i = 0; i < m_nFrameCount[m_nCurrentAnimation]; i++ ) 
                { 
                    dwNextNumber = m_nAnimations[m_nCurrentAnimation][i]; 
 
                    if( dwNextNumber == LOOP_ANIMATION ) 
                        m_nCurrentFrame = i - 1; 
 
                    if( dwNextNumber == GOTO_NEXT_ANIMATION ) 
                        return; 
 
                    if( dwNextNumber == MAINTAIN_LAST_FRAME ) 
                        return; 
 
                    if( dwNextNumber == GO_INACTIVE ) 
                        return; 
                } 
            } 
            else 
            { 
                --m_nCurrentFrame; 
            } 
        } 
    } 
    else if( m_nFrameRateModifier < 0 ) 
    { 
        // The frame rate for animations has been slowed! 
        // Keep skipping cycles until we can move on to 
        // the next frame 
        --m_nFrameSkipCount; 
 
        if( m_nFrameRateModifier == m_nFrameSkipCount ) 
        { 
            if( m_nCurrentFrame <= 0 ) 
            { 
                for( int i = 0; i < m_nFrameCount[m_nCurrentAnimation]; i++ ) 
                { 
                    dwNextNumber = m_nAnimations[m_nCurrentAnimation][i]; 
 
                    if( dwNextNumber == LOOP_ANIMATION ) 
                        m_nCurrentFrame = i - 1; 
 
                    if( dwNextNumber == GOTO_NEXT_ANIMATION ) 
                        return; 
 
                    if( dwNextNumber == MAINTAIN_LAST_FRAME ) 
                        return; 
 
                    if( dwNextNumber == GO_INACTIVE ) 
                        return; 
                } 
            } 
            else 
            { 
                --m_nCurrentFrame; 
            } 
 
            m_nFrameSkipCount = 0; 
        } 
    } 
    else if( m_nFrameRateModifier == 0 ) 
    { 
        if( m_nCurrentFrame <= 0 ) 
        { 
            for( int i = 0; i < m_nFrameCount[m_nCurrentAnimation]; i++ ) 
            { 
                dwNextNumber = m_nAnimations[m_nCurrentAnimation][i]; 
 
                if( dwNextNumber == LOOP_ANIMATION ) 
                    m_nCurrentFrame = i - 1; 
 
                if( dwNextNumber == GOTO_NEXT_ANIMATION ) 
                    return; 
 
                if( dwNextNumber == MAINTAIN_LAST_FRAME ) 
                    return; 
 
                if( dwNextNumber == GO_INACTIVE ) 
                    return; 
            } 
        } 
        else 
        { 
            --m_nCurrentFrame; 
        } 
    } 
 
    if( bUseModifier == false ) 
        m_nFrameRateModifier = nTempHolder; 
} 
 
//----------------------------------------------------------------------------- 
// Name: drawSprite() 
// Desc: Uses the sprite's properties and current animation values to select 
//       the correct frame from the sprit's bitmap, and then copies the 
//       bitmap data from the surface given, onto the display given. 
//----------------------------------------------------------------------------- 
HRESULT CSprite::drawSprite( LPDIRECT3DDEVICE9 pDevice ) 
{ 
    if( m_pD3DXSprite == NULL ) 
    { 
        D3DXIMAGE_INFO d3dxImageInfo; 
 
        D3DXCreateTextureFromFileEx( pDevice, 
                                     m_chSpriteTextureName, 
                                     m_nWidth, // I had to set width manually. D3DPOOL_DEFAULT works for textures but causes problems for D3DXSPRITE. 
                                     m_nHeight, // I had to set height manually. D3DPOOL_DEFAULT works for textures but causes problems for D3DXSPRITE. 
                                     1,   // Don't create mip-maps when you plan on using D3DXSPRITE. It throws off the pixel math for sprite animation. 
                            0, //D3DPOOL_DEFAULT, 
                                     D3DFMT_UNKNOWN, 
                            D3DPOOL_MANAGED, //D3DPOOL_DEFAULT, 
                                     D3DX_DEFAULT, 
                                     D3DX_DEFAULT, 
                                     D3DCOLOR_COLORVALUE(0.0f,0.0f,0.0f,1.0f), 
                                     &d3dxImageInfo, 
                                     NULL, 
                                     &m_pSpriteTexture ); 
 
        D3DXCreateSprite( pDevice, &m_pD3DXSprite ); 
    } 
 
    HRESULT hr = 0; 
 
    if( m_bActive == true ) 
    { 
        RECT  rcSource; 
        DWORD dwFrameNumber; 
        DWORD dwNextNumber; 
 
        if( m_bSingleFrame == false ) 
        { 
            dwFrameNumber = m_nAnimations[m_nCurrentAnimation][m_nCurrentFrame]; 
        } 
        else 
        { 
            dwFrameNumber = 0; 
            m_nFramesAcross = 1; 
        } 
 
        // Create a source RECT that represents the section of the bitmap  
        // where the next frame of animation will be copied from during the  
        // call to Draw(). 
        rcSource.top    = ( ( dwFrameNumber / m_nFramesAcross ) * m_nFrameHeight ); 
        rcSource.left   = ( ( dwFrameNumber % m_nFramesAcross ) * m_nFrameWidth ); 
        rcSource.bottom = rcSource.top  + m_nFrameHeight; 
        rcSource.right  = rcSource.left + m_nFrameWidth; 
 
        // If an offset was used, (i.e. frame 0 is not be located in the upper  
        // left corner of the bitmap), the offset values must be applied or the  
        // frames will not be copied correctly.  
        if( m_nFrameOffset_x != 0 || m_nFrameOffset_y != 0 ) 
        { 
            rcSource.top    += m_nFrameOffset_y; 
            rcSource.left   += m_nFrameOffset_x; 
            rcSource.bottom += m_nFrameOffset_y; 
            rcSource.right  += m_nFrameOffset_x; 
        } 
 
        D3DXVECTOR3 vCenter( 0.0f, 0.0f, 0.0f ); 
        D3DXVECTOR3 vPosition( m_fPosition_x, m_fPosition_y, 0.0f ); 
 
        m_pD3DXSprite->Begin( D3DXSPRITE_ALPHABLEND ); 
        { 
            m_pD3DXSprite->Draw( m_pSpriteTexture, 
                                 &rcSource, 
                                 &vCenter, 
                                 &vPosition, 
                                 D3DCOLOR_COLORVALUE(1.0f,1.0f,1.0f,1.0f) ); 
        } 
        m_pD3DXSprite->End(); 
 
        if( m_bAutoAnimate == true && m_bSingleFrame == false) 
        { 
            // Check and see if the next frame number is a special control code! 
            dwNextNumber = m_nAnimations[m_nCurrentAnimation][m_nCurrentFrame+1]; 
 
            if( dwNextNumber == LOOP_ANIMATION ) 
                m_nCurrentFrame = -1; 
 
            if( dwNextNumber == GOTO_NEXT_ANIMATION ) 
            { 
                m_nCurrentAnimation = m_nAnimations[m_nCurrentAnimation][m_nCurrentFrame+2]; 
                m_nCurrentFrame = -1; 
            } 
 
            if( dwNextNumber == GO_INACTIVE ) 
            { 
                m_bActive = false; 
                m_nCurrentFrame = -1; 
            } 
 
            if( dwNextNumber == MAINTAIN_LAST_FRAME ) 
                return hr; 
 
            if( m_nFrameRateModifier == 0 ) 
            { 
                ++m_nCurrentFrame; 
            } 
            else 
            { 
                // Has the frame rate has been modified! 
                if( m_nFrameRateModifier < 0 ) 
                { 
                    // The frame rate for animations has been slowed! 
                    // Keep skipping cycles until we can move on to 
                    // the next frame 
                    --m_nFrameSkipCount; 
 
                    if( m_nFrameRateModifier == m_nFrameSkipCount ) 
                    { 
                        ++m_nCurrentFrame; 
                        m_nFrameSkipCount = 0; 
                    } 
                } 
                else 
                { 
                    // The frame rate for animations has been speeded up! 
                    // Skip ahead the number of frames given  
                    // by nFrameRateModifier 
                    for( int i = 0; i < m_nFrameRateModifier; ++i ) 
                    { 
                        incFrame(false); 
                    } 
                } 
            } 
        } 
    } 
 
    return hr; 
}