Problem with action - iphone

I have designed a game that the main character will jump in the screen for gaining points, but i need the player can only touch after the character landed, i had done following thing but still no work, what have i missed??
(BOOL)ccTouchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView: [touch view]];
point = [[Director sharedDirector] convertCoordinate: point];
id jump = [JumpTo actionWithDuration:0.5 position:ccp(point.x,point.y) height:100 jumps:1];
[plainSprite runAction:jump];
if (![jump isDone])
{
isTouchEnabled=NO;
}
return YES;
}

The problem is that JumpTo works "asynchronously" (well, not really, but it's going to give the appearance of an asynchronous call). Here's how it works:
Creating any IntervalAction (like JumpTo) just creates an object that keeps track of some property such as position, opacity, etc. The game loop then moves on, calling the action periodically to update its property.
So, in your case, the if (![jump isDone]) won't work, because it is called immediately after the action is created, not after it is done.
So, how to solve the problem -
First create a jumpIsDone method that re-enables your sprite. Then:
isTouchEnabled = NO;
[plainSprite runAction: [JumpTo actionWithDuration: 0.5 position:ccp(point.x, point.y) height:100 jumps:1]];
[plainSprite runAction: [Sequence actionOne: [DelayTime actionWithDuration: 0.5]
two: [CallFunc actionWithTarget: self selector: #selector(jumpIsDone)]]];

Related

cocos2d for iPhone - Touch no longer works correctly after scale

I am rather new to using Cocos2d for iPhone and I am having an issue with touch locations. At the moment I am simply trying to touch and move a sprite on the screen, this works fine when the layer is unmoved as well as when I translate the layer (changing self.position in X direction in my case) however, when I scale my layer (example: self.scale = .5) the touch no longer moves the sprite. I have done a lot of forum searching/google searching and I think my issue has to do with my coordinate transforms (node space/world space etc.) But I am not 100% sure. I did notice that when I scale, if I click the location where the sprite would be without the scale, then I could move the sprite. This leads me to believe that my transforms are not taking the scale into account.
Here is the coordinate transform code I am currently using to get touch locations:
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [self convertToNodeSpace:location];
location = [[CCDirector sharedDirector] convertToGL:location];
}
Here is the code that is checking if the location (same location variable as above) is touching a sprite, although I feel much more confident that this code is correct, who knows!
for (CCSprite *sprite in movableSprites) {
if (CGRectContainsPoint(sprite.boundingBox, touchLocation)) {
NSLog(#"Woohoo, you touched a sprite!");
break;
}
}
Let me know if you need anymore information and thanks for reading!
I think you should double the bounding box with the scale
for (CCSprite *sprite in movableSprites) {
if (CGRectContainsPoint(sprite.boundingBox*sprite.scale, touchLocation)) {
//touch sprite action
}
}
About converting the point, if I need an absolut screen point I always use:
convertToWorldSpace:CGPointZero.
I'm not really sure why you need this on your touch location, I would usually do this on sprites when I need to disregard their position in a parent node.
Other then that, If your game is not real multi-touch game you better use ccTouchBegan and not ccTouchesBegan.
Use this function to get sprite rect.
-(CGRect)getSpriteRect:(CCNode *)inSprite
{
CGRect sprRect = CGRectMake(
inSprite.position.x - inSprite.contentSize.width*inSprite.anchorPoint.x,
inSprite.position.y - inSprite.contentSize.height*inSprite.anchorPoint.y,
inSprite.contentSize.width,
inSprite.contentSize.height
);
return sprRect;
}
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
for (CCSprite *sprite in movableSprites)
{
CGRect rect = [self getSpriteRect:sprite];
if (CGRectContainsPoint(rect, location))
{
NSLog(#"Woohoo, you touched a sprite!");
break;
}
}
}

Why does my sprite go to the wrong co-ordinates after the first move?

Here is my movement method:
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
location = [touch locationInView: [touch view]];
CGPoint location_ = [[CCDirector sharedDirector] convertToGL:location];
NSLog(#"Click Position = (%f,%f)",location_.x,location_.y);
float moveSpeed = 40.0;
float moveDist = sqrt(pow(abs(location_.x - sprite.position.x),2) + pow(abs(location_.y - sprite.position.y),2));
float moveTime = (moveDist / moveSpeed);
[sprite runAction:[CCMoveTo actionWithDuration:moveTime position:location_]];
}
And here's my init method.
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init])) {
self.isTouchEnabled = YES;
// create and initialize a Label
[self scheduleUpdate]; // available since v0.99.3
[self schedule: #selector(update:) interval:0.5];
CGSize size = [[CCDirector sharedDirector] winSize];
bg = [CCSprite spriteWithFile:#"testBG.png"];
bg.position = ccp( size.width /2 , size.height/2 );
[self addChild: bg];
sprite = [CCSprite spriteWithFile:#"testSprite.png"];
sprite.position = ccp( size.width /2 , size.height/2 );
[self addChild: sprite];
[self runAction:[CCFollow actionWithTarget:sprite]];
}
return self;
}
My window follows the sprite around, but like I said, the sprite will go to a different point than touched after the first touch. Can anyone tell me what's going on?
edit: I'm thinking that it may have to do with the co-ordinate system itself, or maybe it's to do with
[touches anyObject];? My searches have turned up little.
edit2: I've found that if I return my sprite back to the middle of the bg sprite again, it'll behave normally again from there, until it's too far off.
I believe the problem is with [self runAction:[CCFollow actionWithTarget:sprite]];.
selfis your Scene that you don't want to move around.
The pattern for doing this would be to add a CCNodethat you would call a your _contentNodeto your sceneand add everything you would like to move as a child.
Then you would call [_contentNode runAction:[CCFollow actionWithTarget:sprite]];
IN this I'll suggest you a simple thing... Before adding a new action, stop the previous action on the sprite...
In your ccTouchesBegan method
[sprite stopAllActions];
[sprite runAction:[CCMoveTo actionWithDuration:moveTime position:location_]];
I think this will help as you sprite will stop once you touch..
In current case its undergoing an action.. Suppose its duration is 2 sec. and on next touch you run action of 1 sec. Then it will go to wrong point as previous action is still not completed.
Hope this helps.. :)

UIScrollView and Cocos2D

I have created a UIScrollView in a cocos2d application. I am adding sprites dynamically, over 3 pages. On the first page, touch works perfectly on a sprite, however if I use the scroll view and navigate to the second page, touch does not work quite right... the sprite will respond to the touch when I touch the screen, approximately the amount I have scrolled to the left. If I scroll back to the first page, touch works perfectly for a sprite. Any ideas? I am using the following tutorial: http://getsetgames.com/2009/08/21/cocos2d-and-uiscrollview/ :)
I think some code might be useful:-
I am using the exact code from your demo...
CocosOverlayScrollView and CocosOverlayViewController
I am creating the CocosOverlayViewController in my layer:-
CocosOverlayViewController *scrollView = [CocosOverlayViewController alloc];
[[[Director sharedDirector] openGLView] addSubview:scrollView.view];
I am creating the layer in my scene:-
Scene *scene = [Scene node];
GridLayer *layer = [GridLayer node];
[scene addChild: layer z:-1];
[scene setTag:12];
I am creating the sprites in my layer:-
myImage.position = ccp(53 * (coordinate.x + 0.52), 57 * (coordinate.y + 1.45));
[myImage runAction:[FadeIn actionWithDuration:0.3]];
myImage.relativeAnchorPoint = YES;
[self addChild:myImage z:-1];
The sprite is using the TouchesDispatcher and the touches are resolved in the class.
If I use the cocos2d moveto function on the layer I can touch a sprite and it responds so I know it works, things just get a little odd when I use the UIScrollView.
I hope you understand my problem and can help, all the best :)
Carl
I finally got to implementing scrolling of a CCLayer by using a UIScrollView derived class, following the tutorials mentioned in this question:
http://getsetgames.com/2009/08/21/cocos2d-and-uiscrollview/
http://www.cocos2d-iphone.org/forum/topic/9417
Both of them are an excellent read, and highly recommended to get a deeper understanding about how UIScrollViews (and UIViews in general) can be made to handle touches in cooperation with Cocos2D.
However, upon implementing these solutions, I also experienced the bug described in the question: if you don't scroll, touches are propagated from the UIScrollView to the CCLayer correctly. If you scroll, the layer scrolls beautifully but non-scrolling touches on the UIScrollView propagate to the CCLayer with an offset that grows the more you scroll, which makes the CCLayer (and/or accompanying CCMenus) unusable.
I have found the cause of this problem to be a bug in how Cocos2D translates touches sent to the OpenGLView to the local CCNode or CCMenu coordinate systems. This bug is present in 1.0 rc, and only affects touches that are generated on a OpenGLView's subview (like our UIScrollView) and get propagated to the Cocos2D main touching area (namely the OpenGLView) by calling the following line inside the UIScrollView's -touchesBegan: method
[[[CCDirector sharedDirector] openGLView] touchesBegan:touches withEvent:event];
(Note that calling this previous line is enough for propagating nonscrolling and nonzooming touches from the UIScrollView to Cocos2D, you do not need to call nextResponder: as the aforementioned blog posts do.)
The solution comes with a small modification on two Cocos2D sources:
CCNode.m
- (CGPoint)convertTouchToNodeSpace:(UITouch *)touch {
// cocos2d 1.0 rc bug when using with additional overlayed views (such as UIScrollView).
// CGPoint point = [touch locationInView: [touch view]];
CGPoint point = [touch locationInView: [[CCDirector sharedDirector] openGLView]];
point = [[CCDirector sharedDirector] convertToGL: point];
return [self convertToNodeSpace:point];
}
- (CGPoint)convertTouchToNodeSpaceAR:(UITouch *)touch {
// cocos2d 1.0 rc bug when using with additional overlayed views (such as UIScrollView).
// CGPoint point = [touch locationInView: [touch view]];
CGPoint point = [touch locationInView: [[CCDirector sharedDirector] openGLView]];
point = [[CCDirector sharedDirector] convertToGL: point];
return [self convertToNodeSpaceAR:point];
}
CCMenu.m
-(CCMenuItem *) itemForTouch: (UITouch *) touch {
// cocos2d 1.0 rc bug when using with additional overlayed views (such as UIScrollView).
// CGPoint touchLocation = [touch locationInView: [touch view]];
CGPoint touchLocation = [touch locationInView: [[CCDirector sharedDirector] openGLView]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
...
The key here is UITouch's locationInView: method. The argument for this method should be the UIView that you want to translate the touches coordinates into. Most Cocos2D project only have one UIView: the OpenGLView, so touches get generated in the OpenGLView (= touch view) and get translated to the same view. However, if you add overlaying subviews to receive touches, such as a UIScrollView, 'touch view' will have this value, which no longer corresponds to the desired OpenGLView.

Detect touch *anywhere on the screen* in cocos2d?

I'm really sorry, I realize there have been several questions asked about cocos2d touch detection (including this answer which helped me a bunch), but I just can't get any of them to work. I would have commented on the answer I linked instead of asking my own question, but i don't have enough rep to leave comments.
All I want to do is stop animation as soon as a user taps anywhere on the screen.
Here's my code so far:
- (BOOL)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"Touches Began");
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView: [touch view]];
location = [[Director sharedDirector] convertCoordinate: location];
CGRect mySurface = (CGRectMake(100, 100, 320, 480));
if(CGRectContainsPoint(mySurface, location)) {
NSLog(#"Event Handled");
return kEventHandled;
[[Director sharedDirector] stopAnimation];
}
return kEventIgnored;
NSLog(#"Event Ignored");
}
I've tried both BOOL and void, ccTouchesBegan and touchesBegan, in a layer file and a cocosNode file, and many other things. Nothing happens. Nothing shows in the log, and the animation continues on its merry little way. What am I doing wrong?
The main problem is that you've got the [[Director sharedDirector] stopAnimation]; after the return kEventHandled; rather than before it. return exits the function as soon as it's called, so anything after it will never get reached.
I don't have my mac in front of me to check the rest of your code, but it seems fine, so I'm guessing that's the main problem. If you're not even seeing the NSLog(#"Touches Began"); then you need to make sure that you're doing this in a CocosNode that extends Layer.
Another useful thing(once you're seeing the touches) is the NSStringFromCGPoint function, which allows you to easily display and debug the values in a CGPoint, so you could do something like:
NSLog(#"This layer was touched at %#", NSStringFromCGPoint(location));

How can I detect touch in cocos2d?

I am developing a 2d game for iPhone by using cocos2d.
I use many small sprite (image) in my game. I want to touch two similar types of sprite(image) and then both sprite(image) will be hidden.
How can I detect touch in a specific sprite(image) ?
A better way to do this is to actually use the bounding box on the sprite itself (which is a CGRect). In this sample code, I put all my sprites in a NSMutableArray and I simple check if the sprite touch is in the bounding box. Make sure you turn on touch detection in the init. If you notice I also accept/reject touches on the layer by returning YES(if I use the touch) or NO(if I don't)
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint location = [self convertTouchToNodeSpace: touch];
for (CCSprite *station in _objectList)
{
if (CGRectContainsPoint(station.boundingBox, location))
{
DLog(#"Found sprite");
return YES;
}
}
return NO;
}
Following Jonas's instructions, and adding onto it a bit more ...
- (void)ccTouchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch* touch = [touches anyObject];
CGPoint location = [[[Director sharedDirector] convertCoordinate: touch.location];
CGRect particularSpriteRect = CGMakeRect(particularSprite.position.x, particularSprite.position.y, particularSprite.contentSize.width, particularSprite.contentSize.height);
if(CGRectContainsPoint(particularSpriteRect, location)) {
// particularSprite touched
return kEventHandled;
}
}
You may need to adjust the x/y a little to account for the 'centered positioning' in Cocos
In your layer that contains your sprite, you need to say:
self.isTouchEnabled = YES;
then you can use the same events that you would use in a UIView, but they're named a little differently:
- (void)ccTouchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch* touch = [touches anyObject];
//in your touchesEnded event, you would want to see if you touched
//down and then up inside the same place, and do your logic there.
}
#david, your code has some typos for cocos 0.7.3 and 2.2.1, specifically CGRectMake instead of CGMakeRect and [touch location] is now [touch locationInView:touch.view].
here's what I did:
- (BOOL)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch * touch = [touches anyObject];
CGPoint location = [[Director sharedDirector] convertCoordinate: [touch locationInView:touch.view]];
CGRect myRect = CGRectMake(sprite.position.x, sprite.position.y, sprite.contentSize.width, sprite.contentSize.height);
if(CGRectContainsPoint(myRect, location)) {
// particularSprite touched
return kEventHandled;
}
}
#Genericrich: CGRectContainsPoint works in CocosLand because of the call 2 lines above:
[[Director sharedDirector] convertCoordinate:]
The Cocos2D objects will be using the OpenGL coordinate system, where 0,0 is the lower left, and UIKit coordinates (like where the touch happened) have 0,0 is upper left. convertCoordinate: is making the flip from UIKit to OpenGL for you.
Here's how it worked for me...
Where spriteSize is obviously the sprite's size... :P
- (BOOL)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch * touch = [touches anyObject];
CGPoint location = [[Director sharedDirector] convertCoordinate: [touch locationInView:touch.view]];
CGRect myRect = CGRectMake(sprite.position.x-spriteSize/2, sprite.position.y-spriteSize/2, spriteSize, spriteSize);
if(CGRectContainsPoint(myRect, location)) {
// particularSprite touched
return kEventHandled;
}
}
this is a good tutorial explaining the basic touch system
http://ganbarugames.com/2010/12/detecting-touch-events-in-cocos2d-iphone/
first, write
self.isTouchEnabled = YES;
then, you need to implement the functions ccTouchesEnded, ccTouchesBegan, etc
from what I understood, you want to be able to 'match' two sprites that can be on different coordinates on the screen.
a method for doing this.. : (im sure theres many other methods)
consider having 2 global variables.
so everytime a touch touches a sprite, you use the CGRectContainsPoint function that is mentioned several times to find which sprite has been touched. then, you can save the 'tag' of that sprite in one of the global variables.
You do the same for the second touch, and then you compare the 2 global variables.
you should be able to figure out the rest but comment if you have problems.