cocos2d-x之SimpleGame分析

來源:互聯網
上載者:User

本文原創著作權歸 部落格園 Terry_龍 所有,轉載請註明原創作者及出處,以示尊重!

作者:Terry_龍
原文:http://www.cnblogs.com/TerryBlog/archive/2012/10/30/2746150.html

作為cocos2d-x的標配DEMO,SimpleGame可算是給入門學cocos2d-x的俺們這些新手門學習的對象了,那麼來分析分析,把幾個關鍵的代碼記錄下來。

 

設定遊戲讀取資源的目錄

CCFileUtils::sharedFileUtils()->setResourceDirectory("sd");

 預設路徑是Resource目錄

 

設定遊戲的解析度大小

CCEGLView::sharedOpenGLView()->setDesignResolutionSize(480, 320, kResolutionNoBorder);

也可以不設定,自動去擷取

 

建立精靈

CCSprite *player=CCSprite::create("Player.png",CCRectMake(0,0,27,40));
        player->setPosition(ccp(
            origin.x+player->getContentSize().width/2, //X軸為:0+遊戲角色的寬度/2
            winVisibleSize.height/2 + player->getContentSize().height/2) //y軸為:指定的螢幕解析度/2+遊戲角色的高/2
            );
        this->addChild(player);

 如果你希望精靈在圖層初始化的時候就產生,那麼精靈的建立最好把它放在於圖層(CCLayer)的init函數中。

 建立精靈時,需要為精靈指定位置(position),可接收的參數是CCPoint類型,CCPoint 是一個存放x、y軸資料的對象

 

使用時間選取器重新整理遊戲

this->schedule(schedule_selector(HelloWorld::gameLogic),1.0);

 調用CCNodes的schedule(SEL_SCHEDULE selector, float interval)方法,這是一個自訂的時間選取器,以秒為單位。這裡以秒為單位,每秒產生一個怪物

 

設定可接受觸摸(Touch)事件

在情境初始化時,設定可接受觸摸

 this->setTouchEnabled(true);

 然後,註冊一個觸摸事件的分發函數

void HelloWorld::registerWithTouchDispatcher(){
    CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this,0);
}

 通過以上的做法,遊戲即可在ccTouchesEnded回呼函數裡面得到觸摸反饋。

 

移動精靈

上面每一秒鐘重新整理遊戲,產生一個遊戲怪物,方法位於HelloWold::addTarget,移動精靈的代碼是

CCFiniteTimeAction* actionMove = CCMoveTo::create( (float)actualDuration,
                                            ccp(0 - target->getContentSize().width/2, actualY) );
    CCFiniteTimeAction* actionMoveDone = CCCallFuncN::create( this, 
                                            callfuncN_selector(HelloWorld::spriteMoveFinished));
    target->runAction( CCSequence::create(actionMove, actionMoveDone, NULL) );

 

 actionMove:設定精靈移動方向和移動速度

actionMoveDone:精靈移動完成後執行可執行檔回呼函數為 spriteMoveFinished,當遊戲移動到螢幕邊界外,即回收該對象

 然後通過精靈的runAction設定,精靈移動

 

上面代碼,怪物的產生位置定在x的最右邊,move方向從右至左到訊息,需要設定x軸的最小值並且完全可以將怪物移動出螢幕即可,故x軸這裡設定行動程式碼: (0 - target->getContentSize().width/2
),y軸不變,隨機從出來那一刻起一直不變做橫向移動。

 

 控制遊戲角色發射飛鏢

上面有提到設定圖層可授受觸摸 ,接下來我們要通過觸摸讓遊戲主角發射飛鏢消滅不斷產生的怪物。代碼見下方

得到觸摸點座標 

CCTouch* touch = (CCTouch*)( touches->anyObject() );
    CCPoint location = touch->getLocation();

 每接受觸摸一次產生一個飛鏢

 CCSize winSize = CCDirector::sharedDirector()->getVisibleSize();

    CCSprite *projectile = CCSprite::create("Projectile.png", CCRectMake(0, 0, 20, 20));
    projectile->setPosition( ccp(20, winSize.height/2+projectile->getContentSize().height/2) );//角色x軸為0+角色的寬度,故飛鏢的x軸應和角色有交接,使使用者看起來飛鏢是從角色身上發出來的

飛鏢移動方向

float offX=location.x - projectile->getPosition().x;
    float offY=location.y - projectile->getPosition().y;

    if(offX <=0)return;

    this->addChild(projectile);
     
    float realX=winSize.width+(projectile->getContentSize().width/2);//飛鏢的橫向方向跟遊戲怪物一樣,也是要移動出遊戲介面並回收的(如果碰到怪物也要回收)
    float ratio = offY/offX;//位移量
    float realY=(realX*ratio)+projectile->getPosition().y;//飛鏢的豎向方嚮應是飛鏢的橫向方向*觸摸點的位移量每幀位移的數值+當前飛鏢所在位置的y軸
    CCPoint realDest =ccp(realX,realY);

控制飛鏢移動

projectile->runAction(CCSequence::create(
        CCMoveTo::create(1.0,realDest),//參數1.移動速度。參數2.移動的x、y軸
        CCCallFuncN::create(this,callfuncN_selector(HelloWorld::spriteMoveFinished)),//設定回呼函數
        NULL
    ));

 

飛鏢與怪物的碰撞檢測

這裡需要在圖層初始化的時候設定一個時間選取器,監聽每幀的遊戲變化

   this->schedule(schedule_selector(HelloWorld::updateGame));

這時委託函數updateGame就啟到每幀監聽的作用了,代碼如下

void HelloWorld::updateGame(float dt){
    CCArray *projectileToDelete =new CCArray;
    CCObject* it=NULL;
    CCObject* jt = NULL;
    CCARRAY_FOREACH(_projectiles,it){ //迴圈每一個飛鏢
        CCSprite *projectile=dynamic_cast<CCSprite*>(it);
        CCRect projectileRect =CCRectMake(
            projectile->getPosition().x - (projectile->getContentSize().width/2),
            projectile->getPosition().y-(projectile->getContentSize().height/2),
            projectile->getContentSize().width,
            projectile->getContentSize().height);

        CCArray* targetsToDelete=new CCArray;
        
        CCARRAY_FOREACH(_targets, jt)//迴圈每一個敵人
        {
            CCSprite *target = dynamic_cast<CCSprite*>(jt);
            
            CCRect targetRect = CCRectMake(
            target->getPosition().x - (target->getContentSize().width/2),
            target->getPosition().y - (target->getContentSize().height/2),
            target->getContentSize().width,
            target->getContentSize().height);
            if (projectileRect.intersectsRect(targetRect)) //這裡做矩形交集檢測,如果兩者有產生交集則將需要刪除的敵人存放於數組裡面
            {
                targetsToDelete->addObject(target);
            }
        }

         CCARRAY_FOREACH(targetsToDelete, jt)//迴圈需要刪除的敵人
         {
             CCSprite *target = dynamic_cast<CCSprite*>(jt);
             _targets->removeObject(target);  //將敵人從產生的敵人數組裡面刪除
             this->removeChild(target, true);//從圖層刪除

              _projectilesDestroyed++;  //累積
              if (_projectilesDestroyed >= 10) //當滿足消滅一定數量的敵人時,則執行遊戲情境切換或者什麼的blablabla
              {
                 ///
              }
          }
         if(targetsToDelete->count() > 0){ //如果有存在需要刪除的敵人,則同時將與敵人交集的飛鏢存入需要刪除的飛鏢數組
            projectileToDelete->addObject(projectile);
         }
         targetsToDelete->release();
    }

    //remove projectile
    CCARRAY_FOREACH(projectileToDelete,it){ //最後迴圈飛鏢將飛鏢刪除掉
        CCSprite *projectile =dynamic_cast<CCSprite*>(it);
        _projectiles->removeObject(projectile);
        this->removeChild(projectile,true);
    }
    projectileToDelete->release();
    //end
 }

 根據上面,邏輯並不複雜,注意一下當前飛鏢與敵人數組之間的關係即可。

 

播放遊戲音效

無論是遊戲背景音效也好,忍者發射飛鏢那一刹那時的聲音也好,好的遊戲都要加上特殊的音效效果才能使遊戲更加引人入勝。 cocos2d-x遊戲引擎當然也有相關的音樂播放介面。從網上找到的一段話:

cocos2d-iphone裡包含cocosDenshion庫,裡面從底到高提供三層介面:CDSoundEngine->CDAudioManager->SimpleAudioEngine,但整個庫完全依賴於OpenAL來實現。關於OpenAL,它不是Khronos
Group的標準,而是Creative公司的一個開源庫,可以軟實現或硬體實現。目前硬體實現了OpenAL的好像就只有蘋果的產品,因此在其他平台上,我們無法提供cocosDenshion底層的支援,但我們是支援頂層的,它是開發人員最常用到的一層。

 

 那麼如何添加音效呢?

添加背景音

 CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("background-music-aac.wav",true);//設定背景音迴圈

 添加發射飛鏢音效

CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("pew-pew-lei.wav",false);

 這裡發射飛鏢音效需要注意一個問題就是,如果這樣寫在Touch裡面,第一次讓音效播放是無效的,原因是播放音效需要預先載入,不然第一次點擊是不會出聲音的,之後才會。不知道這是引擎硬性要求的嗎?解決辦法是在圖層初始化的時候讓音效預先載入一次

CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect("pew-pew-lei.wav");

 

關於情境切換 

 覺得這方面沒什麼要說的,該說的網上都有,尤其是nowpaper
這篇文章 ,講得很形象,可以去看看。

SimpleGame裡面的情境切換類,對應是GameOverScene.cpp,該檔案是判斷遊戲結束時,切換到該介面提示使用者失敗或者成功。這裡有一點需要特點注意的是 

  GameOverScene *gameOverScene=GameOverScene::create();

  gameOverScene->getLayer()->getLabel()->setString("you win!!!");
  CCDirector::sharedDirector()->replaceScene(gameOverScene);

 

 上面紅色代碼這塊,比較難懂,這句話可以這麼理解:通過GameOverScene標頭檔中的CC_SYNTHESIZE_READONLY宏定義產生getLayer方法,該方法返回GameOverLayer類型,然後再通過CC_SYNTHESIZE_READONLY 宏定義產生getLabel方法,返回cocos2d::CCLabelTTF類型,最後調用CCLabelTTF成員裡面的setString ,該_label在初始化GameOverLayer的時候就己經this->addChild(_label)
,會不會這樣就相當於傳參數到另一個CCScene呢?呵呵!

宏定義代碼如下:

#define CC_SYNTHESIZE_READONLY(varType, varName, funName)\

protected: varType varName;\

public: virtual varType get##funName(void) const { return varName; }   //這裡組合得到方法名和傳回型別

 

洋洋洒洒的說了那麼一堆,也算是研究出來了,希望大家能夠少走點彎路。

 

源碼可以在cocos2d-x sample 目錄上找到,或者https://github.com/terryyhl/SimpleGame.git 。 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.