cocos2d dragging a sprite by touch without gaps - cocos2d-iphone

I am trying to drag a sprite by touch on it. If the touch is outside the sprite, it should NOT move.
When user touch on the sprite and drag it, a path is drawn behind. This path should not be broken (like gaps between paths). There should be one consistent path at all the times.
I am using mysprite.position to set new position of sprite same as current touch location.
But there are gaps if user touches a point slightly out of path.
I also tried using CCMoveTo action but that delays the path drawing and if user is drawing very fast then it looks bad that sprite is following behind.
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[mySprite runAction:[CCMoveTo actionWithDuration:0.0f position:touchLocation]];
-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
if(CGRectContainsPoint([mySprite boundingBox], currentTouchPoint)){
CGPoint translation = ccpSub(currentTouchPoint, lastTouchPoint);
CGPoint newPos = ccpAdd(mySprite.position, translation);
mySprite.position = newPos;
[touchPoints addObject:NSStringFromCGPoint(currentTouchPoint)];
[touchPoints addObject:NSStringFromCGPoint(lastTouchPoint)];
}
}
Any suggestions how to achieve it?

Related

Setting z-index of layer when using setNotificationNode in Cocos2D

Since I'm having performance issues with using a UIView parallaxing images in the background of a transparent Cocos2D scene (it was fine in iOS 6), I think I may use the notification node to run the parallax since I need the parallax running between scene transitions. I've tested setting the notifications node, but I haven't figured out how to make it display in a different z-order. I want it to display under everything in the scene.
Right now for my test I have
CCLayer *layer = [CCLayer node];
CCLabelTTF *labelTest = [CCLabelBMFont labelWithString:#"test" fntFile:#"readySetGo.fnt"];
labelTest.position = CGPointMake(100,100);
[layer addChild:labelTest];
[[CCDirector sharedDirector] setNotificationNode:layer]; // Layer should be placed here
[layer onEnter]; // Schedule for updates

Adding cclayer to scene -touches goes down

Always the same problem .
I have a scene and i am adding it a CClayer from another class , which is some background with ccmenu on him .
When touching it, touches goes under this layer, and i dont want it .
otherClass *layer=[otherClass alloc]init]; //otherClass returns a cclayer .
[self addChild: layer];
layer is good, and is above my scene , but the touches goes down.
is there a way in cocos2d to enable ONLY touches at the top layer ??
I must change the touches priority now ?
You need to change touch priority and set to swallowsTouches.
To do this, register your layer on touchDispatcher setting these parameters (you can also see CCLayer registerWithTouchDispatcher method as example):
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];

trying to detect touch ended and touch moved for CCSprite

I have a CCSprite subclass, and initially I had set it up with a
So I had the following code:
-(void)onEnter {
[super onEnter];
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
-(void)onExit {
[super onExit];
[[[CCDirector sharedDirector] touchDispatcher] removeDelegate:self];
}
-(BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
if ([self containsTouch:touch]) {
// do stuff
return YES;
}
return NO;
}
But then I realized that I actually didn't want to use touchBegan, because I want to detect if a sprite has been dragged downward-- So I wanted to use touchMoved and touchEnded instead of touchBegan.
However, when I implement those methods, they are not called...
How can I tell when the sprite's touch ended, and if it was "swiped"?
Enabling multiple touches: In the applicationDidFinishLaunching:application method in your appdelegate, set multiple touches to YES: [glView setMultipleTouchEnabled:YES];
Then in your CCLayer subclass (the class you are working in for detecting touches), in the init method, add self.isTouchEnabled = YES;
Now your multi touch methods should get called.
Swiping: cocos2d does not support gestures out of the box. You will likely have to work yourself. You can start with the apple event handling guide about gestures. The How To Drag and Drop Sprites with Cocos2D totorial at raywenderlich.com hepled me.
In order for the dispatcher to call your methods (moved, ended, cancelled), you have to first claim the touch ie. you will process the events. That is done in ccTouchBegan, when you return YES. After that you will receive the other events.
CCTouchableSprite - my touchable sublcass of CCSprite with Objective-C blocks, you can use touchMoved to detect what you want.

CCPanZoomController + Touchable/Clickable sprites

I am using CCPanZoomController to make my 'map' (one image) zoomable and pan-able.
On this map I would like to have clickable/touchable sprites, which when clicked change the image in the sprite.
The problem is that when the user pinches the screen (to zoom out/in), they may touch the sprite, which changes the image of the sprite, which is something I don't want.
I had an idea to solve this, but as I'm new to Cocos2d I don't know how to implement it:
I thought that I could detect when the user touches the screen/the sprite, and doesn't move their touch (as if to pinch or pan) through detecting when the user first touches the screen, (transform that initial touch into a coordinate), and then when the user stops touching the screen (turn that into a coordinate), and compare the both, and if their is no change (or very little change) then change the image of a sprite?
How would I go about doing this? Big thanks to anyone who can help!!
So I've been working with CCPanZoomController myself in my game and ran into similar issues as you but with many different aspects such as when they touch a sprite, I didn't want to have the background move with it or I'd want the sprite to not move when the background was zooming. So what I did was to make methods to "turn off" touches for the layer that I didn't want to react and re-enable them once the action in the other layer was done.
I created the following method inside each layer to disable it or enable it for touch which I call from the different touch events.
// Public Method: Allows for disabling touch for this layer and re-enabling it
-(void)enableTouches:(BOOL)enable
{
// Check if the bool value is to enable or disable touches
if (enable) {
// Call for the removal of all touch locations in array in the CCLayerPanZoom instance
[_panZoomLayer removeTouchesFromArray];
// Call the touch dispatcher and add the CCLayerPanZoom back as a delegate for touches
[[CCTouchDispatcher sharedDispatcher] addStandardDelegate:_panZoomLayer priority:0];
CCLOG(#"PanZoomWrapperLayer:enableTouches - LayerPanZoom touches enabled");
} else {
// Call the touch dispatcher to remove the CCLayerPanZoom as a delegate to disable touches
[[CCTouchDispatcher sharedDispatcher] removeDelegate:_panZoomLayer];
CCLOG(#"PanZoomWrapperLayer:enableTouches - LayerPanZoom touches disabled");
}
}
I've found a simple solution to this problem. However it may not suit your needs!
I've subclassed the CCMenu class and overridden the -(void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event as follows:
-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
[_selectedItem unselected];
_selectedItem = nil;
}
I've set the touchSwallow property of the instance of that new menu to NO.

centering a sprite in the middle of the screen convertToWorldSpace / NodeSpace

i have passed many many days on this problem, i've not very clear in mind what convertToWorldSpace, convertToNodeSpace does...
i have 2 layer (CCNode) one that i can scale, one for panning the screen, so i scale always what is displayed makeing the center of scaling the middle of the screen:
scaleLayer=[CCNode node];
scaleLayer.position= ccp( size.width /2 , size.height/2 );
[self addChild:scaleLayer z:-2000];
panLayer=[CCNode node];
panLayer.position= ccp( -size.width /2 , -size.height/2 );
[scaleLayer addChild:panLayer z:-2000];
now i add sprites to panlayer:
[panLayer addChild:mysprite z:2];
i'd like to have a button that, when pressed, moves panlayer to make the sprite in the middle of the screen.
i have wrote this but works only if scaleLayer.scale=1
CGPoint p;
p=[panLayer convertToWorldSpace:mysprite.position];
p.x=(panLayer.position.x+(240-p.x));
p.y=(panLayer.position.y+(160-p.y));
[panLayer runAction:[CCMoveTo actionWithDuration:0.5 position:p]];
how can i make the sprite to be at center of the screen with different scales?
thanks
I'm not sure what your existing code does but you might find the property mysprite.boundingBox useful. It will give you a CGRect with the sprite's width and height and the position of its bottom left corner, and it will reflect whatever scale you have applied to the sprite.