Cocos2d-x:學習筆記(2017.05.12更新)

1.參考鏈接彙總

官方接口文檔

關於Cocos2d-x中addchild和removeChild方法的參數的解析

Cocos2d-x3.2 Menu菜單的創建

cocos 中熟練運用場景的切換

cocos2dx一個場景添加多個層

Cocos2d-x Layer錨點設置

cocos2d-x convertToWorldSpace 和 convertToNodeSpace

cocos2d-x 延遲執行一段代碼1 順序執行動作+延遲動作+CallFunc

Cocos2d-x v3.6製作射箭遊戲(三)

菜鳥學習Cocos2d-x 3.x——淺談動畫

cocos2d-x“無法打開源文件”

cocos2d-x 座標研究

深入理解 cocos2d-x 座標系

Cocos2d-x解析XML文件,解決中文亂碼

Cocos2d-x 通過虛擬按鍵控制人物移動

【平凡曉聲 Cocos2d-x】虛擬按鍵控制精靈移動2

android Drawbitmap 畫一個圖片(Rect 的作用)

C++中數字與字符串之間的轉換

Cocos2d-X中使用ProgressTimer實現一些簡單的效果

菜鳥學習Cocos2d-x 3.x——淺談動作Action

Cocos2dx學習筆記12:cocos2dx進度條(ProgressTimer)

cocos2dx[3.4](25)——瓦片地圖TiledMap

cocos2dx 中 如果一個精靈被擊中了,需要消失,用什麼函數來實現呢?

Cocos2d-x v3.3中UserDefault保存的XML文件位置

2.創建Sprite

auto bg = Sprite::create("level-background-0.jpg");
bg->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));
this->addChild(bg, 0);

使用plist:

    auto spritecache = SpriteFrameCache::getInstance();
    spritecache->addSpriteFramesWithFile("level-sheet.plist");
    mouse = Sprite::createWithSpriteFrameName("gem-mouse-0.png");
    mouse->setPosition(Vec2(origin.x + visibleSize.width / 2, 0));

使用動畫第一幀:

    // 創建一張貼圖
    auto texture = Director::getInstance()->getTextureCache()->addImage("$lucia_2.png");
    // 從貼圖中以像素單位切割,創建關鍵幀
    auto frame0 = SpriteFrame::createWithTexture(texture, CC_RECT_PIXELS_TO_POINTS(Rect(0, 0, 113, 113)));
    // 使用第一幀創建精靈
    player = Sprite::createWithSpriteFrame(frame0);
    player->setPosition(Vec2(origin.x + visibleSize.width / 2,
                            origin.y + visibleSize.height/2));
    addChild(player, 3);

3.創建MenuItem

auto closeItem = MenuItemImage::create(
                                       "CloseNormal.png",
                                       "CloseSelected.png",
                                       CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));

closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
                            origin.y + closeItem->getContentSize().height/2));
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 1);
void HelloWorld::menuCloseCallback(Ref* pSender)
{
   Director::getInstance()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}

4.創建Layer

stoneLayer = Layer::create();
stoneLayer->setPosition(Vec2(0, 0));
stoneLayer->setAnchorPoint(Vec2(0, 0));
stoneLayer->ignoreAnchorPointForPosition(false);
stoneLayer->addChild(stone);


mouseLayer = Layer::create();
mouseLayer->setPosition(Vec2(0, origin.y + visibleSize.height / 2));
mouseLayer->setAnchorPoint(Vec2(0, 0));
mouseLayer->ignoreAnchorPointForPosition(false);
mouseLayer->addChild(mouse);

this->addChild(stoneLayer, 1);
this->addChild(mouseLayer, 1);

5.顯示中文字符

    CCDictionary* message = CCDictionary::createWithContentsOfFile("Chinese.xml");
    auto nameKey = message->valueForKey("Name");
    const char* Name = nameKey->getCString();
    auto IDKey = message->valueForKey("ID");
    const char* ID = IDKey->getCString();
    auto label = Label::createWithTTF(Name, "fonts/FZSTK.ttf", 24);
    auto label1 = Label::createWithTTF(ID, "fonts/Marker Felt.ttf", 24);
    // position the label on the center of the screen
    label->setPosition(Vec2(origin.x + visibleSize.width/2,
                            origin.y + visibleSize.height - label->getContentSize().height));
    label1->setPosition(Vec2(origin.x + visibleSize.width / 2,
                            origin.y + visibleSize.height
                             - label->getContentSize().height-label1->getContentSize().height));
<?xml version="1.0" encoding="UTF-8"?>

<dict>

<key>Name</key>

<string>名字</string>

<key>ID</key>

<string>學號</string>

</dict>

6. 播放背景英語

#include <SimpleAudioEngine.h>
#define MUSIC_FILE "666.mp3"

以下是menuItem的觸發函數,點擊一下播放音樂,再點擊一下停止音樂

void HelloWorld::display_music(Ref* pSender) {
    CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadBackgroundMusic(MUSIC_FILE);
    CocosDenshion::SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(0.5);
    if (count % 2 == 0)
      CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic(MUSIC_FILE, true);
    else
      CocosDenshion::SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();
    count++;
}

7.定義動畫(使用plist)

在AppDelegate.cpp中,

SpriteFrameCache::getInstance()->addSpriteFramesWithFile("level-sheet.plist");
char _totalFrames = 7;
char _frameName[40];
Animation* diamondAnimation = Animation::create();

for (int i = 0; i < _totalFrames; i++) {
    sprintf(_frameName, "pulled-diamond-%d.png", i);
    diamondAnimation->addSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(_frameName));
}
diamondAnimation->setDelayPerUnit(0.1);
AnimationCache::getInstance()->addAnimation(diamondAnimation, "diamondAnimation");

在GameSence.cpp中,

Animate* diamondAnimate = Animate::create(AnimationCache::getInstance()->getAnimation("diamondAnimation"));
diamond->runAction(RepeatForever::create(diamondAnimate));

通過texture定義動畫:

// 定義存儲動畫幀的vector
cocos2d::Vector<SpriteFrame*> attack;
// 創建一張貼圖
auto texture = Director::getInstance()->getTextureCache()->addImage("$lucia_2.png");
// 攻擊動畫
attack.reserve(17);
for (int i = 0; i < 17; i++) {
    auto frame = SpriteFrame::createWithTexture(texture, CC_RECT_PIXELS_TO_POINTS(Rect(113*i,0,113,113)));
    attack.pushBack(frame);
}
auto attack_animation = Animation::createWithSpriteFrames(attack, 0.1f);
attack_animation->setRestoreOriginalFrame(true);
AnimationCache::getInstance()->addAnimation(attack_animation, "attackAnimation");

8.觸摸監聽器

EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = CC_CALLBACK_2(GameSence::onTouchBegan, this);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);
bool GameSence::onTouchBegan(Touch *touch, Event *unused_event) {}

9.獲得visibleSize與origin

Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();

10.設置錨點

mouseLayer->setAnchorPoint(Vec2(0, 0));
mouseLayer->ignoreAnchorPointForPosition(false);

11.MoveTo使用

auto moveTo = MoveTo::create(2, mouseLayer->convertToNodeSpace(location));
mouse->runAction(moveTo);

12.世界座標系與本地座標系的轉換

auto location = mouse->getPosition();
location = mouseLayer->convertToWorldSpace(location);
auto moveTo = MoveTo::create(1, stoneLayer->convertToNodeSpace(location));
stone->runAction(moveTo);

13.延遲函數的實現(異步操作)

auto _delayTime = DelayTime::create(0.5);
auto _func = CallFunc::create([this]() {
    stoneLayer->removeChild(stone);
    stone = Sprite::create("stone.png");
    stone->setPosition(Vec2(560, 480));
    stoneLayer->addChild(stone);
});
auto _seq = Sequence::create(_delayTime, _func, NULL);
this->runAction(_seq);

14.設置背景

// 設置背景
auto bg = Sprite::create("background.jpg");
bg->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));
this->addChild(bg, 0);

使用TileMap

// 設置背景
TMXTiledMap* tmx = TMXTiledMap::create("map.tmx");
tmx->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));
tmx->setAnchorPoint(Vec2(0.5, 0.5));
tmx->setScale(Director::getInstance()->getContentScaleFactor());
this->addChild(tmx, 0);

15.創建倒計時

// 創建倒計時
time = Label::createWithTTF("120", "fonts/arial.ttf", 36);
time->setPosition(Vec2(origin.x+visibleSize.width/2, origin.y+visibleSize.height-30));
this->addChild(time);
schedule(schedule_selector(HelloWorld::updateTime), 1);
dtime = 120;
// 事件更新函數
void HelloWorld::updateTime(float delta) {
    dtime--;
    if (dtime < 0) dtime = 0;
    char str[10];
    sprintf(str, "%d", dtime); // 將int類型轉化爲字符串char*類型
    time->setString(str);
}

16.遊戲的hp條

// 進度條定義
cocos2d::ProgressTimer* pT;
// hp條
Sprite* sp0 = Sprite::create("hp.png", CC_RECT_PIXELS_TO_POINTS(Rect(0, 320, 420, 47))); // 進度條框
Sprite* sp = Sprite::create("hp.png", CC_RECT_PIXELS_TO_POINTS(Rect(610, 362, 4, 16))); // 進度條

// 使用hp條設置progressBar
pT = ProgressTimer::create(sp);
pT->setScaleX(90);
pT->setAnchorPoint(Vec2(0, 0));
pT->setType(ProgressTimerType::BAR); // 定義進度條類型
pT->setBarChangeRate(Point(1, 0));
pT->setMidpoint(Point(0, 1));
pT->setPercentage(100);
pT->setPosition(Vec2(origin.x+14*pT->getContentSize().width,origin.y + visibleSize.height - 2*pT->getContentSize().height));
addChild(pT,1);
sp0->setAnchorPoint(Vec2(0, 0));
sp0->setPosition(Vec2(origin.x + pT->getContentSize().width, origin.y + visibleSize.height - sp0->getContentSize().height));
addChild(sp0,0);

17.遊戲方向鍵WSAD定義

// 方向鍵
auto buttonW = Button::create("W.png", "W.png");
auto buttonS = Button::create("S.png", "S.png");
auto buttonA = Button::create("A.png", "A.png");
auto buttonD = Button::create("D.png", "D.png");
buttonW->setPosition(Vec2(origin.x + 60, origin.y + 60));
buttonS->setPosition(Vec2(origin.x + 60, origin.y + 20));
buttonA->setPosition(Vec2(origin.x + 20, origin.y + 20));
buttonD->setPosition(Vec2(origin.x + 100, origin.y + 20));

// W鍵事件處理函數
buttonW->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
    switch (type) {
    case ui::Widget::TouchEventType::BEGAN:
        schedule(schedule_selector(HelloWorld::moveW), 0.3f);
        break;
    case ui::Widget::TouchEventType::ENDED:
        unschedule(schedule_selector(HelloWorld::moveW));
        break;
    }
});

// S鍵事件處理函數
buttonS->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
    switch (type) {
    case ui::Widget::TouchEventType::BEGAN:
        schedule(schedule_selector(HelloWorld::moveS), 0.3f);
        break;
    case ui::Widget::TouchEventType::ENDED:
        unschedule(schedule_selector(HelloWorld::moveS));
        break;
    }
});

// A鍵事件處理函數
buttonA->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
    switch (type) {
    case ui::Widget::TouchEventType::BEGAN:
        schedule(schedule_selector(HelloWorld::moveA), 0.3f);
        break;
    case ui::Widget::TouchEventType::ENDED:
        unschedule(schedule_selector(HelloWorld::moveA));
        break;
    }
});

// D鍵事件處理函數
buttonD->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
    switch (type) {
    case ui::Widget::TouchEventType::BEGAN:
        schedule(schedule_selector(HelloWorld::moveD), 0.3f);
        break;
    case ui::Widget::TouchEventType::ENDED:
        unschedule(schedule_selector(HelloWorld::moveD));
        break;
    }
});

this->addChild(buttonW);
this->addChild(buttonS);
this->addChild(buttonA);
this->addChild(buttonD);

// 方向鍵D的移動
void HelloWorld::moveD(float dt) {
//auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),
    //                                      MoveBy::create(0.15f, Vec2(10, 0)));
auto location = player->getPosition();
if (location.x + 20 >= visibleSize.width) {
    auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(visibleSize.width-location.x-10, 0)),
        Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
    player->runAction(seq);
    return;
}
auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(20, 0)),
    Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
player->runAction(seq);
}

// 方向鍵A的移動
void HelloWorld::moveA(float dt) {
//auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),
    //MoveBy::create(0.15f, Vec2(-10, 0)));
auto location = player->getPosition();
if (location.x - 20 <= 0) {
    auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(-location.x+10, 0)),
        Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
    player->runAction(seq);
    return;
}
auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(-20, 0)),
    Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
player->runAction(seq);
}

// 方向鍵W的移動
void HelloWorld::moveW(float dt) {
//auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),
    //MoveBy::create(0.15f, Vec2(0, 10)));
auto location = player->getPosition();
if (location.y + 20 >= visibleSize.height) {
    auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, visibleSize.height-location.y-10)),
        Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
    player->runAction(seq);
    return;
}
auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, 20)),
    Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
player->runAction(seq);
}

// 方向鍵S的移動
void HelloWorld::moveS(float dt) {
//auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),
    //MoveBy::create(0.15f, Vec2(0, -10)));
auto location = player->getPosition();
if (location.y - 20 <= 0) {
    auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, -location.y+10)),
        Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
    player->runAction(seq);
    return;
}
auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, -20)),
    Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));
player->runAction(seq);
}

上面的按鈕實現的是點擊按鈕移動,鬆開按鈕停止移動。但是這種實現可能會有bug,莫名其妙人物就不受控制了。所以我將之改爲點擊一下移動一下,即鬆開鼠標按鈕後人物纔會移動:

// 方向鍵D的移動

void HelloWorld::moveD(float dt) {

    //auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),

        //                                      MoveBy::create(0.15f, Vec2(10, 0)));

    player->setFlipX(false);

    auto location = player->getPosition();

    if (location.x + 20 >= visibleSize.width) {

        //auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(visibleSize.width-location.x-10, 0)),

            //Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

        //player->runAction(seq);

        player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

        player->runAction(MoveBy::create(0.6f, Vec2(visibleSize.width - location.x - 10, 0)));

        return;

    }

    //auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(20, 0)),

        //Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

    //player->runAction(seq);

    player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

    player->runAction(MoveBy::create(0.6f, Vec2(20, 0)));

}



// 方向鍵A的移動

void HelloWorld::moveA(float dt) {

    //auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),

        //MoveBy::create(0.15f, Vec2(-10, 0)));

    player->setFlipX(true);

    auto location = player->getPosition();

    if (location.x - 20 <= 0) {

        //auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(-location.x+10, 0)),

            //Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

        //player->runAction(seq);

        player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

        player->runAction(MoveBy::create(0.6f, Vec2(-location.x + 10, 0)));

        return;

    }

    //auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(-20, 0)),

        //Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

    //player->runAction(seq);

    player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

    player->runAction(MoveBy::create(0.6f, Vec2(-20, 0)));

}



// 方向鍵W的移動

void HelloWorld::moveW(float dt) {

    //auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),

        //MoveBy::create(0.15f, Vec2(0, 10)));

    auto location = player->getPosition();

    if (location.y + 20 >= visibleSize.height) {

        //auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, visibleSize.height-location.y-10)),

            //Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

        //player->runAction(seq);

        player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

        player->runAction(MoveBy::create(0.6f, Vec2(0, visibleSize.height - location.y - 10)));

        return;

    }

    //auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, 20)),

        //Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

    //player->runAction(seq);

    player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

    player->runAction(MoveBy::create(0.6f, Vec2(0, 20)));

}



// 方向鍵S的移動

void HelloWorld::moveS(float dt) {

    //auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")),

        //MoveBy::create(0.15f, Vec2(0, -10)));

    auto location = player->getPosition();

    if (location.y - 20 <= 0) {

        //auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, -location.y+10)),

            //Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

        //player->runAction(seq);

        player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

        player->runAction(MoveBy::create(0.6f, Vec2(0, -location.y + 10)));

        return;

    }

    //auto seq = Sequence::createWithTwoActions(MoveBy::create(0.6f, Vec2(0, -20)),

        //Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

    //player->runAction(seq);

    player->runAction(Animate::create(AnimationCache::getInstance()->getAnimation("runAnimation")));

    player->runAction(MoveBy::create(0.6f, Vec2(0, -20)));

}

18.實現動畫Animation的回調函數

auto callFunc = CallFunc::create([&] {isDone = true; });
auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("attackAnimation")),
    callFunc);

19.通過互斥鎖避免動畫重疊進行

(1)首先我在類中新添加一個isDone成員,當isDone爲false時,說明player正在執行動畫;當isDone爲true時,說明player已經執行完動畫;

(2)將isDone初始爲true,即可執行狀態;

(3)在X、Y的點擊事件處理函數的開始部分(在執行動畫之前),添加一個條件判斷,判斷isDone是否爲true。如果爲true,則繼續執行下面的代碼,如果爲false,則return函數;

(4)然後利用Sequence的createTwoAction來實現動畫完成後的回調函數,回調函數的功能就是將isDone的值賦爲true。

    // 技能鍵X的事件處理函數
    buttonX->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
        switch (type) {
        case ui::Widget::TouchEventType::BEGAN:
            break;
        case ui::Widget::TouchEventType::ENDED:
            if (isDone == false) return; // 動畫未完成,不能執行新動畫
            else isDone = false; // 開始執行動畫
            if (pT->getPercentage() == 0) return; // 進度條爲0時不可再執行該動畫
            auto callFunc = CallFunc::create([&] {isDone = true; }); // 定義動畫執行完畢的回調函數
            /*Animate* deadAnimation = Animate::create(AnimationCache::getInstance()->getAnimation("deadAnimation"));
            auto action = Sequence::create(callFunc);*/
            auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("deadAnimation")),
                callFunc);
            player->runAction(seq);
            //player->runAction(deadAnimation);
            if (pT->getPercentage() - 40 >= 0) { // 每次X操作減少進度條40
                pT->setPercentage(pT->getPercentage() - 40);
            }
            else {
                pT->setPercentage(0);
            }
            break;
        }
    });

    // 技能鍵Y的事件處理函數
    buttonY->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
        switch (type) {
        case ui::Widget::TouchEventType::BEGAN:
            break;
        case ui::Widget::TouchEventType::ENDED:
            if (isDone == false) return;
            else isDone = false;
            /*Animate* attackAnimation = Animate::create(AnimationCache::getInstance()->getAnimation("attackAnimation"));
            player->runAction(attackAnimation);*/
            auto callFunc = CallFunc::create([&] {isDone = true; });
            auto seq = Sequence::createWithTwoActions(Animate::create(AnimationCache::getInstance()->getAnimation("attackAnimation")),
                callFunc);
            player->runAction(seq);
            if (pT->getPercentage() + 40 <= 100) {
                pT->setPercentage(pT->getPercentage() + 40);
            }
            else {
                pT->setPercentage(100);
            }
            break;
        }
    });
    this->addChild(buttonX);
    this->addChild(buttonY);
    return true;
}

20.自定義調度器

switch (type) {
case ui::Widget::TouchEventType::BEGAN:
    schedule(schedule_selector(HelloWorld::moveS), 0.3f);
    break;
case ui::Widget::TouchEventType::ENDED:
    unschedule(schedule_selector(HelloWorld::moveS));
    break;

21.Lambada函數

buttonA->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
        switch (type) {
        case ui::Widget::TouchEventType::BEGAN:
            schedule(schedule_selector(HelloWorld::moveA), 0.3f);
            break;
        case ui::Widget::TouchEventType::ENDED:
            unschedule(schedule_selector(HelloWorld::moveA));
            break;
        }
    });

22. 單例模式示例

class Factory:public cocos2d::Ref {
public:
    //獲取單例工廠
    static Factory* getInstance();
    //生成一個怪物,並存儲到容器中管理
    Sprite* createMonster();
    //讓容器中的所有怪物都往角色移動,通過容器管理所有的怪物很方便
    void moveMonster(Vec2 playerPos,float time);
    //移除怪物
    void removeMonster(Sprite*);
    //判斷碰撞
    Sprite* collider(Rect rect);
    //初始化怪物幀動畫
    void initSpriteFrame();
private:
    Factory();
    Vector<Sprite*> monster;
    cocos2d::Vector<SpriteFrame*> monsterDead;
    static Factory* factory;
};
// Monster.cpp
Factory* Factory::factory = NULL;
Factory::Factory() {
    initSpriteFrame();
}
// 獲取單例
Factory* Factory::getInstance() {
    if (factory == NULL) {
        factory = new Factory();
    }
    return factory;
}

// 生成monster死亡的動畫幀並存入到vector數組中
void Factory::initSpriteFrame() {
    auto texture = Director::getInstance()->getTextureCache()->addImage("Monster.png");
    monsterDead.reserve(4);
    for (int i = 0; i < 4; i++) {
        auto frame = SpriteFrame::createWithTexture(texture, CC_RECT_PIXELS_TO_POINTS(Rect(258 - 48 * i, 0, 42, 42)));
        monsterDead.pushBack(frame);
    }
    // 將這個動畫加入到AnimationCache中
    auto monsterdead_animation = Animation::createWithSpriteFrames(monsterDead, 0.1f);
    AnimationCache::getInstance()->addAnimation(monsterdead_animation, "monsterDeadAnimation");
}

// 新建一個monster
Sprite* Factory::createMonster() {
    Sprite* mons = Sprite::create("Monster.png", CC_RECT_PIXELS_TO_POINTS(Rect(364,0,42,42)));
    monster.pushBack(mons);
    return mons;
}

// 遍歷刪除與參數一致的monster
void Factory::removeMonster(Sprite* sp) {
   cocos2d:Vector<Sprite*>::iterator it = monster.begin();
    for (; it != monster.end(); it++) {
        if (*it == sp) {
            monster.erase(it);
            return;
        }
    }
}

// 實現monster朝着player的方向移動
void Factory::moveMonster(Vec2 playerPos,float time){
    cocos2d:Vector<Sprite*>::iterator it = monster.begin();
    for (; it != monster.end(); it++) {
        Vec2 monsterPos = (*it)->getPosition();
        Vec2 direction = playerPos - monsterPos;
        direction.normalize(); // 得到該向量的單位向量,即向量除以向量的模
        (*it)->runAction(MoveBy::create(time, direction*30));
    }
}
// 當monster在rect的範圍內時,返回指向該monster的指針
Sprite* Factory::collider(Rect rect) {
    cocos2d:Vector<Sprite*>::iterator it = monster.begin();
    for (; it != monster.end(); it++) {
        Vec2 monsterPos = (*it)->getPosition();
        if (rect.containsPoint(monsterPos)) {
            return (*it);
        }
    }
    return NULL;
}

23.Monster朝Player方向移動

// 實現monster朝着player的方向移動
void Factory::moveMonster(Vec2 playerPos,float time){
    cocos2d:Vector<Sprite*>::iterator it = monster.begin();
    for (; it != monster.end(); it++) {
        Vec2 monsterPos = (*it)->getPosition();
        Vec2 direction = playerPos - monsterPos;
        direction.normalize(); // 得到該向量的單位向量,即向量除以向量的模
        (*it)->runAction(MoveBy::create(time, direction*30));
    }
}

24.碰撞檢測

// 當monster在rect的範圍內時,返回指向該monster的指針
Sprite* Factory::collider(Rect rect) {
    cocos2d:Vector<Sprite*>::iterator it = monster.begin();
    for (; it != monster.end(); it++) {
        Vec2 monsterPos = (*it)->getPosition();
        if (rect.containsPoint(monsterPos)) {
            return (*it);
        }
    }
    return NULL;
}

// 檢測碰撞
// getBoundingBox()用於獲取精靈外框區域
void HelloWorld::detectHit(float delta) {
    auto factory = Factory::getInstance();
    Sprite* collision = factory->collider(player->getBoundingBox());
    if (collision != NULL) {
        buttonX();
        Animate* monsterDead = Animate::create(AnimationCache::getInstance()->getAnimation("monsterDeadAnimation"));
        collision->runAction(monsterDead);
        //collision->setVisible(false);
        // 碰到人物後怪物消失
        CCActionInterval* fadeout = CCFadeOut::create(2);
        collision->runAction(fadeout);
        factory->removeMonster(collision);
    }
}

25.生成處於隨機位置的精靈

// 生成怪物
void HelloWorld::createMonster(float delta) {
    auto factory = Factory::getInstance();
    auto monster = factory->createMonster();
    monster->setPosition(random(origin.x, origin.x + visibleSize.width), random(origin.y, origin.y + visibleSize.height));
    this->addChild(monster, 3);
    factory->moveMonster(player->getPosition(), 5);
}

26.同步實現兩個動畫

// collision 是一個精靈對象
    Animate* monsterDead = Animate::create(AnimationCache::getInstance()->getAnimation("monsterDeadAnimation"));
    collision->runAction(monsterDead);
    //collision->setVisible(false);
    // 碰到人物後怪物消失
    CCActionInterval* fadeout = CCFadeOut::create(2);
    collision->runAction(fadeout);

27. 精靈的翻轉

player->setFlipX(true);
player->setFlipX(false);

28. 增加player左右各40的攻擊範圍

    Rect playerRect = player->getBoundingBox();
    Rect attackRect = Rect(playerRect.getMinX() - 40, playerRect.getMinY(),
                           playerRect.getMaxX() - playerRect.getMinX() + 80,
                           playerRect.getMaxY() - playerRect.getMinY());

Rect 的第一二個參數爲左下角的x,y座標,第三個參數爲寬,第四個參數爲高。

29. 漸漸淡出消失的動畫

    CCActionInterval* fadeout = CCFadeOut::create(2);
    collision->runAction(fadeout);
    factory->removeMonster(collision);

30. 本地存儲UserDefault

# define database UserDefault::getInstance()
database->setIntegerForKey("killNum", dtime);
// 當set完後,數據不會馬上保存到XML文件中。所以一定要記得用flush()來保存數據,否則會丟失
database->flush();
// 查詢xml存放的路徑
log("%s", FileUtils::getInstance()->getWritablePath().c_str());

31. HttpClient

POST請求

HttpRequest* request = new HttpRequest();
request->setUrl("http://localhost:8080/login");
request->setRequestType(HttpRequest::Type::POST);
request->setResponseCallback(CC_CALLBACK_2(LoginScene::onHttpRequestComplete, this));
request->setTag("POST test");
String str = "username=" + textField->getString();
const char* postData = str.getCString();
request->setRequestData(postData, strlen(postData));
cocos2d::network::HttpClient::getInstance()->send(request);
request->release();

void LoginScene::onHttpRequestComplete(HttpClient *sender, HttpResponse *response) {
    if (!response) {
        return;
    }
    if (!response->isSucceed()) {
        log("response fail!");
        log("error buffer:%s", response->getErrorBuffer());
        return;
    }
    std::vector<char> *buffer = response->getResponseData();
    printf("Http Text, dump data: ");
    for (unsigned int i = 0; i < buffer->size(); i++) {
        printf("%c", (*buffer)[i]);
    }
    printf("\n");
    string head = "";
    std::vector<char> *header = response->getResponseHeader();
    for (unsigned int i = 0; i < header->size(); i++) {
        head += (*header)[i];
    }
    // 在登錄請求完畢後,獲取該用戶的gameSessionId
    Global::gameSessionId = Global::getSessionIdFromHeader(head);
    UserDefault* default = UserDefault::getInstance();
    default->setStringForKey("Me", Global::gameSessionId);
}

GET請求

HttpRequest* request = new HttpRequest();
string str = "http://localhost:8080/rank?top=" + rank_str;
request->setUrl(str.c_str());
request->setRequestType(HttpRequest::Type::GET);
request->setTag("GET test");
vector<string> headers;
headers.push_back("Cookie: GAMESESSIONID=" + Global::gameSessionId);
request->setHeaders(headers);
request->setResponseCallback(CC_CALLBACK_2(GameScene::onHttpRequestComplete1, this));
cocos2d::network::HttpClient::getInstance()->send(request);
request->release();

// rank的請求完成函數
void GameScene::onHttpRequestComplete1(HttpClient *sender, HttpResponse *response) {
    if (!response) {
        return;
    }
    if (!response->isSucceed()) {
        log("response fail!");
        log("error buffer:%s", response->getErrorBuffer());
        return;
    }
    std::vector<char> *buffer = response->getResponseData();
    printf("Http Text, dump data: ");
    string str;
    for (unsigned int i = 0; i < buffer->size(); i++) {
        printf("%c", (*buffer)[i]);
        str += (*buffer)[i];
    }
    printf("\n");
    // rank_field->setString(str);

    // 對返回的json進行解析
    rapidjson::Document d;
    d.Parse<0>(str.c_str());
    string info = d["info"].GetString();
    str = "";
    for (unsigned int i = 1; i < info.size(); i++) {
        if (info[i] != '|') {
            str += info[i];
        }
        else {
            str += "\n";
        }
    }
    rank_field->setString(str);
}

32. 實現自動化登錄

從createScene函數中開刀:

Scene* LoginScene::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();
    Global::gameSessionId = UserDefault::getInstance()->getStringForKey("Me");
    if (Global::gameSessionId != "") {
        auto layer = GameScene::create();
        scene->addChild(layer);
    }
    else {
        // 'layer' is an autorelease object
        auto layer = LoginScene::create();
        // add layer as a child to scene
        scene->addChild(layer);
    }

    // return the scene
    return scene;
}

33.頁面跳轉

以跳轉GameScene頁面爲例:

// 頁面跳轉
auto sc = GameScene::createScene();
Director::getInstance()->pushScene(sc);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章