LoginSignup
9
2

More than 5 years have passed since last update.

触ってみたcocos2d-x!!

Last updated at Posted at 2016-12-02

Fusic アドベントカレンダー3日目です。

記念すべき 2日目は、@gorogoroyasuの力作でした。
ここだけの話ですが、@gorogoroyasuはハードルを下げると言いつつ
上げてしまって、少し書き辛いですが、
頑張ります。

ということで、Fusic アドベントカレンダー3日目です。

まずもってお前だれ?

・Fusicの2年目のチョです。
・出身:韓国。
・しかし、日本に馴染みすぎと言われます。
・会社のみんなからは「お前日本人やろ?」と言われています。
・だから?結構日本語話せるので、他のところで会ったら、楽しく話ししたいです!怖がらないで。。。😢

テーマ

今回のテーマは「やっていなかったことをやる」、「とりあえずハードルをあげる」というテーマで書きます。

普段なにやっているの?

Cakephp3やAWSなど色んなものを利用しWeb開発をやっています。
うちは言語と環境の制約がなく自由に仕事できて、
楽しくやってます!
なのであんまり触ることないゲームをやってみようと思って、
cocos2d-xを選択!

どうやってハードルをあげるつもり?

それはですね。
入社してからよく言われた話ですが、
どこかで発表するとき@debilityの話題を話すと
いいよと言われてました。
真面目といえばチョと呼ばれるような人間なので。
仕方なく@debilityの出現するゲームを作りました!

対象

cocos2d-xをとりあえず使ってみたい人
macを使っている人
いずれmacを使う人

どんなゲーム?

さて、ここから本番です。

最後の目標として、
下記で表示されているゲームを作ります。

image

そもそもcocos2d-xとは?

・open sorce cocos2dエンジンのbranchの一つ。
・色んなプラットホームを提供する2dゲームの一つ。

提供されているプラットホームは何があるの?

・Mac OSX、IOS
・Android
・Windows、Windows Phone
・Linux Ubuntu
色々できそう。。。

長所は?

・Exampleが多くて、誰でも簡単にできる
・容量が少ないゲーム開発ができる!

cocos2Dの構成

▼背景
・一つ一つのSceneがあって、Sceneを重ねて作る感じ。
▼Layer
・Sceneに含まるObject
・ユーザーのイベントを受けられる
▼Sprite
・実際に動くキャラクターなど
▼Action
・cocos2Dノード属性を時間によって変更するClass
・Spriteにアニメーションの設定ができる!

奥が深い。。。

ここまで理解したら、実際にコードを書いて見ようじゃないか!

install

http://www.cocos2d-x.org/download このサイトから Cocos2d-xの最新版をDownloadしよう!
・DownloadするとzipファイルがDownloadされるので、unzipしてください。
・で、unzipしたら一個のフォルダーができています。そこに入ってください。
・そのフォルダーには setup.py があるはずです。そのファイルをrunしましょう!因みに実行コマンドは python setup.py です。
・そうすると英語で色々聞かれると思いますが、全部Enterを押して結構です。
・で、最後に source ~/.bash_profile を叩いてください。
・ここまでがinstallです。あら素敵。

次はProjectを作りましょう!

・コマンドは cocos new -l cpp -d ~/Cocos2d-x-Tutorial SimpleGame です。
・上記のコマンドを叩くことで SimpleGame というprojectが出来上がります!あら簡単。

で、ここから一番楽しいコーディング!

  • 今回はXcodeを使って進めます。

作ったProjectでとりあえず実装してみる

・Xcodeで先作ったProjectを開いてみましょう。
ある位置は ~/Cocos2d-x-Tutorial/SimpleGame/proj.ios_mac/ の中に SimpleGame.xcodeproj があります。それを入れてください。
・開くとこんな画面が出てきます。そこで実行するデバイスの設定を切り替えましょう。
・そのようにして、実行ボタンを押すと下記のような画面が開けます。
・これで開発環境は準備できました!

キャラクターを置いてみる!

・先ほど説明した Sprite を利用しキャラクターを画面に配置してみます。
Sprite を使うためには cocos2d namespaceをusingする必要があります。
HelloWorldScene.h の一番上に using namespace cocos2d; と書いてください。
・そして、Helloworld classの中に

using namespace cocos2d;

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

class HelloWorld : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();

    virtual bool init();

    // a selector callback
    void menuCloseCallback(cocos2d::Ref* pSender);

    // implement the "static create()" method manually
    CREATE_FUNC(HelloWorld);
    void addMonster(float dt);
    bool onTouchBegan(Touch *touch, Event *unused_event);
    bool onContactBegan(PhysicsContact &contact);
private: //ここです。
    Sprite* _player;
};

#endif // __HELLOWORLD_SCENE_H__

を宣言します。
・宣言した_player変数を設定して配置してみます。
・表示したい画像をSimpleGame/Resourcesにdrag and dropしてください。
・用意する画像は「print.png」、「monster.png」、「projectile.png」です。
・そうすると下記のような画面が出てきて、下記の画面のように設定してください。
image

・HelloWorldScene.cppの中の HelloWorld::init の中に下記のコードを書いてください。

    // 1
    if ( !Layer::init() ) {
        return false;
    }
    // 2
    auto origin = Director::getInstance()->getVisibleOrigin();
    auto winSize = Director::getInstance()->getVisibleSize();
    // 3
    auto background = DrawNode::create();
    background->drawSolidRect(origin, winSize, Color4F(0.6,0.6,0.6,1.0));
    this->addChild(background);
    // 4
    _player = Sprite::create("prin.png");
    _player->setPosition(Vec2(winSize.width * 0.1, winSize.height * 0.5));
    this->addChild(_player);

    srand((unsigned int)time(nullptr));
    this->schedule(schedule_selector(HelloWorld::addMonster), 1.5);

    auto eventListener = EventListenerTouchOneByOne::create();
    eventListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
    this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(eventListener, _player);

    auto contactListener = EventListenerPhysicsContact::create();
    contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegan, this);
    this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener, this);

    return true;

・このように書くことでキャラクターの配置ができます!
・これで、自分が尊敬している@debility先輩が出現しました!見てください。あの姿格好いいっしょ!
・で、感想はさておき。

モンスターが来るように書いてみましょう。

PhysicsCategoryHelloWorldScene.cpp の一番上に書いておきます。

enum class PhysicsCategory {
    None = 0,
    Monster = (1 << 0),    // 1
    Projectile = (1 << 1), // 2
    All = PhysicsCategory::Monster | PhysicsCategory::Projectile // 3
};

・先のように void addMonster(float dt);HelloWorldScene.h に宣言しておきます。
・そして、 HelloWorldScene.cpp で先宣言したaddMonsterの中身を作っていきます。中身は下記のように

    auto monster = Sprite::create("monster.png");

    // 1
    auto monsterContentSize = monster->getContentSize();
    auto selfContentSize = this->getContentSize();
    int minY = monsterContentSize.height/2;
    int maxY = selfContentSize.height - monsterContentSize.height/2;
    int rangeY = maxY - minY;
    int randomY = (rand() % rangeY) + minY;

    monster->setPosition(Vec2(selfContentSize.width + monsterContentSize.width/2, randomY));
    this->addChild(monster);

    // 2
    int minDuration = 2.0;
    int maxDuration = 4.0;
    int rangeDuration = maxDuration - minDuration;
    int randomDuration = (rand() % rangeDuration) + minDuration;

    // 3
    auto actionMove = MoveTo::create(randomDuration, Vec2(-monsterContentSize.width/2, randomY));
    auto actionRemove = RemoveSelf::create();
    monster->runAction(Sequence::create(actionMove,actionRemove, nullptr));

    // 1
    auto monsterSize = monster->getContentSize();
    auto physicsBody = PhysicsBody::createBox(Size(monsterSize.width , monsterSize.height),
                                              PhysicsMaterial(0.1f, 1.0f, 0.0f));
    // 2
    physicsBody->setDynamic(true);
    // 3
    physicsBody->setCategoryBitmask((int)PhysicsCategory::Monster);
    physicsBody->setCollisionBitmask((int)PhysicsCategory::None);
    physicsBody->setContactTestBitmask((int)PhysicsCategory::Projectile);

    monster->setPhysicsBody(physicsBody);

*すみません。今回はコードの説明はあんまりしません。ご了承ください。

次には押した時に攻撃できるようにしましょう。

・HelloWorldScene.hに宣言されている onTouchBegan を実装します。
コードの下記のとおり。

bool HelloWorld::onTouchBegan(Touch *touch, Event *unused_event) {
    // 1  - Just an example for how to get the  _player object
    //auto node = unused_event->getCurrentTarget();

    // 2
    Vec2 touchLocation = touch->getLocation();
    Vec2 offset = touchLocation - _player->getPosition();

    // 3
    if (offset.x < 0) {
        return true;
    }

    // 4
    auto projectile = Sprite::create("projectile.png");
    projectile->setPosition(_player->getPosition());
    this->addChild(projectile);

    // 5
    offset.normalize();
    auto shootAmount = offset * 1000;

    // 6
    auto realDest = shootAmount + projectile->getPosition();

    // 7
    auto actionMove = MoveTo::create(2.0f, realDest);
    auto actionRemove = RemoveSelf::create();
    projectile->runAction(Sequence::create(actionMove,actionRemove, nullptr));

    auto projectileSize = projectile->getContentSize();
    auto physicsBody = PhysicsBody::createCircle(projectileSize.width/2 );
    physicsBody->setDynamic(true);
    physicsBody->setCategoryBitmask((int)PhysicsCategory::Projectile);
    physicsBody->setCollisionBitmask((int)PhysicsCategory::None);
    physicsBody->setContactTestBitmask((int)PhysicsCategory::Monster);
    projectile->setPhysicsBody(physicsBody);

    return true;
}

次はあたったらモンスターが画面からなくなるように書いてみましょう。

・HelloWorld::createSceneを下記のように書いて、

Scene* HelloWorld::createScene()
{
    auto scene = Scene::createWithPhysics();
    scene->getPhysicsWorld()->setGravity(Vec2(0,0));
    scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);

    // 'layer' is an autorelease object
    auto layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

・onContactBeganの中身を書くことで実現されます。

bool HelloWorld::onContactBegan(PhysicsContact &contact) {
  auto nodeA = contact.getShapeA()->getBody()->getNode();
  auto nodeB = contact.getShapeB()->getBody()->getNode();

  nodeA->removeFromParent();
  nodeB->removeFromParent();
  return true;
}

感想

・やっぱ、新しいことをするのは楽しい。
・これからもどんどんチャレンジしていきたい。

9
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2