2012年11月9日金曜日

Cocos2d-xのHello Worldを改造して15パズルっぽい何かを作る(前編)


前回、Cocos2d-xの開発環境をインストールし、Androidで Hello World を表示することが出来ました。
今回は、そのHello World を改造して、15パズルのような何かを作って行きます。
私自身はCocos2dは初めてで、なにが出来るのかまったく知りません。調べつつ実装しつつ覚えていきたいと思います。

15パズルについて簡単に説明しておくと、正方形の画像を縦横4分割して16のピースに分割し、その内1枚のピースを抜いて残った15枚をスライドさせながら元絵を完成させるパズルです。

15パズル

・16分割の画像を作成
まずは、画像を16分割することを考えます。画像はとりあえずHello Worldに使用されているCocos2d-xのマスコット(?)画像を使用します。
AndroidのJavaプログラムであれば、Bitmapに読み込んだ画像をCanvasのdrawBitmapで切りだしていけば良いですが、Cocos2d-xではどうすれば良いでしょうか。
とりあえず、Hello Worldのソースファイルからの画像読み込み箇所を見てみます。

Classes/HelloWorldScene.cpp から
    // add "HelloWorld" splash screen"
    CCSprite* pSprite = CCSprite::create("HelloWorld.png");

どうやら、画像をスプライトとして読み込んでいるようです。
スプライトはゲームプログラムではおなじみですね。
http://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%97%E3%83%A9%E3%82%A4%E3%83%88_(%E6%98%A0%E5%83%8F%E6%8A%80%E8%A1%93)

これをどうやって16分割するか、CCSpriteに画像を分割するようなメソッドがあれば良いのですが。
まずは、スプライトを生成しているCCSprite::create のリファレンスを見てみます。
http://www.cocos2d-x.org/reference/native-cpp/d4/de7/classcocos2d_1_1_c_c_sprite.html#a4410a015719defb1aa4ca40c8762d7ad



画像のファイル名と矩形を指定して切り出す CCSprite::create メソッドがありました。

static CCSprite* create( const char *  pszFileName, const CCRect &rect )

これが使えそうです。


さっそく、先のHelloWorld.png読み込み処理を、矩形を切りだして16のスプライトを生成する処理に書き換えます。

// add "HelloWorld" splash screen"
CCSprite* pSprites[16]; // 16個分のスプライトの配列を用意する
const int PIECE_SIZE = 64; // ピースのサイズをとりあえず16ピクセルとする
int ix=0;
for (int y=0;y<4; y++) {
for (int x=0;x<4; x++) {
CCRect rect(float(x*PIECE_SIZE), // X座標
float(y*PIECE_SIZE), // Y座標
float(PIECE_SIZE), // 幅
float(PIECE_SIZE)); // 高さ
pSprites[ix] = CCSprite::create("HelloWorld.png", rect);
ix++;
}
}

pSprites はCCSpriteのポインタの16個の配列です。配列はその場でスタック上にメモリを割り当てられますので、Javaのようにnew をする必要はありません。
CCRect のメンバーは x, y, width, height となっています。AndroidのJavaで用意されているRect は left, top, right, bottom なので違いに注意する必要があります。
http://www.cocos2d-x.org/reference/native-cpp/da/d4d/classcocos2d_1_1_c_c_rect.html#aa270b18ac7ce93be45f31a8bee71eeec

これで16個のスプライトを用意出来ました。


・スプライトを画面に表示
生成したスプライトを画面に表示してみましょう。表示の方法は元のHello Worldソースを参考にします。


Classes/HelloWorldScene.cpp から
    // position the sprite on the center of the screen
    pSprite->setPosition( ccp(size.width/2, size.height/2) );

    // add the sprite as a child to this layer
    this->addChild(pSprite, 0);

スプライトにsetPosition で表示座標を設定しaddChild でレイヤに追加しているようです。
ここで、Cocos2dにおける座標の扱いについて知っておく必要があります。
先ほど、CCSprite::create で画像から矩形を切り出しましたが、その時に指定した座標はAndroidプログラマーにはおなじみの左上が原点の座標でした。
ところが、Cocos2d-xの表示座標は左下が原点になっています。つまりY座標が逆転しています。これは、Cocos2dのベースとなっているOpenGLの仕様に合わせたものと思われます。
先程の、スプライト生成処理に、表示座標計算と座標設定処理を加えて書き換えます。

// add "HelloWorld" splash screen"
CCSprite* pSprites[16]; // 16個分のスプライトの配列を用意する
const int PIECE_SIZE = 64; // ピースのサイズをとりあえず16ピクセルとする
const int GAP = 2; // ピース間の隙間
int ix = 0;
int posy,posx; // 表示位置座標要変数
for (int y=0;y<4; y++) {
posy = size.height/2 - ((PIECE_SIZE+GAP) *(y-2)); // Y座標算出

for (int x=0;x<4; x++) {
posx = size.width/2 + ((PIECE_SIZE+GAP) *(x-2)); // X座標算出

CCRect rect(float(x*PIECE_SIZE), // X座標
float(y*PIECE_SIZE), // Y座標
float(PIECE_SIZE), // 幅
float(PIECE_SIZE)); // 高さ
pSprites[ix] = CCSprite::create("HelloWorld.png", rect);

// position the sprite on the center of the screen
pSprites[ix]->setPosition( ccp(posx,posy) );

// add the sprite as a child to this layer
this->addChild(pSprites[ix], 0);
ix++;
}
}

ビルドして実行してみます。


15パズルっぽい表示が出来ました。
元絵が15パズル向きではないですが、別の絵に差し替えれば問題はないでしょう。
あとは、1ピース抜いてタッチ操作でピースをスライドさせられるようにすれば、15パズルっぽい何かの完成です。
実装方法は、今から調べます。

今回のポイント:
・Cocos2dはスプライトを使っている
・スプライトは画像から矩形を切り出して生成できる
・Cocos2dの表示座標系は左下が原点

0 件のコメント:

コメントを投稿