【cocos2d】タッチ情報取得用にレイヤーを分けてみた
今まではゲームのメインとなるレイヤーでタッチ情報を取得し、タッチイベントが発生する度に自分のキャラクターの位置情報を更新していました。オブジェクト指向的な考え方をすると、キャラクターの位置情報が別のオブジェクトから勝手に更新される事に違和感をずっと感じていました。
そこで、タッチ情報を取得するためのクラス(レイヤー)を新たに追加し、タッチ情報が必要なオブジェクトは能動的にそのクラスから情報を取ってくるようにプログラムの構造を修正します。
そこで作成したのが、このCCLayerを継承したTouchLayerクラスです。プロパティとして、現在タッチしてるかどうかのフラグtouchingとタッチの位置をcocos2dの座標で返すlocationを定義しています。どちらも他のオブジェクトから値の変更ができないようreadonlyを指定しています。
#import <Foundation/Foundation.h> #import "cocos2d.h" @interface TouchLayer : CCLayer { } + (TouchLayer *)sharedTouch; @property (nonatomic, readonly) BOOL touching; @property (nonatomic, readonly) CGPoint location; @end
実装はこのようになっています。どのクラスから使いやすいようにシングルトンパターンで実装しました。ヘッダファイルさえインポートしておけば[TouchLayer sharedTouch]でインスタンスを取得できます。
タッチ位置を取得するにはこのように使用します。
CGPoint touchLocaion = [TouchLayer sharedTouch].location;
タッチされていないときは最後にタッチしていた場所を返すようにしました。初めてタッチするまではタッチ位置の情報がないので画面中央より少し下の位置を返します。勝手に決めつけるのはあまり美しくないですが、割り切りました。
#import "TouchLayer.h" @implementation TouchLayer { BOOL _touching; CGPoint _location; } + (TouchLayer *)sharedTouch { static TouchLayer* sharedInstance = nil; if (sharedInstance == nil) { sharedInstance = [[self alloc] init]; } return sharedInstance; } - (id)init { if ((self = [super init])) { _touching = NO; CGSize winSize = [CCDirector sharedDirector].winSize; _location = ccp(winSize.width/2, winSize.height/4); self.isTouchEnabled = YES; } return self; } - (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { _touching = YES; UITouch *myTouch = [touches anyObject]; CGPoint location = [myTouch locationInView:[myTouch view]]; location = [[CCDirector sharedDirector] convertToGL:location]; _location = location; } - (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { _touching = YES; UITouch *myTouch = [touches anyObject]; CGPoint location = [myTouch locationInView:[myTouch view]]; location = [[CCDirector sharedDirector] convertToGL:location]; _location = location; } - (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { _touching = NO; // とりあえず_locationは前の位置を保持 } @end