cocos2d-xFinalProject踩坑記錄(cocosStudio控件獲取,角色移動及動畫,碰撞檢測,背景音樂與場景)

cocos2d-xFinalProject踩坑記錄數組

不得不吐槽在先,cocos總體框架十分強悍,可是不少細節的東西寫得不夠人性化,並且官方的文檔也沒有跟上,致使浪費大量的時間在一些沒必要要的坑上,實在是不划算,記錄一下此次期末項目用cocos2d-x3.10開發泡泡堂踩到的坑吧!app

1.cocosStudio導出的csb文件組件獲取框架

auto rootNode = CSLoader::createNode("LoginScene/LoginScene.csb");//獲取csb
Layout* background = (Layout*)rootNode->getChildByName("background");//獲取csb上的層
Button* btnMenu = (Button*)Helper::seekWidgetByName(background, "menubutton");//獲取層上的button

注意的是子控件名稱只能使用小寫,若是用大寫的話獲取不到,還不會報錯(Orz,真不知道當時攻城獅是怎麼想的,單步調了好久看地址才發現)函數

坑爹指數:★★★★動畫

2.cocosStudio Button控件的Touch檢測this

範圍是按照你Button圖片來的,因此若是是圓形按鈕,想作得準確,得把圓摳出來設計

坑爹質數:★調試

3.角色移動和動畫播放code

這個打算暑假抽空寫個詳細的專題,角色的位置移動是採用的默認調度器+鍵盤監聽器,每一幀都會檢測按鍵並作出相應的移動,而角色的動畫則是在init裏面另寫了一個函數+鍵盤監聽器,最開始沒想這麼多,二者是合在一塊兒的,可是發現採用調度器放動畫或者函數控制移動都會出現動做不連貫或配合失真,因此無可奈何只能把兩個東西分開寫,再分開調速度,終於實現了。對象

角色位置移動:

//調度器
void MapOfGame::update(float delta) {
    Node::update(delta);
    role1.loadPositon();
    auto upArrow = EventKeyboard::KeyCode::KEY_UP_ARROW,
        downArrow = EventKeyboard::KeyCode::KEY_DOWN_ARROW,
        leftArrow = EventKeyboard::KeyCode::KEY_LEFT_ARROW,
        rightArrow = EventKeyboard::KeyCode::KEY_RIGHT_ARROW;
    if (isKeyPressed(upArrow)) {
        keyPressedMovement(upArrow);
    }
    else if (isKeyPressed(downArrow)) {
        keyPressedMovement(downArrow);
    }
    else if (isKeyPressed(leftArrow)) {
        keyPressedMovement(leftArrow);
    }
    else if (isKeyPressed(rightArrow)) {
        keyPressedMovement(rightArrow);
    }
}

........
  //對應的移動函數
  void MapOfGame::keyPressedMovement(EventKeyboard::KeyCode keyCode) {
    CCPoint moveByPosition;
    RoleDirection tag;
    //you can set move speed here
    switch (keyCode) {
    case EventKeyboard::KeyCode::KEY_UP_ARROW:
        moveByPosition = ccp(0, role1.getSpeed());
        break;
    case EventKeyboard::KeyCode::KEY_DOWN_ARROW:
        moveByPosition = ccp(0, -role1.getSpeed());
        break;
    case EventKeyboard::KeyCode::KEY_LEFT_ARROW:
        moveByPosition = ccp(-role1.getSpeed(), 0);
        break;
    case EventKeyboard::KeyCode::KEY_RIGHT_ARROW:
        moveByPosition = ccp(role1.getSpeed(), 0);
        break;
    default:
        moveByPosition = ccp(0, 0);
        break;
    }
  //建立MoveBy對象並執行移動的動做
    auto move = CCMoveBy::create(0.01f, moveByPosition);
    role1.role->runAction(move);
}

角色移動時的動畫

//這些是在init裏面寫的
    //add keyboard listener
    auto listener = EventListenerKeyboard::create();
    //call responding animation when realted key is pressed
    listener->onKeyPressed = [=](EventKeyboard::KeyCode keyCode, Event *event) {
        keys[keyCode] = true;
        switch (keyCode){
        case EventKeyboard::KeyCode::KEY_UP_ARROW:
            keyPressedAnimation(keyCode);
            break;
        case EventKeyboard::KeyCode::KEY_DOWN_ARROW:
            keyPressedAnimation(keyCode);
            break;
        case EventKeyboard::KeyCode::KEY_LEFT_ARROW:
            keyPressedAnimation(keyCode);
            break;
        case EventKeyboard::KeyCode::KEY_RIGHT_ARROW:
            keyPressedAnimation(keyCode);
            break;
        default:
            break;
    }
};    


.......
  //對應的動畫函數,walkAnimation是以前弄的四個方向序列幀動畫數組
  void MapOfGame::keyPressedAnimation(EventKeyboard::KeyCode keyCode) {
    RoleDirection tag;
    //you can set move speed here
    switch (keyCode) {
    case EventKeyboard::KeyCode::KEY_UP_ARROW:
        tag = kUp;
        break;
    case EventKeyboard::KeyCode::KEY_DOWN_ARROW:
        tag = kDown;
        break;
    case EventKeyboard::KeyCode::KEY_LEFT_ARROW:
        tag = kLeft;
        break;
    case EventKeyboard::KeyCode::KEY_RIGHT_ARROW:
        tag = kRight;
        break;
    default:
        break;
    }
    animations[tag] = RepeatForever::create(CCAnimate::create(walkAnimations[tag]));
    //animations[tag] = CCAnimate::create(walkAnimations[tag]);
    role1.role->runAction(animations[tag]);
}

坑爹指數:★★

4.採用調度器碰撞檢測的注意

個人碰撞檢測的思路是把相關函數在調度器裏每一幀調用一次(實際上和位置移動函數寫在一塊兒的,非法就不會執行移動),保證檢測的及時性,可是卻意外發現單步調試時就沒有問題,一旦運行起來就會出現「慣性過大」衝出碰撞區域後卡住的狀況(此時的座標已經非法了,因此移動不了),耗了幾個小時都沒有檢測出邏輯錯誤,次日睡一覺後忽然發現,個人MoveBy設置的duration是0.28f,也就是說我每一幀的移動動做須要0.28秒來完成,然而我每一秒有60幀,也就是說我若是摁住移動鍵,完成這一秒的移動動做須要60*0.28s,這是不可能了,因此係統可能在執行下一次時直接中斷了上一次duration的過程,形成了碰撞檢測失效,爲了驗證這一猜測,我把每一幀調用的默認調度器scheduleUpdate換成了能夠設置時間間隔的調度器,不廢話,上代碼

//如今調度器就能夠設置時間間隔了
this->schedule(schedule_selector(MapOfGame::update), 0.05f);
//碰撞檢測部分的代碼,和以前貼的移動位置代碼是一個函數
    //collision check
    CCPoint targetPosition = ccpAdd(role1.role->getPosition(), moveByPosition);
    if (checkCollision(targetPosition, tag) == kWall) {
        setFaceDirection(tag);
        return;
    }
    auto move = CCMoveBy::create(0.01f, moveByPosition);
    role1.role->runAction(move);

我把調度器的時間間隔設置了>MoveBy的時間間隔,也就是每一次調度鍵盤監聽和碰撞檢測都能保證上一次移動的過程已經完成,果真,個人角色沒有再出現「慣性過大」衝入非法區域卡住的狀況。

坑爹指數:★★★★★★

5.不一樣場景下背景音樂的切換

在完成碰撞檢測後的上午,我滿心歡喜的覺得提早完成了計劃,想順手牽羊把音效給加上去,在個人設想下一個遊戲引擎放幾個背景音樂應該是再容易不過的事情,然而,cocos蛋疼的設計卻讓這一簡單的設想實現起來變得困難重重。

我採用的是cocos2d-x自帶的音頻組件#include "SimpleAudioEngine.h",而後在每一個場景中調用對應函數播放背景音樂,坑爹的地方來了,好比說個人Scene1和Scene2打算使用不一樣的背景音樂,從前者切換到後者後,背景音樂的播放會中止,後者的音樂只能放幾秒就卡住,在查閱了網上大量的資料後,發現這是cocos2d-x場景切換的特性所致,具體見關東昇的博文:

場景切換與背景音樂

特別須要注意,在這種狀況下,除了須要本身重寫一遍場景生命週期函數外

void MapOfGame::onEnter() {
    Layer::onEnter();
}

void MapOfGame::onEnterTransitionDidFinish() {
    Layer::onEnterTransitionDidFinish();
    //play music
    SimpleAudioEngine::getInstance()->playBackgroundMusic("MusicSource/bg/Village.mp3", true);
    SimpleAudioEngine::getInstance()->playEffect("MusicSource/appear.wav");
}

void MapOfGame::onExit() {
    Layer::onExit();
}

void MapOfGame::onExitTransitionDidStart() {
    Layer::onExitTransitionDidStart();
}

void MapOfGame::cleanup() {
    Layer::cleanup();
}

還要把對應的切換方式設置爲 pushScene,採用repeatScene的話系統會自動調動音樂中止函數,再怎麼弄後面的Scene也出不了聲

void Login::StartGameTouch(Ref* pSender, Widget::TouchEventType type) {
    switch (type) {
    case Widget::TouchEventType::ENDED:
        auto director = Director::getInstance();
        //transfer to MapScene
        auto scene = MapOfGame::createScene();
        auto transition = TransitionCrossFade::create(1.0f, scene);
        SimpleAudioEngine::getInstance()->stopBackgroundMusic();
        director->pushScene(transition);
        break;
    }
}

坑爹指數:★★★★★(真乃神坑,花了我一天就弄一個背景音樂Orz……是我太菜)

相關文章
相關標籤/搜索