Cocos2d-xで作るパズドラ風パズルゲーム(ソースコードあり)

Cocos2d-xで作るパズドラ風パズルゲーム(マッチ3ゲーム)

こんにちは。野口です。

Cocos2d-xは、2Dゲームを作成するのに便利な機能が盛り込まれたオープンソース(MITライセンス)のフレームワーク(ゲームエンジン)です。
Cocos2dは、クロスプラットフォーム対応の2DゲームをPythonで開発できるフレームワークとして始まったようです。
そこから、Cocos2d-xやCocos2d for iPhoneといったフレームワークが派生しました。

単にCocos2dとだけ言った場合、Cocos2d for iPhoneを指している場合が多いのではないでしょうか? というぐらいCocos2d for iPhoneはヒットしたようです。このようにCocos2dには様々な種類があるので、私も最初は混乱しました。

その中で、今回紹介するCocos2d-xはC++でクロスプラットフォーム開発が可能なオープンソース(MITライセンス)のフレームワークです。
また、Cocos2d-xはC++の他にもJavaScriptとLuaによる開発もサポートしています。

本記事では、 大人気のiPhone/Androidゲームであるパズドラのパズル風パズルゲーム(マッチ3ゲームと呼ぶそうです)をCocos2d-xで作るとどうなるか? をテーマにCocos2d-xの機能を紹介したいと思います。
尚、Cocos2d-xはクロスプラットフォーム開発可能と書きましたが、本記事ではiPhoneアプリを前提とさせていただきます。

ソースコードはGitHubで公開しているのでご希望の方は以下から取得してください。
(cocos2d-x-2.1.4で、Xcode5.0のiPhone Retina(4-inch環境でのみ動作確認しています)
https://github.com/noguchi999/fujidora.git

[ Cocos2d-xで作るパズドラ風パズルゲーム(マッチ3ゲーム) ]


■ ソースコード解説

・ 基本コード

では早速、ゲームのソースコードを見ていきましょう。

//GameScene.h
class GameScene : public CCLayer
{
public:
    GameScene();

    virtual bool init();
    static CCScene* scene();
    CREATE_FUNC(GameScene);

    virtual bool ccTouchBegan(CCTouch* pTouch, CCEvent* pEvent);
    virtual void ccTouchMoved(CCTouch* pTouch, CCEvent* pEvent);
    virtual void ccTouchEnded(CCTouch* pTouch, CCEvent* pEvent);
//GameScene.cpp
CCScene* GameScene::scene()
{
    CCScene* scene   = CCScene::create();
    GameScene* layer = GameScene::create();
    scene->addChild(layer);
    
    return scene;
}

上記は、Cocos2d-xでゲームを作成するときのお決まりのコードになります。
ここで登場するCCSceneというのが、ゲーム画面です。
Cocos2d-xでは、1つの画面が1つのCCSceneクラスに対応しています。

CCLayerクラスはゲーム画面に表示するレイヤーです。
1つの画面に複数のレイヤーを重ねて表示することも可能です(本記事では1つだけです)
今回のゲームの画面であるGameSceneクラスはCCLayerクラスを継承しています。

更にこのCCLayerの上にCCSpriteという画像を表示するクラスを重ねていきます。
本記事では、背景画像やパズルのブロックなどの画像をCCSpriteクラスで表現しています。

Cocos2d-xでは、これらのクラスを利用して画面と画面に表示するキャラクターなどの画像を表現し、CCActionというクラスを利用して様々な動きをキャラクターに与えることでゲームを作成していきます。

・ 画面のタッチ操作について

続いて、スマートフォンには欠かせない画面のタッチ操作について、Cocos2d-xではどのように扱っているのかを見てみましょう。

    virtual bool ccTouchBegan(CCTouch* pTouch, CCEvent* pEvent);
    virtual void ccTouchMoved(CCTouch* pTouch, CCEvent* pEvent);
    virtual void ccTouchEnded(CCTouch* pTouch, CCEvent* pEvent);

上のソースコードに書かれているccTouchBegan、ccTouchMoved、ccTouchEndedの3つの関数(もう一つ、本記事では扱っていませんがccTouchCancelledという関数があります)で画面のタッチイベントを受け取ることが出来ます。
それぞれ、タッチされた瞬間、スワイプ中、画面から指が離れた瞬間のイベントを受け取ります。
これらは、いずれもCCLayerクラスが持つ関数です。

このようにCocos2d-xでは、それぞれのタッチイベントの発生時に行いたい処理をそれぞれの関数に記述することでタッチ操作を実装します。
タッチイベントを受け付けるか否かはsetTouchEnabled関数で設定し、シングルタップとダブルタップの区別はsetTouchMode関数で設定することが出来ます。
本記事では、シングルタップのみに対応しています。

本記事のパズルでは、ccTouchBeganの関数内でタップされた位置の座標からその位置にあるスプライト(CCSpriteで定義した画像のことだと思って下さい。ここではパズルのブロックです)を取得しています。
スプライトは自分の位置座標を保持しています(スプライトのgetPositionメソッドで取得できます)
更に同じくスプライトのメソッドであるboundingBox()を利用する事で簡単に衝突判定が行えるので便利です。

タップしたスプライトが判定できたら、ccTouchMovedが呼び出されるたびにタップしている指の位置座標(ccTouchMovedの引数のpTouch)をスプライトに設定(setPosition)してあげれば指の動きに合わせてパズルのブロックを移動させることが出来ます。

指が画面から離れるとccTouchEnded関数が呼び出されるので、その時点でパズルのブロックの配置を確認して3つ以上連なっている同じ色のブロックを消して、消されたブロックの上に乗っているブロックを下に移動させて、空きができた部分に新しいブロックを追加するという処理が実行されます。

・ アニメーションについて

マッチ3ゲームのロジックとしては以上の部分で出来上がりですが(点数計算は今回は未実装です)、ブロックの移動やブロックが消えていく部分がそのままでは味気ないので、アニメーションの処理を追加します。

例として、ブロックを消した際のアニメーションの実装を見ていきましょう。

//GameScene.cpp
void GameScene::removeBlocksAction()
{
    bool isFirst = true;
    for (vector::const_iterator it = removedBlocks.begin(); it != removedBlocks.end(); ++it)
    {
        int x = (*it)->getNexPositionX();
        int y = (*it)->getNexPositionY();
        
        CCScaleTo* shrinkBlock    = CCScaleTo::create(0.2f, 0);
        CCCallFuncN* removeBlocksActionAnimationFunction = CCCallFuncN::create(this, callfuncN_selector(GameScene::removeBlocksActionAnimation));
        CCFiniteTimeAction* shrinkBlockSequence = CCSequence::create(shrinkBlock, removeBlocksActionAnimationFunction, NULL);
        
        CCScaleTo* burst   = CCScaleTo::create(0.3f, 2.5f);
        CCScaleTo* clear   = CCScaleTo::create(0.3f, 1);
        CCCallFuncN* removingParticleFunction = CCCallFuncN::create(this, callfuncN_selector(GameScene::removingParticle));
        CCFiniteTimeAction* shrinkParticalSequence = CCSequence::create(burst, clear, removingParticleFunction, NULL);
        CCNode* partial = createParticle("lizi.plist", blockFields[x][y]->getPosition());
        
        if (isFirst) {
            CCPlaySE* playSe = CCPlaySE::create(kSERemoveBlock);
            shrinkBlockSequence = CCSpawn::create(shrinkBlockSequence, playSe, NULL);
            isFirst = false;
        }
        
        blockFields[x][y]->runAction(shrinkBlockSequence);
        partial->runAction(shrinkParticalSequence);
    }
}

この一連の処理により、ブロックが小さく縮みながら消えると共に炎が燃え上がるアニメーションが表示される(音も鳴ります)
ここで注目して欲しいのは、CCScaleTo、CCCallFuncN、CCSequenceです。

この部分を見て下さい。

CCScaleTo* shrinkBlock    = CCScaleTo::create(0.2f, 0);
CCCallFuncN* removeBlocksActionAnimationFunction = CCCallFuncN::create(this, callfuncN_selector(GameScene::removeBlocksActionAnimation));
CCFiniteTimeAction* shrinkBlockSequence = CCSequence::create(shrinkBlock, removeBlocksActionAnimationFunction, NULL);

CCScaleToは、対象のスプライトを拡大/縮小するアニメーション機能を提供しています。
他にも、スプライトを移動させるCCMoveToやスプライトをジャンプさせるCCJumpなどアニメーションを簡単に実装できる様々なクラスが提供されています。

CCCallFuncNは、アニメーションと同時または、アニメーションの終了時に実行させたい任意の関数を指定することが出来ます。
プログラムの処理の実行そのものは、アニメーションの処理と同期しているわけではないのでアニメーションと連動して実行したい関数がある場合は、CCCallFuncNを利用します。

CCSequenceは、アニメーションやCCCallFuncNで定義した関数を順番に実行するためのクラスです。
CCSequence::createの引数に実行したい順番にカンマ区切りでCCActionクラス等のインスタンスを記述することで、その順番通りにアニメーションが実行されます。

CCSequenceを使わずに、単にそれぞれのアニメーション等を実行してしまうと最初のアニメーションが終わっていないのに次のアニメーションやCCCallFuncNで指定した関数が実行されてしまいます。

この例では、スプライトを小さく縮めて見えなくした後でスプライトを削除する処理を行っている関数を呼び出したいので、そのような順番でCCSequenceに登録します。

このようにして定義したアニメーションを実行したいスプライトのrunActionメソッドの引数に渡してあげることでアニメーションが実行されます。

今回はアニメーションの実装はコーディングで行いましたが、CocosBuilder※1というツールを利用することでFlashアニメーションを作るような感覚でアニメーションの実装を行う事も可能です。

※1. CocosBuilderは既に開発停止しており、SpriteBuilderというものが後継に当たるようです。
とは言え、SpriteBuilderは2013年10月時点では実用レベルに達していないため、当面はCocosBuilderを利用することになりそうです。

以上が大まかなゲームの処理の流れです。


■ デモ

実際に動かしてみるとこんな感じになります。


■ 最後に。

本記事のプログラム作成にあたっては以下の書籍が非常に参考になりました。
cocos2d-xによるiPhone/Androidアプリプログラミングガイド

ソースコードや画像の一部も流用させていただいています。
良書ですので、Cocos2d-xに興味を持たれた方は一読をオススメします。

コメントを残す

メールアドレスが公開されることはありません。

ABOUTこの記事をかいた人

僕と契約してアーティストになってよ。 普段はJavaやPHPで業務Webアプリばっかり作っています。 安西先生、Rubyで仕事がしたいです・・・。