Cocos2d - Touch Events

In this chapter we will discover how easy it is to handle touch events on sprites and bezier tile shapes with LevelHelper.

Using LevelHelper you can register your own methods that will be called when a touch event will be triggered on a specific sprite or bezier node.
You can also register your own methods that will be called on sprites or bezier nodes of a certain tag.

How touches are handled using LevelHelper


In the following image the sprite object is defined by the green rectangle and the blue line and dots represents the physic shape defined for that sprite inside SpriteHelper.
In this case, because the sprite has a physic shape defined, the touch will be handled only in the inside area of the physic shape, as showed in the following image by the blue tint area.


Note:
If you want the touch area to be bigger then the actual sprite, you can define a physic shape rectangle that is bigger then the sprite.

In the case where the sprite has no physic shape defined, the touch will be handled in the inside area of the entire sprite, as showed in the following image by the blue tint area.

Handle touch on a specific sprite

To handle touch on a specific sprite, we just get the pointer to that sprite and then register our callbacks for the specific touch event.
In this example I will register for all touch events, but you are not required to do so.
LHSprite* mySprite = [lh spriteWithUniqueName:@"MySpriteName"];
        
[mySprite registerTouchBeginObserver:self selector:@selector(touchBegin:)];
[mySprite registerTouchMovedObserver:self selector:@selector(touchMoved:)];
[mySprite registerTouchEndedObserver:self selector:@selector(touchEnded:)];

Here we registered our methods that will be called when a touch event occurs.
You can name your methods however you like, but the signature needs to be the same.
Here is the definition of the methods:
-(void)touchBegin:(LHTouchInfo*)info{
    if(info.sprite)
    NSLog(@"Touch BEGIN on sprite %@", [info.sprite uniqueName]);        
    
    if(info.bezier)
        NSLog(@"Touch BEGIN on bezier %@", [info.bezier uniqueName]);        
}

-(void)touchMoved:(LHTouchInfo*)info{
    if(info.sprite)
    NSLog(@"Touch MOVED on sprite %@", [info.sprite uniqueName]);            

    if(info.bezier)
        NSLog(@"Touch MOVED on bezier %@", [info.bezier uniqueName]);        
}

-(void)touchEnded:(LHTouchInfo*)info{
    if(info.sprite)
    NSLog(@"Touch ENDED on sprite %@", [info.sprite uniqueName]);        
    
    if(info.bezier)
        NSLog(@"Touch ENDED on bezier %@", [info.bezier uniqueName]);        
}

Understanding the touch info

As you can see in the methods declaration we have a LHTouchInfo object that is given to us.
The following table shows the info that can be taken out from the object.

info.relativePoint CGPoint - Relative point of the touch point on a sprite. More info later on this page.
info.glPoint CGPoint - The touch point converted to OpenGL coordinates
info.delta CGPoint - How much a touch has moved from the last call. This returns a zero point on touch begin events.
info.eventUIEvent* - The actual touch event
info.touch UITouch* - The actual touch object
info.sprite LHSprite* - The sprite on which the event was triggered. This is NULL when touch has been performed on a bezier tile shape.
info.bezierLHBezierNode* - The bezier node on which the event was triggered. This is NULL when touch has been performed on a sprite.


Notes:
In the callback methods always check agains
info.sprite
and
info.bezier
in order to know what object type has triggered the touch event and handle your game logic accordingly. Failing to do so may crash your game.

The relativePoint in LHTouchInfo

This is a CGPoint object that will represent a point relative to the origin of a LHSprite (CCSprite).
This info is not available on bezier tile shapes touch events.

In the followin image, the yellow point represents the sprite position (center point).
The black lines represents the 4 quadrands of the sprites based on its position.
Based on where on the sprite the touch has been performed, the relativePoint info will return a point that is the difference between the touch point and the position of the sprite.

As displayed in the image, the relative point will have positiv values for the first quadrant, positive x values and negative y values for the second quadrant, negative x and negativ y values for the third quadrant and negative x and positive y for the fourth quadrant.

Handle touch on a specific bezier tile shape

To handle touch on a specific bezier tile shape, we just get the pointer to that bezier object and then register our callbacks for the specific touch event.
In this example I will register for all touch events, but you are not required to do so.
LHBezierNode* bezier = [lh bezierNodeWithUniqueName:@"Bezier_1"];
        
[bezier registerTouchBeginObserver:self selector:@selector(touchBegin:)];
[bezier registerTouchMovedObserver:self selector:@selector(touchMoved:)];
[bezier registerTouchEndedObserver:self selector:@selector(touchEnded:)];

Handle touch on all beziers and sprites of a certain tag

To handle touches on all sprites or beziers of a certain tag, you must use the LHTouchMgr class and register your callback methods agains the tag you want before loading the level file.
The following will demonstrate registration for 2 tags, but you can register on as many tags as you want.
As with the callback on a specific sprite or bezier node, you are not required to register to all touch events.
[[LHTouchMgr sharedInstance] registerTouchBeginObserver:self selector:@selector(touchBeginTAGOne:) forTag:TAG_ONE];
[[LHTouchMgr sharedInstance] registerTouchMovedObserver:self selector:@selector(touchMovedTAGOne:) forTag:TAG_ONE];
[[LHTouchMgr sharedInstance] registerTouchEndedObserver:self selector:@selector(touchEndedTAGOne:) forTag:TAG_ONE];        

[[LHTouchMgr sharedInstance] registerTouchBeginObserver:self selector:@selector(touchBeginTAGTwo:) forTag:TAG_TWO];
[[LHTouchMgr sharedInstance] registerTouchMovedObserver:self selector:@selector(touchMovedTAGTwo:) forTag:TAG_TWO];
[[LHTouchMgr sharedInstance] registerTouchEndedObserver:self selector:@selector(touchEndedTAGTwo:) forTag:TAG_TWO];        
        
lh = [[LevelHelperLoader alloc] initWithContentOfFile:@"LevelFile"];        
[lh addObjectsToWorld:world cocos2dLayer:self];

Swallow touches

In certain conditions you want the touch to be swallowed so that the touch does not go up the chain and trigger a touch event in your layer.
Here is how you can swallow the touches on objects of a certain tag.
Note: Only call this if you want to swallow the touches, if not, just don't call this method.
[[LHTouchMgr sharedInstance] swallowTouchesForTag:MY_TAG];

Priority of touches

In certain conditions you want the touch to have a special priority. The default priority for touches is 0.
So if you want another priority just call this method:
[[LHTouchMgr sharedInstance] setPriority:1 forTouchesOfTag:MY_TAG];