「#Cocos2d-x」タグアーカイブ

【COCOS2D-X】クエストリストをスクロールしすぎないように調整する。

https://github.com/takishita2nd/cocos2d-x_sample

こんなかんじになりました。

今回はスクロール処理にもう少し手を加えて、

スクロールしすぎないようにストッパ処理を追加しました。

    if(questListMenu.isShow)
    {
        // Yの差分だけメニューを動かす
        float divY = touch->getLocation().y - keepPosition.y;
        auto visibleSize = Director::getInstance()->getVisibleSize();
        Vec2 origin = Director::getInstance()->getVisibleOrigin();

        if(questListMenu.questListMenu[0].parts.point.y - questListMenu.questListMenu[0].parts.size.height + divY < visibleSize.height)
        {
            for(int i = 0; i < QUEST_NUM; i++)
            {
                questListMenu.questListMenu[i].parts.point = Vec2(questListMenu.parts.point.x, questListMenu.parts.point.y - questListMenu.questListMenu->parts.sprite->getContentSize().height * (i + 1));
                questListMenu.questListMenu[i].parts.sprite->setPosition(questListMenu.questListMenu[i].parts.point);
                questListMenu.questListMenu[i].questName.point = Vec2(questListMenu.questListMenu[i].parts.point.x + questListMenu.questListMenu[i].parts.size.width / 30.0, questListMenu.questListMenu[i].parts.point.y);
                questListMenu.questListMenu[i].questName.label->setPosition(questListMenu.questListMenu[i].questName.point);
            }
        }
        else if(questListMenu.questListMenu[QUEST_NUM - 1].parts.point.y + divY >= origin.y)
        {
            int listcount = 0;
            for(int i = QUEST_NUM - 1; i <= 0; i--)
            {
                questListMenu.questListMenu[QUEST_NUM - 1].parts.sprite->setPosition(questListMenu.questListMenu[i].parts.point.x, questListMenu.questListMenu[0].parts.point.y * listcount + origin.y);
                questListMenu.questListMenu[QUEST_NUM - 1].parts.point.y = questListMenu.questListMenu[0].parts.point.y * listcount + origin.y;
                questListMenu.questListMenu[QUEST_NUM - 1].questName.label->setPosition(questListMenu.questListMenu[i].questName.point.x, questListMenu.questListMenu[0].parts.point.y * listcount + origin.y);
                questListMenu.questListMenu[QUEST_NUM - 1].questName.point.y = questListMenu.questListMenu[0].parts.point.y * listcount + origin.y;
                listcount++;
            }
        }
        else
        {
            for(int i = 0; i < QUEST_NUM; i++)
            {
                questListMenu.questListMenu[i].parts.sprite->setPosition(questListMenu.questListMenu[i].parts.point.x, questListMenu.questListMenu[i].parts.point.y + divY);
                questListMenu.questListMenu[i].parts.point.y = questListMenu.questListMenu[i].parts.point.y + divY;
                questListMenu.questListMenu[i].questName.label->setPosition(questListMenu.questListMenu[i].questName.point.x, questListMenu.questListMenu[i].questName.point.y + divY);
                questListMenu.questListMenu[i].questName.point.y = questListMenu.questListMenu[i].questName.point.y + divY;
            }
        }

        keepPosition.y += divY;
    }

考え方としては、

リストの先頭が画面上部のサイズから下に移動しそうなときは初期位置に設定する、

リストの最後が画面の下から上にいs¥どうしそうなときは下からリストを並べる、

といった感じです。

じゃあ、次はタップで選択処理だな。

【COCOS2D-X】クエストリストをスクロールさせてみる。

こんな感じになりました。

今まではタッチしたときの処理のみを実装していましたが、

タッチ処理のイベントハンドラは三つありまして、

    // タッチアニメーション
    auto listener1 = EventListenerTouchOneByOne::create();
    listener1->onTouchBegan = CC_CALLBACK_2(HomeScene::onTouchBegan, this);
    listener1->onTouchMoved = CC_CALLBACK_2(HomeScene::onTouchMoved, this);
    listener1->onTouchEnded = CC_CALLBACK_2(HomeScene::onTouchEnded, this);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, this);

onTouchBeganはタッチ開始の処理、

onTouchMovedはタッチ中に動かしたとき、

onTouchEndedは画面から指をリリースときに動作します。

まずは、タッチ処理とスライド処理を分ける必要があるので、

タッチ判定は、タッチ時とリリース時のポジションが同じパーツならばタッチと判定します。

なぜ変更する必要があるのかというと、タッチ開始時に判定しちゃうとスライドの判定ができないのでリリース時にタッチ判定をする必要があります。

これはとりあえず仮の処理です。後で変えるかもしれません。

今回重要なのはスクロール処理。

タッチ開始時にその位置を記憶しておきます。


    if(questListMenu.isShow)
    {
        keepPosition = touch->getLocation();
    }

そして、指移動処理で、移動前と移動後の位置の差分をとり、その分だけパーツを移動させます。

void HomeScene::onTouchMoved(cocos2d::Touch *touch, cocos2d::Event *event)
{
    log("move(%f, %f)", touch->getLocation().x, touch->getLocation().y);

    if(questListMenu.isShow)
    {
        // Yの差分だけメニューを動かす
        float divY = touch->getLocation().y - keepPosition.y;
        for(int i = 0; i < QUEST_NUM; i++)
        {
            questListMenu.questListMenu[i].parts.sprite->setPosition(questListMenu.questListMenu[i].parts.point.x, questListMenu.questListMenu[i].parts.point.y + divY);
            questListMenu.questListMenu[i].parts.point.y = questListMenu.questListMenu[i].parts.point.y + divY;
            questListMenu.questListMenu[i].questName.label->setPosition(questListMenu.questListMenu[i].questName.point.x, questListMenu.questListMenu[i].questName.point.y + divY);
            questListMenu.questListMenu[i].questName.point.y = questListMenu.questListMenu[i].questName.point.y + divY;
        }
        keepPosition.y += divY;
    }
}

思った以上に滑らかなスクロールができました。

「これ以上スクロールさせない」といった処理も必要になりますが、

まぁ、今回はこれで良いでしょう。

【COCOS2D-X】クエストリストの作成を作ってみた。

こんな感じ。

    if(isTouch(touch->getLocation(), &(questButton.parts)))
    {
        auto questList = getQuestList();
        auto questName = questList->begin();
        for(int i = 0; i < questList->size(); i++)
        {
            log("loop");
            questListMenu.questListMenu[i].parts.sprite = Sprite::create("btn02_03_s_bl.png");
            questListMenu.questListMenu[i].parts.sprite->setAnchorPoint(Vec2(0.0, 0.0));
            questListMenu.questListMenu[i].parts.size = Size(questListMenu.questListMenu->parts.sprite->getContentSize().width * questListMenu.scaleRate,
                                                           questListMenu.questListMenu->parts.sprite->getContentSize().height);
            questListMenu.questListMenu[i].parts.point = Vec2(questListMenu.parts.point.x, questListMenu.parts.point.y - questListMenu.questListMenu->parts.sprite->getContentSize().height * (i + 1));
            questListMenu.questListMenu[i].parts.sprite->setPosition(questListMenu.questListMenu[i].parts.point);
            questListMenu.questListMenu[i].parts.sprite->setScale(questListMenu.scaleRate, 1);
            this->addChild(questListMenu.questListMenu[i].parts.sprite, 5);

            questListMenu.questListMenu[i].questName.label = Label::createWithTTF("", "fonts/msgothic.ttc", 18);
            auto str = String();
            str.appendWithFormat("%s", questName.operator*());
            questListMenu.questListMenu[i].questName.label->setString(str.getCString());
            questListMenu.questListMenu[i].questName.label->setAnchorPoint(Vec2(0.0, -0.3));
            questListMenu.questListMenu[i].questName.point = Vec2(questListMenu.questListMenu[i].parts.point.x + questListMenu.questListMenu[i].parts.size.width / 30.0, questListMenu.questListMenu[i].parts.point.y);
            questListMenu.questListMenu[i].questName.label->setPosition(questListMenu.questListMenu[i].questName.point);
            this->addChild(questListMenu.questListMenu[i].questName.label, 6);

            questName++;
        }
    }

あとはこれを指でスクロールさせたいんだけど、

難しそうな気がする。

でもできたらいろいろ応用ができそうだけど。

【COCOS2D-X】クエストリストの作成に着手

こんな感じでウィンドウを作成しました。

「冒険」ボタンをタップすると表示するようになっています。

これを縦に並べてクエストリストを表示させたいのですが、

データ構造はこんな感じで実装しました。

typedef struct _TextLabel {
    cocos2d::Label* label;
    cocos2d::Vec2 point;
} TextLabel;

typedef struct _QuestListMenu {
    Parts parts;
    TextLabel questName;
} QuestListMenu;

typedef struct _QuestList {
    Parts parts;
    QuestListMenu questListMenu[QUEST_NUM];
    float scaleRate;
} QuestList;

シーンの中ではnew演算子禁止なので、listは使えません。

散々悩んだのですが、とりあえず、大きめの配列を用意して使用することにします。

    if(isTouch(touch->getLocation(), &(questButton.parts)))
    {
        log("touch questButton");
        auto questList = getQuestList();
        auto questName = questList->begin();
        questListMenu.questListMenu->parts.sprite = Sprite::create("btn02_03_s_bl.png");
        questListMenu.questListMenu->parts.sprite->setAnchorPoint(Vec2(0.0, 1.0));
        questListMenu.questListMenu->parts.point = questListMenu.parts.point;
        questListMenu.questListMenu->parts.sprite->setPosition(questListMenu.questListMenu->parts.point);
        questListMenu.questListMenu->parts.size = Size(questListMenu.questListMenu->parts.sprite->getContentSize().width * questListMenu.scaleRate,
                                                       questListMenu.questListMenu->parts.sprite->getContentSize().height);
        questListMenu.questListMenu->parts.sprite->setScale(questListMenu.scaleRate, 1);
        this->addChild(questListMenu.questListMenu->parts.sprite, 5);
    }

タップ処理です。

今の段階では上の画面のようなウィンドウを作成追加するだけです。

今後は、数を増やしたり、テキストを追加したりする予定です。

【COCOS2D-X】メニューボタンも作り直す

まずは、キャラクター詳細ウィンドウに表示パラメータを追加しました。

さらに、右側のメニューボタンをキャラウィンドウと同じように構造体を使って配置します。

今後、タッチ判定処理を追加することになるので。

class HomeScene : public cocos2d::Scene
{
private:
    CharaWindow window[4];
    CharaDetailWindow detailWindow;
    MenuButton homeButton;
    MenuButton charaButton;
    MenuButton equipButton;
    MenuButton questButton;
    homeButton.sprite = Sprite::create("btnHome.png");
    if(homeButton.sprite != nullptr)
    {
        homeButton.sprite->setAnchorPoint(Vec2(1.0,1.0));
        homeButton.point = Vec2(sprite->getPosition().x + sprite->getContentSize().width * scaleRate / 2 + origin.x, visibleSize.height + origin.y);
        homeButton.sprite->setPosition(homeButton.point);
        homeButton.size = Size(homeButton.sprite->getContentSize().width * buttonScale, homeButton.sprite->getContentSize().height * buttonScale);
        homeButton.sprite->setScale(buttonScale);
        buttonBase = visibleSize.height - homeButton.size.height;
        this->addChild(homeButton.sprite, 1);
    }

    charaButton.sprite = Sprite::create("btnChara.png");
    if (charaButton.sprite != nullptr)
    {
        charaButton.sprite->setAnchorPoint(Vec2(1.0,1.0));
        charaButton.point = Vec2(sprite->getPosition().x + sprite->getContentSize().width * scaleRate / 2 + origin.x, buttonBase + origin.y);
        charaButton.sprite->setPosition(charaButton.point);
        charaButton.size = Size(charaButton.sprite->getContentSize().width * buttonScale, charaButton.sprite->getContentSize().height * buttonScale);
        charaButton.sprite->setScale(buttonScale);
        buttonBase -= charaButton.size.height;
        this->addChild(charaButton.sprite, 1);
    }

    equipButton.sprite = Sprite::create("btnEquip.png");
    if (equipButton.sprite != nullptr)
    {
        equipButton.sprite->setAnchorPoint(Vec2(1.0,1.0));
        equipButton.point = Vec2(sprite->getPosition().x + sprite->getContentSize().width * scaleRate / 2 + origin.x, buttonBase + origin.y);
        equipButton.sprite->setPosition(equipButton.point);
        equipButton.size = Size(equipButton.sprite->getContentSize().width * buttonScale, equipButton.sprite->getContentSize().height * buttonScale);
        equipButton.sprite->setScale(buttonScale);
        buttonBase -= equipButton.size.height;
        this->addChild(equipButton.sprite, 1);
    }

    questButton.sprite = Sprite::create("btnQuest.png");
    if (questButton.sprite != nullptr)
    {
        questButton.sprite->setAnchorPoint(Vec2(1.0,1.0));
        auto questButtonScale = buttonBase / questButton.sprite->getContentSize().height;
        questButton.point = Vec2(sprite->getPosition().x + sprite->getContentSize().width * scaleRate / 2 + origin.x,
                                 buttonBase + origin.y);
        questButton.sprite->setPosition(questButton.point);
        questButton.size = Size(questButton.sprite->getContentSize().width * questButtonScale, questButton.sprite->getContentSize().height * questButtonScale);
        questButton.sprite->setScale(questButtonScale);
        this->addChild(questButton.sprite, 1);
    }

さて、次はタッチ判定でシーン切り替えと、クエストシーンの作成を行って行きます。

【COCOS2D-X】結局キャラクターウインドウを構造体で作り直す。

結局クラスは使えない、ということで、

やっぱりここは構造体にするしか無いだろう、と思いまして、

めっちゃ書き換えました。

詳細はgitHubを見てくれ。

https://github.com/takishita2nd/cocos2d-x_sample


typedef struct _ParameterLabel {
    cocos2d::Label* label;
    cocos2d::Vec2 point;
} ParameterLabel;

typedef struct _CharaWindow {
    cocos2d::Sprite* sprite;
    cocos2d::Vec2 point;
    cocos2d::Size size;
    ParameterLabel HPLabel;
    ParameterLabel MPLabel;
} CharaWindow;

ウインドウは構造体でまとめました。

これをシーンクラスのprivateで保持し、画面を作成していきます。

    auto chara = gameStatus.Charactors->begin();
    for(int i = 0; i < 4; i++) {
        window[i].sprite = cocos2d::Sprite::create("btn02_03_s_bl.png");
        if (window[i].sprite != nullptr)
        {
            auto scaleRate = (visibleSize.height / 4) / window[i].sprite->getContentSize().height;
            window[i].point = Vec2(xpos + origin.x,
                                   origin.y + window[i].sprite->getContentSize().height * scaleRate * i);
            window[i].size = Size(window[i].sprite->getContentSize().width * scaleRate,
                                  window[i].sprite->getContentSize().height * scaleRate);
            window[i].sprite->setAnchorPoint(Vec2(0,0));
            window[i].sprite->setScale(scaleRate);
            window[i].sprite->setPosition(window[i].point);
            this->addChild(window[i].sprite);

            window[i].HPLabel.label = Label::createWithTTF("", "fonts/msgothic.ttc", 10);
            auto str = String();
            str.appendWithFormat("HP:%d/%d", chara.operator*()->Hp, chara.operator*()->MaxHp);
            window[i].HPLabel.label->setString(str.getCString());
            window[i].HPLabel.label->setAnchorPoint(Vec2(0.0, 1.0));
            window[i].HPLabel.point = Vec2(window[i].point.x + window[i].point.x / 10.0,
                                           window[i].point.y + window[i].size.height - window[i].size.height / 20.0);
            window[i].HPLabel.label->setPosition(window[i].HPLabel.point);
            this->addChild(window[i].HPLabel.label, 10);

            window[i].MPLabel.label = Label::createWithTTF("", "fonts/msgothic.ttc", 10);
            str = String();
            str.appendWithFormat("MP:%d/%d", chara.operator*()->Mp, chara.operator*()->MaxMp);
            window[i].MPLabel.label->setString(str.getCString());
            window[i].MPLabel.label->setAnchorPoint(Vec2(0.0, 1.0));
            window[i].MPLabel.point = Vec2(window[i].point.x + window[i].point.x / 10.0,
                    window[i].HPLabel.label->getPosition().y - window[i].HPLabel.label->getContentSize().height - window[i].size.height / 20.0);
            window[i].MPLabel.label->setPosition(window[i].MPLabel.point);
            this->addChild(window[i].MPLabel.label, 10);
        }
        chara++;
    }

もはや、何やってるか解らないレベル。

緻密にパーツを配置する座標とか計算しています。

で、左のウインドウをタップすると、中央に詳細画面が表示される仕組みにしています。

    if(detailWindow.isShow)
    {
        this->removeChild(detailWindow.sprite);
        this->removeChild(detailWindow.HPLabel.label);
        this->removeChild(detailWindow.MPLabel.label);
    }

    for(int i = 0; i < 4; i++)
    {
        if(isTouch(touch->getLocation(), &window[i]))
        {
            detailWindow.isShow = true;
            if(detailWindow.showIndex == i)
            {
                detailWindow.showIndex = -1;
                break;
            }
            detailWindow.showIndex = i;
            detailWindow.sprite = Sprite::create("btn02_03_s_bl.png");
            detailWindow.sprite->setAnchorPoint(Vec2(0.0, 0.0));
            detailWindow.sprite->setPosition(detailWindow.point);
            detailWindow.size = Size(window[i].sprite->getContentSize().width * detailWindow.scaleRate,
                                     window[i].sprite->getContentSize().height * detailWindow.scaleRate);
            detailWindow.sprite->setScale(detailWindow.scaleRate);
            this->addChild(detailWindow.sprite, 1);

            auto character = gameStatus.Charactors->begin();
            for(int j = 0; j < i; j++)
            {
                character++;
            }
            detailWindow.HPLabel.label = Label::createWithTTF("", "fonts/msgothic.ttc", 10);
            auto str = String();
            str.appendWithFormat("HP:%d/%d", character.operator*()->Hp, character.operator*()->MaxHp);
            detailWindow.HPLabel.label->setString(str.getCString());
            detailWindow.HPLabel.label->setAnchorPoint(Vec2(0.0, 0.0));
            detailWindow.HPLabel.point = Vec2(detailWindow.point.x + detailWindow.point.x / 10.0,
                                              detailWindow.point.y + detailWindow.size.height - detailWindow.size.height / 10.0);
            detailWindow.HPLabel.label->setPosition(detailWindow.HPLabel.point);
            this->addChild(detailWindow.HPLabel.label, 10);

            detailWindow.MPLabel.label = Label::createWithTTF("", "fonts/msgothic.ttc", 10);
            str = String();
            str.appendWithFormat("MP:%d/%d", character.operator*()->Mp, character.operator*()->MaxMp);
            detailWindow.MPLabel.label->setString(str.getCString());
            detailWindow.MPLabel.label->setAnchorPoint(Vec2(0.0, 0.0));
            detailWindow.MPLabel.point = Vec2(detailWindow.point.x + detailWindow.point.x / 10.0,
              detailWindow.point.y + detailWindow.size.height - detailWindow.HPLabel.label->getContentSize().height - detailWindow.size.height / 10.0);
            detailWindow.MPLabel.label->setPosition(detailWindow.MPLabel.point);
            this->addChild(detailWindow.MPLabel.label, 10);
        }
    }

疲れた・・・

【COCOS2D-X】new演算子でインスタンスを作成してはならない(と思う)

前回のソースから、またいろいろとコーディングしていたんですが、

そこで一つ思ったことがありまして、

前回追加作成したクラス、いつdeleteすればいい??

シーンの処理の中でインスタンスを作成したのですが、

シーンが終了したあと、インスタンスを削除するタイミングが無いんです。

これは大問題で、

確実にメモリリークの問題が発生します。

と、言うことは、だよ。

cocos2d-xでは、シーンの中でnewを使ってインスタンスを作ってはいけないんじゃ無いか、って思いました。

マズいな。

これから大規模修正入りまーす。

【COCOS2D-X】ステータスウィンドウをクラス化

見た目は変わらないんですが。

前回のままだといろいろ扱いづらいので、左のウィンドウをクラス化しました。

そして、今回は、前回と同じように表示できるところまで作成しました。

このウィンドウをタップすると、画面中央に詳細が表示されるような動きにしたいと思っています。

//
// Created by ntaki on 2020/12/12.
//

#ifndef PROJ_ANDROID_CHARAWINDOW_H
#define PROJ_ANDROID_CHARAWINDOW_H

#include "cocos2d.h"
#include "GameStatusData/Character.h"

class CharaWindow {
private:
    cocos2d::Vec2 point;
    cocos2d::Size size;
    cocos2d::Sprite* sprite;
    cocos2d::Label* hpLabel;
    cocos2d::Label* MpLabel;
public:
    CharaWindow();
    ~CharaWindow();

    void show(cocos2d::Scene* scene);
    void hide(cocos2d::Scene* scene);
    cocos2d::Size getSpriteContentSize();
    cocos2d::Vec2 getPosition();
    cocos2d::Size getSize();
    void setPosition(cocos2d::Vec2 vector);
    void setScale(float rate);
    void setParameter(Character* chara);
    bool isTouch(cocos2d::Vec2 vector);
};


#endif //PROJ_ANDROID_CHARAWINDOW_H
//
// Created by ntaki on 2020/12/12.
//

#include "CharaWindow.h"

CharaWindow::CharaWindow()
{
    sprite = cocos2d::Sprite::create("btn02_03_s_bl.png");
    if (sprite != nullptr)
    {
        sprite->setAnchorPoint(cocos2d::Vec2(0,0));
        auto offset = sprite->getContentSize().width / 10.0;
        hpLabel = cocos2d::Label::createWithTTF("Hello World", "fonts/msgothic.ttc", 6);
        if(hpLabel != nullptr)
        {
            hpLabel->setAnchorPoint(cocos2d::Vec2(0, 1));
            hpLabel->setPosition(cocos2d::Vec2(0, sprite->getContentSize().height));
            sprite->addChild(hpLabel);
        }
        MpLabel = cocos2d::Label::createWithTTF("Hello World", "fonts/msgothic.ttc", 6);
        if(MpLabel != nullptr)
        {
            MpLabel->setAnchorPoint(cocos2d::Vec2(0, 1));
            MpLabel->setPosition(cocos2d::Vec2(0, sprite->getContentSize().height - 1 * hpLabel->getContentSize().height));
            sprite->addChild(MpLabel);
        }
    }
}

CharaWindow::~CharaWindow()
{
}

void CharaWindow::setPosition(cocos2d::Vec2 vector)
{
    if (sprite != nullptr)
    {
        point = vector;
        sprite->setPosition(point);
    }
}

void CharaWindow::setScale(float rate)
{
    if (sprite != nullptr)
    {
        sprite->setScale(rate);
        size = cocos2d::Size(sprite->getContentSize().width * rate, sprite->getContentSize().height * rate);
    }
}

void CharaWindow::show(cocos2d::Scene* scene)
{
    if (sprite != nullptr && scene != nullptr)
    {
        scene->addChild(sprite, 1);
    }
}

void CharaWindow::hide(cocos2d::Scene *scene)
{
    if (sprite != nullptr && scene != nullptr)
    {
        scene->removeChild(sprite, false);
    }
}

cocos2d::Vec2 CharaWindow::getPosition()
{
    return point;
}

cocos2d::Size CharaWindow::getSize()
{
    return size;
}

cocos2d::Size CharaWindow::getSpriteContentSize()
{
    if (sprite != nullptr)
    {
        return sprite->getContentSize();
    }
}

void CharaWindow::setParameter(Character* chara)
{
    auto hpStr = cocos2d::String();
    hpStr.appendWithFormat("HP : %d", chara->MaxHp);
    hpLabel->setString(hpStr.getCString());

    auto mpStr = cocos2d::String();
    mpStr.appendWithFormat("MP : %d", chara->MaxMp);
    MpLabel->setString(mpStr.getCString());
}

bool CharaWindow::isTouch(cocos2d::Vec2 vector)
{
    return false;
}
    CharaWindow* window[4];
    auto chara = GameStatus::GetGameData()->Charactors->begin();
    for(int i = 0; i < 4; i++) {
        window[i] = new CharaWindow();
        window[i]->setParameter(chara.operator*());
        window[i]->setScale((visibleSize.height / 4) / window[i]->getSpriteContentSize().height);
        window[i]->setPosition(Vec2(xpos + origin.x, origin.y + window[i]->getSize().height * i));
        window[i]->show(this);
        chara++;
    }

クラス化させることで、ウィンドウ表示処理がかなりスッキリしました。

このクラスの中で使用しているオブジェクトはnewで作成した物ではないので、cocos-2dx内部で適時ガベージコレクションされるでしょう。

【COCOS2D-X】ステータスを表示

数字は完全にランダムです。

ちょっとゲームらしくなってきたでしょ。

#ifndef PROJ_ANDROID_CHARACTER_H
#define PROJ_ANDROID_CHARACTER_H

#include "cocos2d.h"

class Character {
public:
    int Hp;
    int MaxHp;
    int Mp;
    int MaxMp;
    int Power;
    int Speed;
    int Magic;
public:
    Character();
    ~Character();
};


#endif //PROJ_ANDROID_CHARACTER_H
#include "Character.h"

Character::Character()
{
    MaxHp = cocos2d::random<int>(0, 100);
    MaxMp = cocos2d::random<int>(0, 100);
    Power = cocos2d::random<int>(0, 100);
    Speed = cocos2d::random<int>(0, 100);
    Magic = cocos2d::random<int>(0, 100);
}

Character::~Character()
{

}
#ifndef PROJ_ANDROID_GAMESTATUS_H
#define PROJ_ANDROID_GAMESTATUS_H

#include "cocos2d.h"
#include "Character.h"
#include <list>

class GameStatus {
private:
    static GameStatus *gameStatus;
public:
    std::list<Character*> *Charactors;
private:
    GameStatus();
    ~GameStatus();
public:
    static GameStatus* GetGameData();
    static void Destroy();
};


#endif //PROJ_ANDROID_GAMESTATUS_H
#include "GameStatus.h"

GameStatus *GameStatus::gameStatus = nullptr;

GameStatus::GameStatus()
{
    Charactors = new std::list<Character*>();
    for(int i = 0; i < 4; i++)
    {
        Character *character = new Character();
        Charactors->push_back(character);
    }
}

GameStatus::~GameStatus()
{
    for(Character *character = Charactors->front(); Charactors->empty() == true; character = Charactors->front())
    {
        delete character;
        Charactors->pop_front();
    }
    delete Charactors;
}

GameStatus * GameStatus::GetGameData()
{
    if(gameStatus == nullptr)
    {
        gameStatus = new GameStatus();
    }
    return gameStatus;
}

void GameStatus::Destroy()
{
    delete gameStatus;
}
    // ステータスウィンドウの配置
    auto xpos = (visibleSize.width - sprite->getContentSize().width * scaleRate) / 2.0;
    float windowScale = 0;
    float windowHeight = 0;

    Sprite *charaStatusWindow[4];
    auto chara = GameStatus::GetGameData()->Charactors->begin();
    for(int i = 0; i < 4; i++)
    {
        charaStatusWindow[i] = Sprite::create("btn02_03_s_bl.png");
        if (charaStatusWindow[i] == nullptr)
        {
            problemLoading("'btn02_03_s_bl.png'");
        }
        else
        {
            if(windowScale == 0 || windowHeight == 0)
            {
                windowHeight = charaStatusWindow[i]->getContentSize().height;
                windowScale = (visibleSize.height / 4) / windowHeight;
            }
            charaStatusWindow[i]->setPosition(Vec2(xpos + origin.x,origin.y + windowHeight * i * windowScale));
            charaStatusWindow[i]->setAnchorPoint(Vec2(0,0));
            charaStatusWindow[i]->setScale(windowScale);

            this->addChild(charaStatusWindow[i], 1);
        }

        auto offset = charaStatusWindow[i]->getContentSize().width / 10.0;
        auto hpLabel = Label::createWithTTF("Hello World", "fonts/msgothic.ttc", 12);
        if (hpLabel == nullptr)
        {
            problemLoading("'fonts/msgothic.ttc'");
        }
        else
        {
            hpLabel->setAnchorPoint(Vec2(0, 1));
            hpLabel->setPosition(Vec2(origin.x + xpos + offset, origin.y + windowHeight * (i + 1) * windowScale));

            this->addChild(hpLabel, 2);

            auto hpStr = String();
            hpStr.appendWithFormat("HP : %d", chara.operator*()->MaxHp);
            hpLabel->setString(hpStr.getCString());
        }

        auto MpLabel = Label::createWithTTF("Hello World", "fonts/msgothic.ttc", 12);
        if (MpLabel == nullptr)
        {
            problemLoading("'fonts/msgothic.ttc'");
        }
        else
        {
            MpLabel->setAnchorPoint(Vec2(0, 1));
            MpLabel->setPosition(Vec2(origin.x + xpos + offset, origin.y + windowHeight * (i + 1) * windowScale - hpLabel->getContentSize().height));

            this->addChild(MpLabel, 2);

            auto mpStr = String();
            mpStr.appendWithFormat("MP : %d", chara.operator*()->MaxMp);
            MpLabel->setString(mpStr.getCString());
        }
        chara++;
    }

ウインドウ周りのクラス設計もちゃんと考えないといけないね。

あと、C++のList型は、他のプログラムのList型の様に使用できなくて、ちょっとめんどい。

完全にイテレータパターンのクラスなので、少々扱いづらい。

慣れるしか無いんだけど。

あと、乱数はcocos-2dxに搭載されているものが使用できます。

C++標準の乱数よりも使いやすいです。

【COCOS2D-X】アイコン画像をピッチリ並べる

とりあえず、アイコンをピッチリ並べてみました。

ポイントは、座標や拡大サイズを全て計算で算出すること。

こうしないと、機種が変わったときに、確実にレイアウトが崩れます。

    float buttonScale = visibleSize.height / (visibleSize.height / 4.0);
    float buttonBase = 0.0;
    auto homeButton = Sprite::create("btnHome.png");
    if (homeButton == nullptr)
    {
        problemLoading("'btnHome.png'");
    }
    else
    {
        homeButton->setPosition(Vec2(sprite->getPosition().x + sprite->getContentSize().width * scaleRate / 2 + origin.x, visibleSize.height + origin.y));
        homeButton->setAnchorPoint(Vec2(1.0,1.0));
        homeButton->setScale(buttonScale);
        buttonBase = visibleSize.height - homeButton->getContentSize().height * buttonScale;
        this->addChild(homeButton, 1);
    }

    auto charaButton = Sprite::create("btnChara.png");
    if (charaButton == nullptr)
    {
        problemLoading("'btnChara.png'");
    }
    else
    {
        charaButton->setPosition(Vec2(sprite->getPosition().x + sprite->getContentSize().width * scaleRate / 2 + origin.x,
                                      buttonBase + origin.y));
        charaButton->setAnchorPoint(Vec2(1.0,1.0));
        charaButton->setScale(buttonScale);
        buttonBase -= charaButton->getContentSize().height * buttonScale;
        this->addChild(charaButton, 1);
    }

    auto equipButton = Sprite::create("btnEquip.png");
    if (equipButton == nullptr)
    {
        problemLoading("'btnEquip.png'");
    }
    else
    {
        equipButton->setPosition(Vec2(sprite->getPosition().x + sprite->getContentSize().width * scaleRate / 2 + origin.x,
                                      buttonBase + origin.y));
        equipButton->setAnchorPoint(Vec2(1.0,1.0));
        equipButton->setScale(buttonScale);
        buttonBase -= equipButton->getContentSize().height * buttonScale;
        this->addChild(equipButton, 1);
    }

    auto questButton = Sprite::create("btnQuest.png");
    if (questButton == nullptr)
    {
        problemLoading("'btnQuest.png'");
    }
    else
    {
        auto scale = buttonBase / questButton->getContentSize().height;
        questButton->setPosition(Vec2(sprite->getPosition().x + sprite->getContentSize().width * scaleRate / 2 + origin.x,
                                      buttonBase + origin.y));
        questButton->setAnchorPoint(Vec2(1.0,1.0));
        questButton->setScale(scale);

        this->addChild(questButton, 1);
    }

例えば、「キャラ」のアイコンは「ホーム」のアイコンの下に並ぶように座標を計算して配置していますし、

その下の「装備」も「キャラ」の下に並ぶように座標を計算で算出しています。

「クエスト」のボタンは、上の3つのアイコンを並べた空きスペースにピッチリ収まるように、拡大率を算出して配置しています。

アイコンの拡大率も計算で算出しているので、機種や解像度が変化しても、アイコンの大きさが変わる程度で、大きくレイアウトは崩れないと思います。

思った以上に良い感じです。