だいたい47度

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

PageTop

CCMenuAdvancedのboundaryRectについて

CCMenuAdvancedのboundaryRectについて、少し混乱したのでメモ。

cocos2d-extensionのCCMenuAdvancedは、CCMenuなのだけど、menuそのものを動かすこともできるという便利なクラス。menuの項目が描写したい領域に収まらないときに使うのが便利です。

ただmenuが完全に自由自在に動かせてしまうとマズイです。例えば、menuを縦方向にのみ動かせるようにしたい場合、横方向へは動かせないようにしなくてはいけません。

そこでmenuの動作を規定するために、boundaryRectというプロパティにCGRectを登録してやります。すると「menu.boundingBoxはboundaryRectを内包する場合にのみ動ける」ようになります。例えて言うならば、menu描画領域が輪投げの輪、boundaryRect領域が輪投げの軸という感じです(わかりづらい?)。

縦にしか移動できないCCMenuAdvancedを作りたいのであれば、boundaryRectの幅をmenu.contentSizeの幅と同じにしてあげればよいわけです。更に、menuが一番下まで移動した時にmenuの一番上が引っかかる部分をboundaryRectの上辺、逆にmenuが一番上まで移動した時にmenuの一番下が引っかかる部分をboundaryRectの下辺としてあげることになります。

boundaryRectがmenu描画領域からハミ出てしまう場合は、boundaryRectの右上が標準となります。例えば、boundaryRectにmenuが完全に内包されてしまう場合は、boundaryRectの右上とmenuの右上が揃う形で固定されます。その場合、スクロールはできません。また、boundaryRectの縦幅はmenu描画領域に収まるものの、横幅が収まらない場合は、menuは右軸に固定され、上下動はできる形になります。

boundaryRectに従う動きは、CCMenuAdvancedのfixPositionメソッドで実装されています。fixPositionは、ccTouchMoveである程度以上の動きが感知されるたびに呼び出され、ハミ出ている場合はmenuの位置を補正します。

よって、CCMenuAdvancedをaddする場合は、positionは適当にしておいて、boundaryRectを設定後にfixPositionを呼び出してあげるのが簡単そうです。

//画面左端で縦方向に動かせるCCMenuAdvanced
//必要なCCMenuItemがitemArrayに格納されているとする
CCMenuAdvanced* menu = [CCMenuAdvanced menuWithArray:itemArray];
[menu alignItemsVerticallyWithPadding:5.0f bottomToTop:NO];
CGSize screenSize = [[CCDirector sharedDirector] winSize];
menu.boundaryRect = CGRectMake(0, 0, menu.contentSize.width, screenSize.height);
[menu fixPosition];//boundaryRectの右上に揃う

スポンサーサイト

PageTop

CCMenuItemに簡単にtoggle機能を付加

cocos2d-extensionのCCAdvancedMenuにおいて、CCMenuItemSpriteに「選択すると選択された状態画像が維持され、同menu内の他のボタンが押されたときに非選択状態画像に変わる」機能を付けたいと思いました。結果的にCCMenuでも使えるものになっているのと、単純な話なのに混乱して2-3時間悩んだので、メモがてら公開。

CCMenuItemToggleに、normalImageとselectedImageを良い感じにしたCCMenuItemSpriteを付加する方法もありますが、すでにあるボタンに関して書き換える量が多いので、CCMenuItemSpriteを上書きすることで実装しました。

まずメソッドtoggleとuntoggleを実装します。それぞれのvisibleを書き換えてやるだけの処理です。toggle状態をisToggledで管理します。

//CCMenuItemSpriteToggle.m
@implementation CCMenuItemSpriteToggle{
BOOL _isToggled;
}

- (void)toggle{
_isToggled = YES;
[normalImage_ setVisible:NO];
[selectedImage_ setVisible:YES];
[disabledImage_ setVisible:NO];
}
- (void)untoggle{
_isToggled = NO;
[normalImage_ setVisible:YES];
[selectedImage_ setVisible:NO];
[disabledImage_ setVisible:NO];
}
//続く


あとはこれらのメソッドを呼び出す箇所を決めます。

まずはtoggleの呼び出し箇所を考えます。

CCAdvancedMenuのタッチ開始時と終了時の処理はCCMenuと同じです。タッチ開始時にCCMenuItemのselectedを呼び出し、指を離すとunselected→activateの順で呼び出します。selectedではnormalImageのvisibleをNOにし、selectedImageのvisibleをYESにします(toggleと同じ描画)。unselectedではその逆の動作を行います(untoggleと同じ描画)。activateは設定した関数を呼び出します。

よって、activate内でtoggleを呼び出せばよいように思いますが、それだけではダメです。CCAdvancedMenuでは、ある程度以上の距離をドラッグすると、ccTouchMovedメソッドの中でunselectedが呼び出されるようになっているのです。そのため、toggleされているボタンをタッチしてドラッグ操作をするとunselectedが呼ばれ、描画が元に戻ってしまいます。

以上のことからunselectedを上書きする必要があります。単純に無効化するだけでは、ccTouchCancelledのunselectedも効かなくなり、toggleされていないボタンからドラッグを開始した際にselectedされたままになってしまうので、以下のようにオーバーライドします。これでtoggle側の呼び出しはおしまいです。

//続き
- (void)activate{
[self toggle];
[super activate];
}

- (void)unselected{
[super unselected];
if (_isToggled) { [self toggle]; }
}
@end


次にuntoggleの呼び出し箇所を考えます。

untoggleは同じmenu内の他のボタンが押された場合に呼び出されるべきなので、CCMenuItemSpriteToggleの外から呼び出します。現在toggleされているボタンを認識できるようにしておき、menu各ボタンが押された時にtoggleされているボタンのuntoggleを呼び出せばOKです。


以上、後は普通のCCMenuItemSpriteと同じように使えます。CCMenuItem自体に実装すればもっと広範に使える気もします。更にCCMenuのサブクラスも作ったりもできそうです。

PageTop
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。