Friday, January 23, 2015

Cocos2d-x: Phát triển game Smart Memory (Phần 2)

Xây dựng giao diện với Cocostudio

Ta sử dụng Cocostudio để xây dựng các Scene giao diện cho game

http://kensaistudio.com/?p=82








Xây dựng Game

Main Menu scene

MainMenuScene.h


#include "cocos2d.h"
#include "ui/CocosGUI.h"
#include "network/HttpClient.h"
#include "HttpHelper.h"

using namespace cocos2d;
using namespace ui;
using namespace network;

class MainMenuScene : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();
  
    virtual bool init();
  
    CREATE_FUNC(MainMenuScene);
  
private:
 
    void buttonClick(Ref *sender, Widget::TouchEventType type);

private:
    Button *btnBasic_;
    Button *btnColor_;
    Button *btnCrazy_;
    Button *btnMore_;
    Button *btnHighScore_;
    Button *btnSoundOn_;
    Button *btnSoundOff_;
    Button *btnFacebook_;
    Button *btnLike_;
    LayerColor *layerAlert_;
    Button *btnNoUpdate_;
    Button *btnUpdate_;
};


Ta định nghĩa các Button cho từng “menu” ở trên MainMenuScene, định nghĩa hàm buttonClick để nhận sự kiện click của các Button.

MainMenuScene.m

btnBasic_ = (Button *)sceneLayout->getChildByName("btnBasic");
btnBasic_->addTouchEventListener(CC_CALLBACK_2(MainMenuScene::buttonClick, this));
btnColor_ = (Button *)sceneLayout->getChildByName("btnColor");
btnColor_->addTouchEventListener(CC_CALLBACK_2(MainMenuScene::buttonClick, this));
btnCrazy_ = (Button *)sceneLayout->getChildByName("btnCrazy");
btnCrazy_->addTouchEventListener(CC_CALLBACK_2(MainMenuScene::buttonClick, this));

Định nghĩa hàm buttonClick

void MainMenuScene::buttonClick(Ref *sender, Widget::TouchEventType type)
{
    Node *button = (Node *)sender;
    if (type == Widget::TouchEventType::ENDED) {
        if (button == btnBasic_) {
            GameInfor::setGameMode(GameModeBasic);
            Director::getInstance()->replaceScene(TransitionCrossFade::create(0.5f, (Scene *)InGameScene::createScene()));
        } else if (button == btnColor_) {
            GameInfor::setGameMode(GameModeColor);
            Director::getInstance()->replaceScene(TransitionCrossFade::create(0.5f, (Scene *)InGameScene::createScene()));
        } else if (button == btnCrazy_) {
            GameInfor::setGameMode(GameModeCrazy);
            Director::getInstance()->replaceScene(TransitionCrossFade::create(0.5f, (Scene *)InGameScene::createScene()));
        } else if (button == btnHighScore_) {
            Director::getInstance()->replaceScene(TransitionCrossFade::create(0.5f, (Scene *)HighScoreScene::createScene()));
        }
}

Mỗi button click chúng ta sẽ chuyển scene với hàm replaceScene.

Ingame Scene


 InGameScene.h
#include "cocos2d.h"
#include "ui/CocosGUI.h"
#include "Constant.h"

using namespace cocos2d;
using namespace ui;

class InGameScene : public cocos2d::Layer
{
    typedef struct tagMemory
    {
        int data;
        int color;
    } MemoryInfor;
  
public:
    static cocos2d::Scene* createScene();
  
    virtual bool init();
  
    CREATE_FUNC(InGameScene);

private:
    virtual void onEnter();
    virtual void onExit();
  
    void buttonClick(Ref *sender, Widget::TouchEventType type);
  
    void update(float fDelta);
  
    void prepare();
    void displayUIByMode();
    void next();
    void finishMoving();
    void loseGame(bool byTime);
    void gameOver(float fDelta);
  
    SpriteFrame *createData(int dataIndex, int colorIndex);
private:
    Button          *btnBack_;
    Button          *btnNo_;
    Button          *btnYes_;
    Button          *btnSameFigure_;
    Button          *btnSameColor_;
    Button          *btnSameAll_;
    Button          *btnNoSame_;
  
    Label           *lblTime_;
    Label           *lblScore_;
  
    Vec2            showPosition_;
    int             movingLength_;
    Sprite          *memorySprite1_;
    Sprite          *memorySprite2_;
    Sprite          *currMemorySprite_;
    Sprite          *nextMemorySprite_;
  
    bool            percent_[20] = {false,true,false,false,true,false,false,false,true,false,false,true,false,false,false,true,false,false,true,false};

    int             maxData_;
    int             maxColors_;
    Color3B         colors_[5];
    int             preDataIndex_;
    int             preColorIndex_;
    MemoryInfor     preInfor_;
    MemoryInfor     currInfor_;
  
    GameMode        gameMode_;
    bool            isMoving_;
    int             timeLevel_;
    int             time_;
    float           timeCnt_;
    int             score_;
    int             detalScore_;
    int             correctCnt_;
    int             sameCnt_;
};
InGameScene.m
void InGameScene::prepare()
{
    preDataIndex_   = -1;
    preColorIndex_  = -1;
    preInfor_.data  = -1;
    preInfor_.color = -1;
    maxData_        = 6;
    maxColors_      = 6;
    isMoving_       = false;
    timeLevel_      = 8;
    time_           = timeLevel_;
    score_          = 0;
    timeCnt_        = 0;
    correctCnt_     = 0;
    sameCnt_        = 0;
  
    if (gameMode_ == GameModeBasic) {
        detalScore_ = SCORE_BASIC;
    } else if (gameMode_ == GameModeColor) {
        detalScore_ = SCORE_COLOR;
    } else {
        detalScore_ = SCORE_CRAZY;
    }

    colors_[0]  = Color3B(28, 132, 196);
    colors_[1]  = Color3B(151, 77, 255);
    colors_[2]  = Color3B(255, 98, 0);
    colors_[3]  = Color3B(251, 58, 60);
    colors_[4]  = Color3B(251, 238, 33);
    colors_[5]  = Color3B(150, 248, 3);
}

void InGameScene::displayUIByMode()
{

    if (gameMode_ == GameModeBasic) {
        sprtBg_->setVisible(true);
        sprtQuestBg_->setVisible(false);
        sprtBasicBg_->setVisible(true);
        btnBack_->setVisible(false);
        btnNo_->setVisible(true);
        btnYes_->setVisible(true);
      
        sprtColorBg_->setVisible(false);
        sprtCrazyBg_->setVisible(false);
        sprtQuestCrazyBg_->setVisible(false);
        btnSameFigure_->setVisible(false);
        btnSameColor_->setVisible(false);
        btnSameAll_->setVisible(false);
        btnNoSame_->setVisible(false);
    } else if (gameMode_ == GameModeColor) {
        sprtBg_->setVisible(true);
        sprtQuestBg_->setVisible(true);
        sprtColorBg_->setVisible(true);
        btnBack_->setVisible(false);
        btnNo_->setVisible(true);
        btnYes_->setVisible(true);
      
        sprtBasicBg_->setVisible(false);
        sprtCrazyBg_->setVisible(false);
        sprtQuestCrazyBg_->setVisible(false);
        btnSameFigure_->setVisible(false);
        btnSameColor_->setVisible(false);
        btnSameAll_->setVisible(false);
        btnNoSame_->setVisible(false);
    } else {
        sprtBg_->setVisible(false);
        sprtQuestBg_->setVisible(false);
        btnBack_->setVisible(false);
        btnNo_->setVisible(false);
        btnYes_->setVisible(false);
      
        sprtBasicBg_->setVisible(false);
        sprtColorBg_->setVisible(false);
        sprtCrazyBg_->setVisible(true);
        sprtQuestCrazyBg_->setVisible(true);
        btnSameFigure_->setVisible(true);
        btnSameColor_->setVisible(true);
        btnSameAll_->setVisible(true);
        btnNoSame_->setVisible(true);
    }
  
    this->next();
}

void InGameScene::next()
{
    time_           = timeLevel_;
    lblTime_->setString(std::to_string(time_));
  
    preInfor_.data  = currInfor_.data;
    preInfor_.color = currInfor_.color;
  
    nextMemorySprite_ = memorySprite2_;
    if (currMemorySprite_ == memorySprite2_) {
        nextMemorySprite_ = memorySprite1_;
    }
  
    int ra = rand() % 20;
  
    int nextDataIndex = rand() % maxData_;
    int nextColorIndex = rand() % maxColors_;

    if (GameInfor::getGameMode() == GameModeBasic) {
        nextColorIndex = preInfor_.color;
    }
  
    if (percent_[ra]) {
        if (gameMode_ == GameModeBasic) {
            nextDataIndex = preInfor_.data;
        } else if (gameMode_ == GameModeColor) {
            nextColorIndex = preInfor_.color;
        } else {
            int r2 = rand() % 3;
            if (r2 == 0) {
                nextDataIndex = preInfor_.data;
            } else if (r2 == 1) {
                nextColorIndex = preInfor_.color;
            } else if (r2 == 2) {
                nextDataIndex = preInfor_.data;
                nextColorIndex = preInfor_.color;
            }
        }
      
}
  
    if ((gameMode_ == GameModeBasic && nextDataIndex == preInfor_.data) ||
        (gameMode_ == GameModeColor && nextColorIndex == preInfor_.color) ||
        (gameMode_ == GameModeCrazy && nextDataIndex == preInfor_.data && nextColorIndex == preInfor_.color)) {
        sameCnt_ ++;
      
        if (sameCnt_ == 3) {
            if (gameMode_ == GameModeBasic) {
                nextDataIndex = nextDataIndex + 1 < maxData_ ? (nextDataIndex + 1) : 0;
            } else if (gameMode_ == GameModeColor) {
                nextColorIndex = nextColorIndex + 1 < maxColors_ ? (nextColorIndex + 1) : 0;
            } else {
                nextDataIndex = nextDataIndex + 1 < maxData_ ? (nextDataIndex + 1) : 0;
            }
        }
      
} else {
        sameCnt_ = 0;
    }
  
    currInfor_.data     = nextDataIndex;
    currInfor_.color    = nextColorIndex;
  

    std::string str = "data_" + std::to_string(nextDataIndex) + ".png";
    nextMemorySprite_->setSpriteFrame(str);
    nextMemorySprite_->setColor(colors_[nextColorIndex]);

    isMoving_ = true;
  
    currMemorySprite_->runAction(Sequence::create(MoveTo::create(0.3, Vec2(showPosition_.x - movingLength_, showPosition_.y)), CallFunc::create(CC_CALLBACK_0(InGameScene::finishMoving, this)), NULL));
    nextMemorySprite_->runAction(MoveTo::create(0.3, showPosition_));
}

SpriteFrame *InGameScene::createData(int dataIndex, int colorIndex)
{
    std::string str = "data_" + std::to_string(dataIndex) + ".png";
    Image *loadImage = new Image;
    loadImage->autorelease();
  
    if( loadImage->initWithImageFile(str) )
    {
        //make a color array which is easier to work with
        Color3B srcColor = Color3B(254, 254, 254);
        Color3B dstColor = colors_[colorIndex];
        unsigned long srcC = (srcColor.r << 0) | (srcColor.g << 8) | (srcColor.b << 16);
        unsigned long dstC = (dstColor.r << 0) | (dstColor.g << 8) | (dstColor.b << 16);
      
        unsigned char * rawData = loadImage->getData();
        int width = loadImage->getWidth();
        int height = loadImage->getHeight();
      
        //replace the colors need replacing
        unsigned int * b = (unsigned int *) rawData;
        for( int pixel = 0; pixel < width*height; pixel++ )
        {
            unsigned int p = *b;
            if( (p&0x00FFFFFF) == srcC )
            {
                *b = (int)((p&0xFF000000) | dstC);
            }
          
            b++;
        }
      
        Texture2D *texture = new Texture2D();
        texture->autorelease();
        if (texture->initWithData(rawData, 4*width*height, Texture2D::PixelFormat::RGBA8888, width, height, Size(width, height))) {
            auto sprtFr = SpriteFrame::createWithTexture(texture, Rect(0, 0, width, height));
            return sprtFr;
        }
    }
    return NULL;
}


void InGameScene::finishMoving()
{
    currMemorySprite_->setPosition(Vec2(showPosition_.x + movingLength_, showPosition_.y));
    currMemorySprite_ = nextMemorySprite_;
    isMoving_ = false;
}

void InGameScene::update(float fDelta)
{
    if (preInfor_.data > -1 && !isMoving_) {
        //Playing
        timeCnt_ += fDelta;
        if (timeCnt_ >= 1.0) {
            timeCnt_ -= 1.0;
            time_ --;
            lblTime_->setString(std::to_string(time_));
        }
      
        if (time_ == 0) {
            //GameOver
            preInfor_.data = -1;
            isMoving_ = true;
            this->loseGame(true);
        }
    }
}

void InGameScene::buttonClick(Ref *sender, Widget::TouchEventType type) {
  
    if (isMoving_) {
        return;
    }
  
    Node *button = (Node *) sender;
    if (type == Widget::TouchEventType::ENDED) {
        bool result = false;
      
        if (button == btnYes_) {
            //YES
            if (preInfor_.data < 0) {
                AudioHelper::play(AudioHelper::AudioType::ButtonClick);
                this->displayUIByMode();
                return;
            } else {
                if (gameMode_ == GameModeBasic &&
                    preInfor_.data == currInfor_.data) {
                    result = true;
                } else if (gameMode_ == GameModeColor &&
                           preInfor_.color == currInfor_.color) {
                    result = true;
                }
            }
        } else if (button == btnNo_) {
            if (preInfor_.data > -1) {
                if (gameMode_ == GameModeBasic &&
                    preInfor_.data != currInfor_.data) {
                    result = true;
                } else if (gameMode_ == GameModeColor &&
                           preInfor_.color != currInfor_.color) {
                    result = true;
                }
            } else {
                return;
            }
        } else if (button == btnSameFigure_) {
            //Same Figure
            if (preInfor_.data == currInfor_.data && preInfor_.color != currInfor_.color) {
                result = true;
            }
        } else if (button == btnSameColor_) {
            if (preInfor_.data != currInfor_.data && preInfor_.color == currInfor_.color) {
                result = true;
            }
        } else if (button == btnSameAll_) {
            if (preInfor_.data == currInfor_.data && preInfor_.color == currInfor_.color) {
                result = true;
            }
        } else if (button == btnNoSame_) {
            if (preInfor_.data != currInfor_.data && preInfor_.color != currInfor_.color) {
                result = true;
            }
        }

      
        if (result) {
            AudioHelper::play(AudioHelper::AudioType::Right);
            correctCnt_ ++;
            timeCnt_ = 0;
            if (correctCnt_ == 8) {
                timeLevel_ = 5;
            } else if (correctCnt_ == 16) {
                timeLevel_ = 3;
            } else if (correctCnt_ == 28) {
                if (gameMode_ == GameModeCrazy) {
                    timeLevel_ = 2;
                }
            } else if (correctCnt_ == 40) {
                if (gameMode_ != GameModeCrazy) {
                    timeLevel_ = 1;
                }
            }

            score_ += detalScore_;
            lblScore_->setString(std::to_string(score_));
            this->next();
        } else {
            this->loseGame(false);
        }
    }
}

void InGameScene::loseGame(bool byTime)
{
    AudioHelper::play(AudioHelper::AudioType::Wrong);
    preInfor_.data = -1; //pause loop
    isMoving_ = true; //disable click
  
    Sprite *alert;
    if (byTime) {
        alert = Sprite::create("timeover.png");
    } else {
        alert = Sprite::create("selectwrong.png");
    }
    Vec2 origin = Director::getInstance()->getVisibleOrigin();
    alert->setScale(Director::getInstance()->getContentScaleFactor());
    alert->setPosition(Vec2(currMemorySprite_->getPositionX(), currMemorySprite_->getPositionY() + origin.y * 0.1));
    this->addChild(alert, ZORDER_LAYER_4);
  
    GameInfor::setBestScore(score_);
    this->scheduleOnce(schedule_selector(InGameScene::gameOver), 1.2);
}

void InGameScene::gameOver(float fDelta)
{
    AudioHelper::play(AudioHelper::AudioType::GameOver);
    Director::getInstance()->replaceScene(TransitionCrossFade::create(0.5f, (Scene *)GameOverScene::createScene()));
}

Ta sử dụng các memorySprite1 và memorySprite2 để hiển thị các con vật chuyển qua lại trong màn hình game.
Hàm Next() để quyết định chọn các con vật sẽ tiếp tục hiển thị khi người chơi click button.

GameOver Scene

GameOverScene.h

#include "cocos2d.h"
#include "ui/CocosGUI.h"
#include "network/HttpClient.h"
#include "HttpHelper.h"

using namespace cocos2d;
using namespace ui;
using namespace network;
class GameOverScene : public cocos2d::Layer, public TextFieldDelegate
{
public:
    static cocos2d::Scene* createScene();
  
    virtual bool init();
  
    CREATE_FUNC(GameOverScene);
  
    void onBackKeyClick();
private:
    virtual bool onTouchBegan(Touch *touch, Event *unused_event);
    virtual void onTouchMoved(Touch *touch, Event *unused_event);
    virtual void onTouchEnded(Touch *touch, Event *unused_event);
  
    void buttonClick(Ref *sender, Widget::TouchEventType type);
    virtual bool onTextFieldInsertText(TextFieldTTF * sender, const char * text, size_t nLen);
    virtual bool onTextFieldDeleteBackward(TextFieldTTF * sender, const char * delText, size_t nLen);
  
    void submitScore();
  
private:
    Button *btnQuit_;
    Button *btnRetry_;
    Button *btnFacebook_;
    Button *btnSubmit_;
    TextFieldTTF *txtName_;
    Label        *lblName_;
    Sprite       *txtBg_;
    bool    isSending;
    bool    clicked_;
    int     dy_;
};
Ta sử dụng TextFieldTFF để nhập tên người chơi.

GameOverScene.m

    txtName_ = TextFieldTTF::textFieldWithPlaceHolder("Submit your name", "Arial", 35);
    txtName_->setPosition(txtBg_->getPosition());
    txtName_->setColor(Color3B(111, 58, 255));
    txtName_->setDelegate(this);
    sceneLayout->addChild(txtName_, 100);

<Còn tiếp>

No comments:

Post a Comment