I am trying to figure out touch handling on multiple CCNodes .
I have
Main CCLayer
------> z:2 Hud CCNode
On main layer I choose an object, on hud layer I want to control it. I followed this q&a its very helpful Cocos2d handling touch with multiple layers
On Main Layer touch events, below is Hud Node work:
-(void) registerWithTouchDispatcher
{
[[CCDirector sharedDirector].touchDispatcher addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
-(BOOL) ccTouchBegan:(UITouch*)touch withEvent:(UIEvent*)event
{
//detects touched Object and sends it to hud
if (object != nil)
{
//sends it to hud
return true;
}
return false;
}
-(void) ccTouchMoved:(UITouch*)touch withEvent:(UIEvent*)event
-(void) ccTouchEnded:(UITouch*)touch withEvent:(UIEvent*)event
-(void) ccTouchCancelled:(UITouch*)touch withEvent:(UIEvent*)event
On Hud CCNode none of ccTouchBegan/moved/ended methods are fired
-(void) registerWithTouchDispatcher
{
[[CCDirector sharedDirector].touchDispatcher addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
-(BOOL) ccTouchBegan:(UITouch*)touch withEvent:(UIEvent*)event
{
if (object!=nil) {
NSLog(#"Touch began");
return YES;
}
else
return NO;
}
EDIT:
I have a button to set speed of the object on HUD Node , it has nothing to do with object!=nil because when I put breakpoints I see that -(BOOL) ccTouchBegan:(UITouch*)touch withEvent:(UIEvent*)event is never called
-(void)speed1Tapped:(id)sender
{
if (object!=nil) {
NSLog(#"Moving Object is %#:",object!=nil);
}
}
On Log I get:
object is <ObjectATC: 0x13763850>
Why ccTouchBegan/moved/ended methods are not fired in CCNode?
How can I handle touches on multiple CCNodes, CCLayers ?
I guess you dont receive touch method because you did not register the touchDipatcher
either in your CCNodes init method or onEnter method try to register it.
//register touches
- (void)onEnter {
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
[super onEnter];
}
- (void)onExit {
[[[CCDirector sharedDirector] touchDispatcher]removeDelegate:self];
[super onExit];
}
In your touch methods, you have a conditional that says if (object != nil), but object is not defined anywhere in the code that you have shown. Is it defined elsewhere? Otherwise, this is why it is not firing.
Related
I am developing a cocos2d game where I have a CCLayer named GamePlaylayer and another CCLayer named ShopLayer. ShopLayer is a fullscreen layer. GamePlayLayer is touchenabled and has multiple buttons (CCMenuItemImage). ShopLayer is accessed from a shop button which has the following #selector.
(void) onClickShop {
ShopLayer * shop = [[ShopLayer alloc] init];
[self addChild:shop z:40]; }
To stop touch propagation I used CCTouchOneByOneDelegate and the following methods in the ShopLayer.
(void) onEnter {
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self
priority:0 swallowsTouches:YES];
[super onEnter];
}
(void) onExit {
[[[CCDirector sharedDirector] touchDispatcher] removeDelegate:self];
[super onExit];
}
(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
return YES;
}
Now it stops ccTouchesBegan of the GamePlayLayer to be called which is fine. But it cannot stop other buttons of the GamePlayLayer to be called. So when I touch at positions where the buttons of GamePlayLayer are placed, they get called even though I can not see them.
So my question is how to stop clicking buttons of lower layer from upper layer?
use kCCMenuHandlerPriority for the touch priority
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:kCCMenuHandlerPriority swallowsTouches:YES];
SetTouch priority kCCMenuHandlerPriority of this class.
I have a serious problem with Cocos2d.
1) I have one scene with few buttons in it
2) I have another scene in which i use
-(void) onEnter {
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowTouches:YES];
[super onEnter];
}
and also
-(void) onExit {
[[[CCDirector sharedDirector] touchDispatcher] removeDelegate:self];
[super onExit];
}
3) After replacing 1st scene to the 2nd everything is ok
4) But after returing to 1st scene (by replaceScene) all buttons on 1st scene are blocked. Nothing works
5) If i'm not using "removeDelegate" in "onExit()" buttons on 1st scene work, but touches from the 2nd scene are still active.
So let me clarify first off with showing what code i have implemented
-(BOOL)canBecomeFirstResponder
{
return YES;
}
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self becomeFirstResponder];
}
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated
{
[self resignFirstResponder];
[super viewWillDisappear:animated];
}
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion == UIEventSubtypeMotionShake)
{
NSLog(#"FUUU");
}
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion == UIEventSubtypeMotionShake)
{
NSLog(#"FUUU");
}
}
this is all in a UIViewController class
and in - (void) applicationDidFinishLaunching:(UIApplication*)application i have set
[application setApplicationSupportsShakeToEdit:YES];
Yet it does nothing, not nary single motion detected. I'm not sure what else to do. This seems to have worked for many other people, so i am baffled as to why i am different...Could it be because it's through a UINavigationController? or because i load the main application via a plist and my main looks like so
retVal = UIApplicationMain(argc, argv, nil, nil);
I am quite thoroughly stumped.
In order to detect shake gesture you need to subclass the UIView and implement the following methods (Do not implement these methods on UIViewController):
(BOOL)canBecomeFirstResponder
(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
Then add the subclassed view to UIViewController and make it first responder by calling -becomeFirstResponder on it.
You don't need to set [application setApplicationSupportsShakeToEdit:YES]; because this is the default value and iOS use this only for Shake to Undo/Redo.
If you want to capture the motion in your view controller you need to set this property to NO [application setApplicationSupportsShakeToEdit:NO]; and handle it by yourself.
As described in Event Handling Programming Guide.
Hope this helps.
PS: Just in case, you call the wrong super in your viewDidAppear method. This should be :
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self becomeFirstResponder];
}
Thank you all for your responses but i ended up using a different method i accessed the accelerometer in the app delegate and then send a nsnotifcation via the nsnotification center to the current ui navigation controller displayed
- (void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
[[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:nil userInfo:nil];
}
If a notification(i.e., a UIAlertView) appears while touching the screen (or home button is being pressed), ccTouchEnded will be called in game layer, but at the touch will already have ended.
How can I determine when the touch ends?
Check out the apple reference for UIResponder:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIResponder_Class/Reference/Reference.html
You probably want
touchesEnded:withEvent:
Hope this helps :)
You should implement ccTouchesCancelled. This will occur whenever a touch event is interrupted.
Just check how many touch objects you have.
if([touches count] == 0)
{
//NO TOUCHES
}
-Make your scene conforms to protocol CCTargetedTouchDelegate
-Add This line to init of your scene:
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:NO];
-Implement these functions:
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
return YES;
}
-(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
//here touch is ended
}
I've already know how to catch the shake gesture with the code below
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if ( event.subtype == UIEventSubtypeMotionShake )
{
// Put in code here to handle shake
NSLog(#"Device Shaked");
}
if ( [super respondsToSelector:#selector(motionEnded:withEvent:)] )
[super motionEnded:motion withEvent:event];
}
The NSLog shows that it did received the shake
but how to push another view,or back to the last view, as we know the code below can only use in ViewController class instead of View class, this Leavesview is handle by a LeavesviewController, and I use this viewController in another PDFViewController to display, so how could I make it jump to another view or dismiss back???
UIViewController *myView = [[UIViewController alloc]init];
[self.navigationController pushViewController:myView animated:YES];
See this complet Code......
- (BOOL) canBecomeFirstResponder {
return YES;
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (event.subtype == UIEventSubtypeMotionShake)
{
// Work which you want
}
}
also dont forget these two methods...
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self becomeFirstResponder];
}
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
[self resignFirstResponder];
}
Ok, Obviously I am just a starter 2 months ago. Also, obviously the answer is the Delegation;