Cocos2d supports two different ways of handling touch events. These are defined by two different types of delegates (both defined in CCTouchDelegateProtocol.h).
@protocol CCStandardTouchDelegate <NSObject> @optional - (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; - (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; - (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - (void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; @end
These are the same sorts of events you'd get in a standard CocoaTouch app. You'll get all events, and all touches; it will be up to you to sort out which touches you care about in a multi-touch environment.
To get these events in a CCLayer subclass, you simply set isTouchEnabled = YES, like so:
self.isTouchEnabled = YES;
@protocol CCTargetedTouchDelegate <NSObject> - (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event; @optional // touch updates: - (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event; - (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event; - (void)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event; @end
Note two important differences between this one and the standard touch delegate:
So ccTouchBegan will be invoked separately for each of the available touches, and you return YES to indicate a touch you care about. Only touches claimed by ccTouchBegan will be subsequently passed on to the Moved, Ended, and Cancelled events (all of which are optional).
To receive these events, you must register as a targeted touch delegate with the global dispatcher. In a CCLayer subclass, override registerWithTouchDispatcher as follows:
-(void) registerWithTouchDispatcher
{
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
(which will mean importing “CCTouchDispatcher.h” at the top of your file).
Apart from the more complex registration, the targeted touch delegate is generally easier to use, since you don't have to split the NSSet up yourself, and you don't have to keep checking whether the event is the one you want in the Moved/Ended/Cancelled events. But if you want to deal with multiple touches in one method (for example, because you combine them into a zoom or rotate input), you'll probably want to use the standard touch delegate instead.
Note that you can only use one or the other.
To recieve multi-touch events, you have to activate them. You can do this by adding the following code in your AppDelegate's applicationDidFinishLaunching:
[glView setMultipleTouchEnabled:YES];
The above discussion of isTouchEnabled and registerWithTouchDispatcher only applies to CCLayer and its subclasses (notably CCMenu, which already does all this). To touch-enable other classes, slightly more work is required:
The latter point is handled for you in a CCLayer with isTouchEnabled but manually, will look something like this:
For CCStandardTouchDelegate
- (void)onEnter
{
[[[CCDirector sharedDirector] touchDispatcher] addStandardDelegate:self priority:0];
[super onEnter];
}
For CCTargetedTouchDelegate
- (void)onEnter
{
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
[super onEnter];
}
And for both
- (void)onExit
{
[[[CCDirector sharedDirector] touchDispatcher] removeDelegate:self];
[super onExit];
}
Calling NSLog or CCLog within ccTouch or ccTouches handlers will abnormally reduce the performance of your app.