How to do you make Gesture Recognizers only accessible from one scene?
I have a simple cocos2d app with two scenes. I create a UITapGestureRecognizer like so in AppDelegate:
CCScene *gameScene = [GameLayer scene];
GameLayer *gameLayer = (GameLayer *) [gameScene.children objectAtIndex:0];
// Capture a tap
UITapGestureRecognizer *tapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:gameLayer action:@selector(handleTapFrom:)] autorelease];
[tapRecognizer setDelegate:viewController];
[viewController.view addGestureRecognizer:tapRecognizer];
[[CCDirector sharedDirector] runWithScene:gameScene];
That works great, I get the touch event, and everything is dandy. However, I want to switch to another scene for my pause screen, which I do like so:
PauseMenuScene *pauseMenu = [PauseMenuScene node];
[[CCDirector sharedDirector] replaceScene:pauseMenu];
When that scene launches however, if I touch anywhere on it it crashes. This seems to be because the touches are going to gameScene, which is in stasis.
How do I prevent this?
After andrewx confirmed my suspicion, I was able to solve this. I still couldn’t figure out how to add UIGestureRecognizers to individual scenes, but what I did instead was send the gestures to my delegate directly, and then have it parsel them out to my scenes. Here’s a snippet:
Create the gesture recognizer in AppDelegate (changed to direct to self):
UITapGestureRecognizer *tapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapFrom:)] autorelease];
[tapRecognizer setDelegate:viewController];
[viewController.view addGestureRecognizer:tapRecognizer];
Next, I made sure that I actually had a CCScene class for my main class (I was just going off the base HelloWord class so it only had a CCLayer class). That class looks like:
@implementation GameScene
@synthesize layer = _layer;
-(id) init
{
if (self = [super init])
{
self.layer = [GameLayer node];
[self addChild:_layer];
}
return self;
}
-(void) dealloc
{
[_layer release];
_layer = nil;
[super dealloc];
}
@end
And finally, I delegated the taps:
-(void) handleTapFrom: (UITapGestureRecognizer *) recognizer
{
CCScene *currentScene = [[CCDirector sharedDirector] runningScene];
if ([currentScene isKindOfClass:[GameScene class]])
{
GameLayer *gLayer = ((GameScene *) currentScene).layer;
[gLayer handleTapFrom:recognizer];
}
}
Your gesture recognizer is initialized with a target of one scene, but when you
replaceScene, that target no longer exists, right? So your gesture recognizer is trying to send touches to a layer that is not there. I suspect this is the cause of your crash.I recommend adding your touch controls to the individual cocos classes so each scene can handle touches on its own. When that scene is released and replaced by another one, it has its own touch recognizers also. This is much safer than adding touch controls to the App Delegate, which really isn’t the place (usually) for this type of scene-specific logic.