Hi
Does anyone have anyone have an example on how to use the touch dispatcher on a sprite. I've looked at TouchesTest and MenuTest and I still don't understand it.
Please help.
-alex
touch dispatcher for dummies?
(45 posts) (8 voices)-
Posted 3 years ago #
-
You've looked at TouchesTest... you've probably missed the Paddle.m file. This is where the sprite registers to the
TouchDispatcherand receives the touches events in theccTouch____methods.Posted 3 years ago # -
yeah, I've had a look and its just too much information for me - I am a complete newbie. I'm wondering if someone can post an example where there would be a sprite and action directe to that sprite and its location ???
Posted 3 years ago # -
Hello Alex
It is not too hard to understand, just break it down to the basics.
in the .h file:
@interface Paddle : TextureNode <TargetedTouchDelegate> {
Register for TargetedTouches ^
You also need the PaddleState typedef and property (you can rename them - just be consistent).Then in the .m file:
In the init method - set the state to ungrabbed.In your onEnter and onExit you just need to register for targeted touches.
You need some way of detecting if your touch is in your object. The demo has a containsTouchLocation method - that uses the rect method of TextureNode - if you are not using a TextureNode, then you need to roll your own Rect method.
Finally, you can grab the ccTouch... functions - and it should all work fine.
Now, if you want another demo - go to this thread and grab the sample there (last link) - and I think I put some stuff in there. Hopefully.
http://www.cocos2d-iphone.org/forum/topic/364
Justin
Posted 3 years ago # -
this is just so complicated to understand. I've been sitting and trying various things for a few days and I can not get it to work. I can't get it to work because I do not understand.
All I want to do is to run the following action :
id scaleto = [ScaleTo actionWithDuration: 0.5 scale:0.5f];
id actionBy = [ScaleBy actionWithDuration: 0.5 scale: 2];
id actionByBack = [actionBy reverse];[self runAction: scaleto];
[self runAction: [Sequence actions:actionBy, actionByBack, nil]];return kEventHandled;
I can get it to work on a layer and I figured I could just add it to the demo in paddle.m and it would work:
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{if (state != kPaddleStateUngrabbed) return NO;
if ( ![self containsTouchLocation:touch] ) return NO;state = kPaddleStateGrabbed;
return NO;id scaleto = [ScaleTo actionWithDuration: 0.5 scale:0.5f];
id actionBy = [ScaleBy actionWithDuration: 0.5 scale: 2];
id actionByBack = [actionBy reverse];[self runAction: scaleto];
[self runAction: [Sequence actions:actionBy, actionByBack, nil]];return kEventHandled;
}but it doesn't - I get 3 warnings and 1 error:
-warnings being treated as error
-warnings: implicit conversion shorten 64-bit value into a 32-bit value
-warnings: implicit conversion shorten 64-bit value into a 32-bit value
Command/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc-4.2 failed with exit code 1Why can't I get it to work this way. I just need to see how I could scale the paddles when a touch begins and then maybe I could make another tiny step forward...
SOS #-(
Posted 3 years ago # -
You need some way of detecting if your touch is in your object. The demo has a containsTouchLocation method - that uses the rect method of TextureNode - if you are not using a TextureNode, then you need to roll your own Rect method.could someone also explain the differences in these 2 methods?
Posted 3 years ago # -
c'mon anyone - I feel like the village idiot :-)
Posted 3 years ago # -
ok thanks a lot :-)
Posted 3 years ago # -
anyone? SOS!
Posted 3 years ago # -
Also,
but it doesn't - I get 3 warnings and 1 error:
-warnings being treated as error
-warnings: implicit conversion shorten 64-bit value into a 32-bit value
-warnings: implicit conversion shorten 64-bit value into a 32-bit value
Command/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc-4.2 failed with exit code 1Check the project configuration and uncheck "treat warnings as errors" since the compiling error you are getting is because of that. Having any warning will yield an error.
Posted 3 years ago # -
@pabloruiz55 THANK YOU - the actions work but what about the warnings - is this a major no-no?
Posted 3 years ago # -
Could you check where it is throwing these warnings? "implicit conversion shorten 64-bit value into a 32-bit value"
Posted 3 years ago # -
here in the actions that I've added:
id scaleto = [ScaleTo actionWithDuration: 0.5 scale:0.5f];
id actionBy = [ScaleBy actionWithDuration: 0.5 scale: 2];Posted 3 years ago # -
id scaleto = [ScaleTo actionWithDuration: 0.5f scale:0.5f]; id actionBy = [ScaleBy actionWithDuration: 0.5f scale: 2.0f];Posted 3 years ago # -
That is strange, did it fix the warnings now?
Posted 3 years ago # -
Now it did, I must have missed something before ;-) Thank you.
Posted 3 years ago # -
how does one limit the touch so the action is completed before it can be restarted?
Posted 3 years ago # -
@Alex - you already have a model to follow in the code you posted. Look at how they check if the paddle has already been grabbed. You need to do something similar but check if your action is running. Actions have an isDone method to check if they are complete or you could use a Sequence with a CallFunc action at the end that calls a method that resets a flag that will allow the action to run again.
Posted 3 years ago # -
@Alex:
Sorry, I was 'sidelined' by my wife, for some reason she doesn't think iPhone programming is a top priority.
Do you still need a simple example? It looks like from your posts you have it working now.
Posted 3 years ago # -
yeah, i would actually. one that implements CGRect and touch location if possible?
Posted 3 years ago # -
how does one limit the touch so the action is completed before it can be restarted?
Posted 3 years ago # -
@Alex
Read Steve's response above. When the action triggered by the touch starts running you can set a flag (some people would use a variable of type BOOL):
running = YES;Then, you can change your action so that it finishes with a callback to a function that resets the flag:
running = NO;Then, in your code that triggers the action you would need something like:
if (!running) { //run actions here }Anyway, that is one way to do it.
Posted 3 years ago # -
thanks, what about a dummy example including touch location?
Posted 3 years ago # -
OK - rather than confuse things with my crummy code, let's take a look at the TouchesTest code distributed with Cocos2D.
Most of the interesting code is in the Paddle class. Let's look at the interface in 'Paddle.h':
@interface Paddle : TextureNode <TargetedTouchDelegate> {So, Paddle is a subclass of TextureNode. Notice the code in angle brackets? We are declaring that our Paddle class will adhere to the TargetedTouchDelegate protocol. This is like signing a contract, and promising to implement the methods that this protocol expects to exist. If we look at the definition of the TargetedTouchDelegate protocol in 'TouchDelegateProtocol', we see:
@protocol TargetedTouchDelegate <NSObject> /** Return YES to claim the touch. @since v0.8 */ - (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; @endReading this, we can see that we must implement the 'ccTouchesBegan' method. Also, we may implement 'ccTouchesMoved', 'ccTouchesEnded', and 'ccTouchesCanceled', but the protocol does not require it. In practice, you will almost always implement the optional methods.
Why are we adhering to the 'TargetedTouchDelegate' protocol? Because the touch dispatcher expects us to. When the user touches the screen, the touch dispatcher will call the appropriate method on our Paddle class. Obviously, the method that the touch dispatcher calls must exist, but we are promising that it exists when we declare that our class adheres to the 'TargetedTouchDelegate' protocol.
OK, so far so good. Back to the paddle class implementation, where we define the methods we promised to in our protocol declaration.
First, in the 'onEnter' method, we tell the touch dispatcher that Paddle is a delegate:
- (void)onEnter { [[TouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES]; [super onEnter]; }Then, we implement the required method:
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event { if (state != kPaddleStateUngrabbed) return NO; if ( ![self containsTouchLocation:touch] ) return NO; state = kPaddleStateGrabbed; return YES; }This code may be slightly tricky, but taken line-by-line it's not too bad. 'state' is a variable that keeps track of wheter the Paddle is already being touched. If so, we don't care if it is touched again, so we exit from the function, returning NO. Returing NO tells the touch dispatcher that some other object might care about the touch, but we don't, so pass it along.
We also check to see if the touch is actually on the paddle, and if it doesn't we again return NO, passing the touch along. How do we check if the touch is touching the paddle? Look at the following code:
- (BOOL)containsTouchLocation:(UITouch *)touch { return CGRectContainsPoint(self.rect, [self convertTouchToNodeSpaceAR:touch]); }We're checking to see if a rectangle contains a point. If it does, the statement evaluates to true, and the function returns YES. The rect method follows:
- (CGRect)rect { CGSize s = [self.texture contentSize]; return CGRectMake(-s.width / 2, -s.height / 2, s.width, s.height); }The tricky thing about this code is that we are defing a rectangle based on the size of the sprite, relative to its anchor point. The default anchor point (0,0) is actually the center of the sprite, so this code actually defines a rectangle relative to the sprite, as if it had its own coordinate system, with (0,0) at the sprite's center.
In 'Paddle.h' we made rect a property, so we can use the dot '.' accessor to get its value.
The final piece of the puzzle is 'convertTouchToNodeSpaceAR:toch'. AR stands for 'anchor relative', so the touch is converted to the coordinate system of the sprite, relative to the sprite's anchor point.
So, if the touch is within the sprites rect, we change the 'state' variable, and return YES, telling the touch dispatcher that the touch belongs to us, and the touch should not be passed along.
Wrapping things up, you can probably see that in 'ccTouchesMoved' we change the position of the paddle if the paddle is grabbed.
Posted 3 years ago # -
@cjl - wow thanks for the lengthy explanation- I'm still digesting. I have a few comments though:
'- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{if (state != kPaddleStateUngrabbed) return NO;
if ( ![self containsTouchLocation:touch] ) return NO;state = kPaddleStateGrabbed;
//return YES;id actionBy = [ScaleBy actionWithDuration: 1.0f scale: 2.0f];
id actionByBack = [actionBy reverse];[self runAction: [Sequence actions:actionBy, actionByBack, nil]];
return kEventHandled;
}'I can only get my action to work if 'return YES' is erased after 'state = kPaddleStateGrabbed; '
Anyone have a clue why?Also, to understand the CGRect method correctly in terms of a sprite with a non-movable location of x=200 and y=160 and width of 45 and height of 100 - how would we implement it - I am trying to produce a button and the paddles in the example are a little to advanced for a newbie like me ;)
@Steve Oldmeadow
I had a look at the sprites test which contains the CallFunc action.
I tried to add it to my sequence as the final action as:
'[CallFunc actionWithTarget:self selector:@selector(callback1)],'
And the sequence can not be started?
This seems like the easiest way to implement this method - but I can't seem to get it to work?Posted 3 years ago # -
@Alex:
When you issue a return statement, the remainder of the function is not evaluated. If you put 'return YES' where you have 'return kEventHandled', it will work.
The rect method above will work for your sprite, too, assuming your sprite 'goes all the way to the edges' in your png (doesn't have any padding around it, which it shouldn't). Read what I wrote above again. The rect method produces a rect relative to the node (sprite) coordinate system.
By the way, I'm not quite sure why you're making a button, because Cocos already provides Menu and MenuItem.
Posted 3 years ago # -
My game consists of sprites that have to be pushed... I call them buttons just for reference sake.
Posted 3 years ago # -
Thank you so much cjl for your informative explanation!
I learnt a lot in regards to the rect method, as it now makes sense what it is doing when you draw a rectangle relative to the zero point in the centre.
Posted 3 years ago #
Reply »
You must log in to post.