cocos2dでマルチタッチを検出する
マルチタッチ用のタッチ判定メソッド
今まで使っていたccTouchBeganやccTouchMovedといったメソッドは引数(UITouch*)を見てもわかるように、一つのタッチオブジェクトしか取得できません。
マルチタッチを扱うためには一度に2つや3つのタッチオブジェクトを取得しなければなりません。そのためにcocos2dでは複数のタッチオブジェクトを一度に取得できる”ccTouchesBegan”や”ccTouchesMoved”が用意されています。
「Touch」が「Touches」になているので間違わないように使用してください。 これらのメソッドはUITouch*の代わりにNSSetという集合データを取得しています。この集合データの中身がタッチオブジェクトなのです。
前回までのタッチ判定メソッドをすべて書き換えて、HelloWorldLayerを以下のようにしました。
#import "HelloWorldLayer.h" #import "AppDelegate.h" @implementation HelloWorldLayer +(CCScene *) scene { CCScene *scene = [CCScene node]; HelloWorldLayer *layer = [HelloWorldLayer node]; [scene addChild: layer]; return scene; } -(id) init { if( (self=[super init]) ) { CGSize wSize = [[CCDirector sharedDirector] winSize]; CCSprite* circleGreen = [CCSprite spriteWithFile:@"green_circle.png"]; [self addChild:circleGreen z:0 tag:tagCircleGreen]; circleGreen.position = ccp(wSize.width/2, wSize.height/2); } return self; } -(void)onEnter { [super onEnter]; [[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES]; } -(void)onExit { [super onExit]; [[[CCDirector sharedDirector] touchDispatcher] removeDelegate:self]; } -(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"Touched"); } -(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"on Move"); } -(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"Ended"); } - (void) dealloc { [super dealloc]; }
重要な部分はccTouchesBegan、ccTouchesMoved、ccTouchesEndedです。他は大して変更していません。
さて、これで実行してみるとどうでしょう。タッチが検出されませんね。
シングルタッチの時はccTouchBeganがBOOL型で、タッチを受け入れるかどうかをreturnで返していました。一方、ccTouchesBeganはvoid型でそのような判定を行う機能がありません。 ではどのようにタッチを判定するのでしょうか。
ccTouchesメソッド群を機能させるためにはCCLayerクラスのプロパティの一つである”isTouchEnabled”をオンにしてやらないといけません。 init内でこれをオンにしてやりましょう。
-(id) init { if( (self=[super init]) ) { CGSize wSize = [[CCDirector sharedDirector] winSize]; self.isTouchEnabled = YES; /*タッチ検出を有効化*/ CCSprite* circleGreen = [CCSprite spriteWithFile:@"green_circle.png"]; [self addChild:circleGreen z:0 tag:tagCircleGreen]; circleGreen.position = ccp(wSize.width/2, wSize.height/2); } return self; }
これは大変便利なプロパティで、好きなタイミングで呼び出せます。したがって、タッチを有効化したいときにはこのプロパティにYESを、無効化したいときにはNOを渡してやれば、好きなタイミングで、タッチをコントロールすることができます。
これで実行してみるとタッチに反応するのが確認できます。
ちなみにこの”isTouchEnabled”はタッチデリゲートへの登録、解除も同時に行なってくれるので、シングルタッチの時にonEnterやonExitに記述していた”addTargetedDelegate”メソッドなども記述する必要がありません。
-(void)onEnter { [super onEnter]; //[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES]; } -(void)onExit { [super onExit]; //[[[CCDirector sharedDirector] touchDispatcher] removeDelegate:self]; }
マルチタッチの有効化
最後に行うのがマルチタッチの有効化です。今までの処理は、いわば準備段階。マルチタッチも受け入れられるメソッドを準備していたに過ぎません。
マルチタッチの有効化はAppDelegate.m内で行うのが通例です。
AppDelegateの「- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions」内に書いておけば、アプリが起動した際に有効化できます。 以下のように宣言します。
// Enable multiple touches [glView setMultipleTouchEnabled:YES];
glViewはこのアプリの描画に使われる画面を指し、前半で「CCGLView *glView = [CCGLView viewWithFrame:….」のように生成されているはずです。
この生成が終わったあとならどこでもいいので”setMultipleTouchEnabled”プロパティをオンにしてやれば、マルチタッチが有効化されます。
シミュレータでのマルチタッチ
シミュレータでのマルチタッチの行い方を一応書いておきます。
「alt」or「option」キーを押せば2つのカーソルが現われるはずです。これでマルチタッチができます。
ちなみに平行移動は「shift」+「alt」or「option」キーです。これプラスドラッグもしながらの操作になるので、なかなか使いづらいですが、一応シミュレータでもマルチタッチはシミュレートできます。
マルチタッチの判定
さて、準備は整ったので、マルチタッチを判定してみましょう。
今回は簡単に、タッチの数だけをみてマルチタッチ、シングルタッチを判断してみます。 タッチの数は引数NSSetに入っているオブジェクトの数を見ることで判断できます。ccTouchesメソッド群を以下のように書き換えました。
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { if(touches.count == 2) { NSLog(@"multi touch detected"); } else if(touches.count == 1) { NSLog(@"single touch detected"); } else { NSLog(@"more"); } } -(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { if(touches.count >= 2) { NSLog(@"on Move"); } } -(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { if(touches.count >= 2) { NSLog(@"Ended"); } }
実行すると、マルチタッチの時だけ”on Move”と”Ended”が出力されます。
このようにtouchesのカウントを調べることで判断することができます。
次回はもう少しタッチオブジェクトの扱い方を見て行きたいと思います。