cocos2d-x開發之動作遊戲實戰--5

  先看一下這篇文章:

Cocos2d-x遊戲開發之TecturePacker的plist解析  

  將一下碰撞檢測的實現原理,應爲圖片基於plist的壓縮,碰撞過程中npc以及hero是一個運動的動畫,也就是說,一個動作有很多圖片合成,比如***動畫有五張圖片,而npc的運動動畫有三張,這種情況下的碰撞檢測就比較難一點,簡單的來說是矩形碰撞。

   碰撞算法的具體是實現,初始化動畫的過程中將,npc和hero的動作的圖片生成一個pictureArray的集合,然後成plist中讀取圖片的大小與npc的位置生成碰撞矩行,判斷5*3次。

生成picArray的實現:

bool AnimationManager::loadAnimation(AnimationFormation *af,int count)
{
    //緩衝——這會加載對應的png,並裁切成SpriteFrame,而且還會完成索引
    memset(charBuffer,0,sizeof(charBuffer));
    //sprintf(charBuffer,"objectTexture/16bit/4444-%sYPding.plist",af[0].animateName);
                                                                      
    //CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile(charBuffer);
    CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile(totoYPdingPlist);
    //創建動畫數據
    CCMutableArray<CCSpriteFrame*> *spriteFrames = new CCMutableArray<CCSpriteFrame*>();
    for (int i=0;i<count;i++)
    {
        CCMutableArray<CCString*> *picArray = new CCMutableArray<CCString*>();
        for(int j=getDirection(af[i].direction);j<getDirection(af[i].direction)+af[i].frameNum;j++)
        {
            memset(charBuffer,0,sizeof(charBuffer));
            sprintf(charBuffer,"%s_%d.png",af[i].animateName,/*getBehaviour(af[i].behaviour)*/j);
            CCString* picName=new CCString();
            picName->m_sString=charBuffer;
            picArray->addObject(picName);
            //printf("------AnimationPicture:    %s\n",charBuffer);
            //CCLOG("------AnimationPicture:    %s",charBuffer);
            //FrameCache
            CCSpriteFrame *spriteFrame=CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(charBuffer);
            spriteFrames->addObject(spriteFrame);
        }
        //使用cache緩衝管理
        CCAnimation *animation=CCAnimation::animationWithFrames(spriteFrames,0.1f);
        memset(charBuffer,0,sizeof(charBuffer));
        sprintf(charBuffer,"%s_%s%s",af[i].animateName,getBehaviour(af[i].behaviour),getDirectionName(af[i].direction));
        //CCLOG("AnimationName:       %s\n",charBuffer);
        //parse plist
        CCPlistParseCache::sharedPlistParseCache()->addPictureArrayWithAnimationName(charBuffer,picArray);
        CCAnimationCache::sharedAnimationCache()->addAnimation(animation,charBuffer);
        spriteFrames->removeAllObjects();
    }
    spriteFrames->release();
    return true;
}

關鍵代碼

CCPlistParseCache::sharedPlistParseCache()>addPictureArrayWithAnimation(charBuffer,picArray);

初始話後將CCPlistParseCache類的實現

class CCRectangle :public CCObject
{
public:
    const char* m_string;
    CCSize  size;
    CCRectangle();
    CCRectangle(const char* name,int width,int height);
    static float rectangleGetWidth(const CCRectangle& rect);
    static float rectangleGetHeight(const CCRectangle& rect);
    static const char* rectangleGetName(CCRectangle* rect);
    void  setRectangle(const char* name,int width,int height);
    float geRectangleWidth();
    CCRectangle* rect;
    //inline
    bool initRectangle(const char* m_name,int m_width,int m_height);
    inline int getWidth(void){return width;}
    inline int getHeight(void){return height;}
    inline const char* getName(void){return name;}
    inline const CCSize& getRect(void) { return m_obRect; }
    /** set size of the frame */
    void setRect(const CCSize& rect);
protected:
    const char* name;
    int width;
    int height;
    CCSize m_obRect;
};
#define CCRectangleMake(name,width,height) CCRectangle((name),(width),(height))
class CCPlistParseCache : public CCObject
{
public:
    bool init(void);
    ~CCPlistParseCache(void);
public:
    /** Returns the shared instance of the Sprite Frame cache */
    static CCPlistParseCache* sharedPlistParseCache(void);
    CCPlistParseCache(void):m_pSpriteName(NULL),m_pSpriteNameAliases(NULL),m_pAnimPic(NULL){}
    static void purgeSharedSpriteFrameCache(void);
    void addSpriteCollisionWithFile(const char *pszPlist);
                                          
    void addWeaponCollisionWithFile(const char *pszPlist);
                                          
    void addObjCollisionWithFile(const char *pszPlist);
    void addMoonkCollisionWithFile(const char *pszPlist);
    CCRectangle* spriteCollisionByName(const char *pszName);
    void addPictureArrayWithAnimationName(const char *pszName,CCMutableArray<CCString*>*pic);
    CCMutableArray<CCString*>* pictureArrayByAnimationName(const char *pszName);
private:
    CCDictionary<std::string, CCMutableArray<CCString*>*> *m_pAnimPic;
    const char * picForKey(const char *key, CCDictionary<std::string,  CCMutableArray<CCString*>*> *picDict);
    CCDictionary<std::string, CCString*> *m_pSpriteNameAliases;
    CCDictionary<std::string, CCRectangle*> *m_pSpriteName;
    const char * valueForKey(const char *key, CCDictionary<std::string, CCRectangle*> *dict);
};
#endif//_CCPLISTPARSECACHE_H_

部分函數的實現

void CCPlistParseCache::addSpriteCollisionWithFile(const char* pszPlist)
{
    //Load rootDict from file, and then step into the metadata sub dict.
    DS_Dictionary rootDict;
    if(!rootDict.loadRootSubDictFromFile(pszPlist))
    {
            printf("no load\n");
    }
    if(!rootDict.stepIntoSubDictWithKey("texture"))
    {
           printf("No texture\n");
    }
    //Get an int value from the subdict
    int someInt = rootDict.getIntegerForKey("height");
    CCLOG("height    %d",someInt);
    someInt = rootDict.getIntegerForKey("width");
    CCLOG("width    %d",someInt);
    //Step out of the sub dict and into another
    rootDict.stepOutOfSubDict();
    if(!rootDict.stepIntoSubDictWithKey("frames"))
    {
            printf("no dic\n");
    }
    for(int i=0;i<=59;)
    {
                                     
        char picture[20];
        sprintf(picture,"toto_%d.png",i);
        CCRectangle* rect=m_pSpriteName->objectForKey(picture);
        if(!rootDict.stepIntoSubDictWithKey(picture))
        {
            i++;
            //CCLOG("---noid--%d",i);
            rootDict.stepOutOfSubDict();
            continue;
        }
        //CCLOG("----totoid-------%d",i);
        int x=rootDict.getIntegerForKey("x");
        int y=rootDict.getIntegerForKey("y");
        int width=rootDict.getIntegerForKey("width");
        int height=rootDict.getIntegerForKey("height");
        //CCCollisionRectMake(picture,width,height);
        //CCLOG("Picture:%s  x:%d  y:%d  width:%d  height:%d\n",picture,x,y,width,height);
        CCRectangle rectangle=CCRectangleMake(picture,width-10,height-10);
        rect=new CCRectangle();
        rect->initRectangle(picture,width,height);
        std::string name=picture;
        m_pSpriteName->setObject(rect, name);
        //m_pSpriteName->release();
    }
    for(int i=0;i<=11;)
    {
        char picture[20];
        sprintf(picture,"yDing_%d.png",i);
        CCRectangle* rect=m_pSpriteName->objectForKey(picture);
        if(!rootDict.stepIntoSubDictWithKey(picture))
        {
            i++;
            //printf("No    %s\n",picture);
            rootDict.stepOutOfSubDict();
            continue;
        }
        int x=rootDict.getIntegerForKey("x");
        int y=rootDict.getIntegerForKey("y");
        int width=rootDict.getIntegerForKey("width");
        int height=rootDict.getIntegerForKey("height");
        //CCCollisionRectMake(picture,width,height);
        //printf("Picture:%s  x:%d  y:%d  width:%d  height:%d\n",picture,x,y,width,height);
        CCRectangle rectangle=CCRectangleMake(picture,width,height);
                                     
        rect=new CCRectangle();
                                     
        rect->initRectangle(picture,width,height);
        std::string name=picture;
        m_pSpriteName->setObject(rect, name);
        //m_pSpriteName->release();
    }
    for(int i=0;i<=11;)
    {
        char picture[20];
        sprintf(picture,"pDing_%d.png",i);
        //printf("piccture-----%s",picture);
        CCRectangle* rect=m_pSpriteName->objectForKey(picture);
        if(!rootDict.stepIntoSubDictWithKey(picture))
        {
            i++;
            //printf("No    %s\n",picture);
            rootDict.stepOutOfSubDict();
            continue;
        }
        int x=rootDict.getIntegerForKey("x");
        int y=rootDict.getIntegerForKey("y");
        int width=rootDict.getIntegerForKey("width");
        int height=rootDict.getIntegerForKey("height");
        //CCCollisionRectMake(picture,width,height);
        //printf("Picture:%s  x:%d  y:%d  width:%d  height:%d\n",picture,x,y,width,height);
        CCRectangle rectangle=CCRectangleMake(picture,width,height);
                                     
        rect=new CCRectangle();
                                     
        rect->initRectangle(picture,width,height);
        std::string name=picture;
        m_pSpriteName->setObject(rect, name);
        //m_pSpriteName->release();
    }
}

此類基於CCTextureCache類實現,可以參考實現其他的。

void CCPlistParseCache::addPictureArrayWithAnimationName(const char *pszName,CCMutableArray<CCString*>*pic)
{
    CCMutableArray<CCString*> * picture=m_pAnimPic->objectForKey(pszName);
    //CCLOG("addPic:      -   %s",pszName);
    picture=pic;
    std::string picName=pszName;
    m_pAnimPic->setObject(picture,picName);
}
CCMutableArray<CCString*>* CCPlistParseCache::pictureArrayByAnimationName(const char *pszName)
{
    CCMutableArray<CCString*> *pictureArray =m_pAnimPic->objectForKey(std::string(pszName));
    if (!pictureArray)
    {
        //printf("No PictureArray!");
        //CCLOG("No PictureArray!");
    }
    return pictureArray;
}

然後碰撞collision類的實現

class CCCollisionRect
{
public:
    const char* m_string;
    CCSize  size;
    CCCollisionRect();
    CCCollisionRect(const char* name,int width,int height);
public:
    static CGFloat CCRectGetHeight(const CCCollisionRect& rect);
    static CGFloat CCRectGetWidth(const CCCollisionRect& rect);
    static const char* CCRectGetName(const CCCollisionRect& rect);
};
#define CCCollisionRectMake(name,width, height) CCCollisionRect((name), (width), (height))
class collision:public Singleton<collision>
{
public:
    collision(void);
    ~collision(void);
    bool spriteCollision(CCNode* a,CCNode* b,const char* animationA,const char* animationB,Direction dir,Behaviour be);
    void spriteArray(const char* plistName);
    void plistParse();
    void getCollisionRect(const char* animationName,Direction dir,Behaviour be,CCNode* node);
    CCMutableArray<CCString*>* getAnimationPictureName(const char* animationName,Direction dir,Behaviour be);
                     
    char* getDirectionName(Direction direction);
    char* getBehaviour(Behaviour behaviour);
    bool isCCNodeCollision(const char* animNameA,const char* animNameB,Boy* boy,Enemy* enemy);
    bool isMoonkCollision(const char* animNameA,const char* animNameB,Boy* boy,Boss* boss);
    bool isPlayerCollision(const char* animNameA,const char* animNameB,Player* p,Enemy* enemy);
    bool bulletsCCNodeCollision(int i,const char* animNameA,const char* animNameB,Bullet* bullet,Enemy* enemy);
    bool bulletsMoonkCollision(int i,const char* animNameA,const char* animNameB,Bullet* bullet,Boss* moonk);
                     
private:
    BoxCollision boxCollision;
    bool isWingInit;
    bool isYdingInit;
    bool isPdingInit;
    bool isMoonkInit;
};
#define sCollision collision::getInstance()
#endif//_COLLISION_H_

實現一個函數

bool collision::isCCNodeCollision(const char* animNameA,const char* animNameB,Boy* boy,Enemy* enemy)
{
    //data not had inited
    CCMutableArray<CCString*>*collisionPicArrayA=getAnimationPictureName(animNameA,boy->getDirection(),boy->getBehaviour());
    CCMutableArray<CCString*>*collisionPicArrayB=getAnimationPictureName(animNameB,enemy->getDirection(),enemy->getBehaviour());
                  
    for(int i=0;i<collisionPicArrayA->count();i++)
    {
        for(int j=0;j<collisionPicArrayB->count();j++)
        {
            CCString* strA=collisionPicArrayA->getObjectAtIndex(i);
                          
            //return rectangle width and height
            CCRectangle* rectangleA=CCPlistParseCache::sharedPlistParseCache()->spriteCollisionByName(strA->m_sString.c_str());
            int widthA=rectangleA->getWidth();
            int heightA=rectangleA->getHeight();
            //CCLOG("---------------Collision:%s",strA->m_sString.c_str());
            CCString* strB=collisionPicArrayB->getObjectAtIndex(j);
            CCRectangle* rectangleB=CCPlistParseCache::sharedPlistParseCache()->spriteCollisionByName(strB->m_sString.c_str());
            int widthB=rectangleB->getWidth();
            int heightB=rectangleB->getHeight();
            char charBuffer[128];
            memset(charBuffer,0,sizeof(charBuffer));
            //CCLOG("COLLISION:animName:%s----width:%d    height:%d\n",strA->m_sString.c_str(),widthA,heightA);
            //CCLOG("COLLISION:animName:%s----width:%d    height:%d\n",strB->m_sString.c_str(),widthB,heightB);
            //attackAnimation toto_14.png~toto_19.png
            //ATTACK ANIMATION COLLISION校正
            for(int i=14;i<14+5;i++)
            {
                sprintf(charBuffer,"toto_%d.png",i);
                if(strcmp(charBuffer,strA->m_sString.c_str())==0)
                {
                    widthA=widthA-70;
                    heightA=heightA-50;
                }
                memset(charBuffer,0,sizeof(charBuffer));
            }
            CCRect a;
            CCRect b;
            a=boy->getCollisionRect(widthA,heightA);
            b=enemy->getCollisionRect(widthB,heightB);
                          
            if(CCRect::CCRectIntersectsRect(a,b))
            {
                //CCLOG("COLLISION YES!");
                return true;
            }
        }
    }
    return false;
}

具體怎麼用下一篇再講,待續(兩月後,期間沒網)。。。。。。。。。。。。。。。。。。

long原創




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章