2011/04/29

cocos2dでスクロールするレイヤーを作りました

いわゆるUIScrollViewみたいなやつです。
でもメソッドの命名とかはかなり自分勝手にやってるから使いづらいかもですけど。

CCScrollLayer.zip←ここからダウンロードできます

これ単体で使うには、以下のようにします。
CCScrollLayer *layer = [CCScrollLayer node];
[layer setScrollAreaWithMinPosition:ccp(0,0) maxPosition:ccp(0,1024)];
[layer schedule:@selector(moveScroll)];

と、これでタッチイベントを検出してスクロールします。
上のソースでは縦に0から1024までの座標でスクロール可能です。

2行目を
[layer setScrollAreaWithMinPosition:ccp(0,0) maxPosition:ccp(1024,1024)];
[layer setHorizontalScrollEnable:YES];

のようにすれば縦横にスクロールします。

デフォルトでは縦スクロールが可能になるようにセットされているので、
横だけのスクロールにするんであれば、設定を変えてください。
[layer setScrollAreaWithMinPosition:ccp(0,0) maxPosition:ccp(1024,0)];
[layer setHorizontalScrollEnable:YES];
[layer setVerticalScrollEnable:NO];

とまあこんな感じです。

2011/04/06

pngSplitter修正しました


全角の要素名が対応してなかったので、バグ修正しました。
あと、ドラッグ&ドロップとかに地味に対応。
アイコンの位置も使いやすいように位置を変更。
などなど。

ダウンロード:pngSplitter.zip (要wxPython)

pngSplitterを作りました


cocos2dで複数のフレームを1枚のテクスチャに描いたりしてると、再配置したくなったり使用する際の切り出し座標を知りたくなったりなどいろいろ苦労すると思いますが、再配置はTexture Packerという便利なツールがあるのでいいんですけど、ドット絵を描く時は色とか揃えたりするのにそのキャラの全パターンが1枚になってたほうが便利だったりとかありますよね。

で、このツールなんですが、たとえばフォントテクスチャをプロポーショナルで作ったときの切り出し用のPLISTが欲しい時に使えます。

あと、キャラのパターンを1枚で描いてたけど最終的にTexture Packerでまとめ直したい場合にも使えます。これで切り出しの枠を設定しておいて、バラのPNGを吐き出せばOK。

てな感じのツールです。
pythonの勉強を兼ねて作りました。

使用するには、pythonとwxPythonが必要なので、インストールしてくださいな。
ではでは。

pngSplitterをダウンロードする(ソース付きだよ)

2011/04/03

2Dの壁コリジョンをどうやって計算する?

先日思いついた2Dゲームで壁との衝突判定をどうやって行うかについてまとめておきます。

スーパーマリオやチャレンジャーなどファミコン時代によく遊んだ2Dゲームで壁に衝突すると壁に潜ってしまう方向の移動要素以外は生きて横に移動するというような操作を覚えている人も多いかと思います。
これはそんな感じにするための衝突判定です。

例えば横にのびている壁に斜めにあたった場合に、縦の移動は阻害されるけど、横への移動は許可されるというようなことです。

以下の図を見てください。
青い四角はキャラクター。
緑の四角は壁、白い矢印はキャラクターの移動方向となります。



壁に衝突する際に、キャラクター移動後のA,B,Cの3点での潜りを調べます。
キャラクターの進行方向にしたがって調べるべきA,B,Cの位置は変化しますが、要は移動に関係する3点です。

まずは左上の図を元に説明すると、
1:A,B,Cのすべてが潜らなければ希望する移動は許可される。
2:1でいずれかが衝突する場合には縦横どちらか、あるいは両方の移動が阻害されるので3以降の判定を行う。
3:Cが潜らなければ横方向の移動を許可し、縦方向は阻害される。


左下の図の場合は、
4:Aが潜らなければ縦方向の移動を許可し、横方向は阻害される。

さらにL字の壁の隅に移動しようとした場合などが当てはまりますが、
5:C,Aの両方が潜る場合はすべての移動が阻害される。

とすることでうまいこと壁との衝突を調べることが出来ます。

なお、派生系として右上と右下の場合もキャラクターのサイズを考慮して壁の角との潜りを調べて対応できます。
(おかしな判定を行うと角ギリギリを攻めると半分埋まりながら移動可能になってしまったりしますからね)

てなわけで、壁との判定をまとめてみました。
ひょっとすると1での判定はBのみの潜りを調べることで済むかもしれませんが、どうなんでしょう。

2011/04/02

cocos2dのvertexZパラメータでソートしたい

cocos2dのCCSpriteを多数表示して、Y座標によって奥から手前へのソートを行うことで以下のような表示をする場合に、



簡単に行うには、CCSpriteクラスの中のupdateメソッドなどで現在のY座標を元にソートしなおすことを繰り返すと良いのですが。
たとえば、以下のようなコードですね。

-(void)update:(ccTime)delta {
  [self.parent reorderChild:self z:-position.y];
}

これでは結構処理が無駄になるのではないかと心配になりますよね。
で、vertexZプロパティを使うとOpenGLのZバッファを参照して前後比較をして描画してもらえるので、それを使って処理を軽くしたいと思います。
こんな感じです。

-(void)update:(ccTime)delta {
  self.vertexZ = -position.y;
}

こうすると、前後比較は正しくなるのですが、キャラクターの透明部分までZバッファに描かれてしまって四角い枠が見えるようなおかしな描画になってしまいます。
そこで、さらに以下のメソッドをオーバーライドといい感じになります。(ALPHA_TESTで透明部分はそもそも描画しないということを行ってキャラの絵が描かれている部分のみZ値を書きこむようにするということです)

-(void)draw {
  glEnable(GL_ALPHA_TEST);
  glAlphaFunc(GL_GREATER, 0.0f);
  [super draw];
  glDisable(GL_ALPHA_TEST);
}

これで万事解決ですね。
と思いますよね。
でも、さらに高速化しようとしてCCSpriteBatchNodeを使い始めると、上記のCCSpriteに設定したdrawメソッドが呼ばれなくなるために、せっかく設定したALPHA_TESTが無効化されてしまいます。
その場合は、CCSpriteBatchNodeの方のdrawをオーバーライドしましょう。
こんな感じです。(CCSpriteBatchNodeのdrawはDEPTH_TESTがデフォルトで無効になっているので、その設定も追加しています)

-(void)draw {
  glEnable(GL_DEPTH_TEST);

  glEnable(GL_ALPHA_TEST);
  glAlphaFunc(GL_GREATER, 0.0f);
  [super draw];
  glDisable(GL_ALPHA_TEST);

  glDisable(GL_DEPTH_TEST);
}

以上で楽しいcocos2dライフを送りましょうー。

cocos2dでマルチタッチを取得するには

cocos2dで用意されているCCLayerには以下のようなタッチイベントを有効化するためのメソッドが用意されていますが、マルチタッチをビューに対して有効にするか否かの設定はこれでは行えません。

[self setIsTouchEnabled:YES];

そんなわけで、以下のようにcocos2dのEAGLViewが乗っているウインドウかビューに対して、マルチタッチ有効化を宣言する必要があります。

[window setMultipleTouchEnabled:YES];
あるいは
[glView setMultipleTouchEnabled:YES];
などです。

これで、ccTouchesBeganなどでマルチタッチを取得できるようになりますが、この後少し注意が必要です。
たとえばタイトル画面や他の画面などで画面をタッチすると次のシーンへ移行するというような仕組みになっていた場合に、シングルタッチの場合は速度的に連打してもシーンの移り変わりの再コール行われた場合にほぼ問題なく次のシーンへ移行できるのですが、マルチタッチの場合は連打の間隔が極端に短く取得されることもありえますので、シーン移行中の場合は再コールされても応答しないようなコードを追加しておかないとシーンの移行が正しく終わらないうちに次への移行が呼ばれたりして落ちる場合があります。