cocos2d CCSprite not getting coordinates - objective-c

SOLVED!
to get coordinates of the sprites frame use sprite.boundingBox.origin.x;
Hello!I am implementing a simple code but I cannot understand its behavior:
anewSprite = [CCSprite spriteWithFile:#"grossini.png"];
anewSprite.position = ccp(80, 80);
[self addChild:anewSprite];
anotherSprite = [CCSprite spriteWithFile:#"grossini.png"];
anotherSprite.position = ccp(300, 80);
[self addChild:anotherSprite];
-(BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
CGPoint point= [touch locationInView:[touch view]];
point = [[CCDirector sharedDirector] convertToGL: point];
NSLog(#"point x:%f y:%f", point.x, point.y);
if (CGRectContainsPoint(anewSprite.textureRect, point)){
NSLog(#"contains point");
} else {
NSLog(#"does not contain");
}
return TRUE;
}
-(void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event{
CGPoint point= [touch locationInView:[touch view]];
point = [[CCDirector sharedDirector] convertToGL: point];
anewSprite.position = point;
if (CGRectContainsRect(anewSprite.textureRect, anotherSprite.textureRect) == TRUE) {
NSLog(#"Intersects");
}
}
The problem is following:
NSLog(#"anotherSpriteTextureRectOrigin X:%f Y:%f", enemy1.textureRect.origin.x, enemy1.textureRect.origin.y);
NSLog(#"anewSpriteTextureRectOrigin X:%f Y:%f", anewSprite.textureRect.origin.x, anewSprite.textureRect.origin.y);
shows:
anotherSpriteTextureRectOrigin X:0.000000 Y:0.000000
anewSpriteTextureRectOrigin X:0.000000 Y:0.000000
Thanks in advance!

To check, whether one sprite intersects/contains another, instead of sprite.frame.rect use sprite.boundingBox
Eg:
if (CGRectContainsRect(sprite1.boundingBox, sprite2.boundingBox)) {
NSLog(#"Contains");
}

Related

CCSprite in NSDictionary doesn't react to the BoundingBox

I have an NSDictionary (allSprites) with a lot of Sprites (spriteX) and in my Touch Method I want to check whether the sprite was touched.
My problem is that it doesn't react to the boundingBox. I don't see my error! Is it a problem with NSDictionary? I get no error or anything... But it doesn't work.
Is there another way to check the boundingBox in an NSDictionary? Can somebody help me?
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in [event allTouches]) {
for (NSValue* value in allSprites) {
CGPoint location = [touch locationInView:touch.view];
location = [[CCDirector sharedDirector] convertToGL:location];
if(CGRectContainsPoint([spriteX boundingBox], location)){
NSLog(#"sprite was touched");
}
}
}
}
you dont seem to refer to spriteX at all in your loop other than in the test for bounding box, it is probably not initialized. maybe you meant to do :
for (CCSprite* spriteX in [allSprites allValues]) {
CGPoint location = [touch locationInView:touch.view];
location = [[CCDirector sharedDirector] convertToGL:location];
if(CGRectContainsPoint([spriteX boundingBox], location)){
NSLog(#"sprite was touched");
}
}
if you need the key of the sprite :
for (NSString*key in [allSprites allKeys]) {
spriteX = [allSprites objectForKey:key];
CGPoint location = [touch locationInView:touch.view];
location = [[CCDirector sharedDirector] convertToGL:location];
if(CGRectContainsPoint([spriteX boundingBox], location)){
NSLog(#"sprite with key %# was touched",key);
}
}

Adding and touching multiple sprites in cocos2d

I have a class where I add multiple sprites as shown in the code below:
CCSprite *b = [CCSprite spriteWithFile:#"b"];
b.position = ccp(100, 160);
CCSprite *b2 = [CCSprite spriteWithFile:#"b2.png"];
b2.position = ccp(115, 150);
CCSprite *b3 = [CCSprite spriteWithFile:#"b3.png"];
b.position = ccp(200, 150);
CCSprite *b4 = [CCSprite spriteWithFile:#"b4.png"];
b4.position = ccp(220, 145);
b.anchorPoint = ccp(0.98, 0.05);
b2.anchorPoint = ccp(0.03, 0.05);
b3.anchorPoint = ccp(0.03, 0.05);
b4.anchorPoint = ccp(0.95, 0.05);
[self addChild:b z:1 tag:1];
[self addChild:b2 z:1 tag:2];
[self addChild:b3 z:1 tag:3];
[self addChild:b4 z:1 tag:4];
Here's the code for the touch event:
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouch = [event allTouches];
UITouch *touch = [[allTouch allObjects]objectAtIndex:0];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector]convertToGL:location];
//Swipe Detection - Beginning point
beginTouch = location;
for(int i = 0; i < [hairArray count]; i++)
{
CCSprite *sprite = (CCSprite *)[hairArray objectAtIndex:i];
if(CGRectContainsPoint([sprite boundingBox], location))
{
//selectedSprite is a sprite declared on the header file
selectedSprite = sprite;
}
}}
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
//Move touched sprite
NSSet *allTouch = [event allTouches];
UITouch *touch = [[allTouch allObjects]objectAtIndex:0];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector]convertToGL:location];
if(selectedSprite != nil)
{
selectedSprite.position = ccp(location.x, location.y);
}}
-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//End point of sprite after dragged
NSSet *allTouch = [event allTouches];
UITouch *touch = [[allTouch allObjects]objectAtIndex:0];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector]convertToGL:location];
endTouch = location;
posX = endTouch.x;
//Minimum swipe length
posY = ccpDistance(beginTouch, endTouch);
[self moveSprite];}
Now, the actions itself work just fine but the trouble I'm having is that if I want to drag b2, I have to drag b3 and b4 first. I'm not sure if it has anything to do with the z-index or it is because of the transparent areas that is present for each sprite. Is there something I'm missing here?
if(CGRectContainsPoint([sprite boundingBox], location))
{
//selectedSprite is a sprite declared on the header file
selectedSprite = sprite;
}
This code updates the currently selected sprite as soon as a new one is found while looping on all sprites. This means that if 3 sprites overlap you will get that the selected one is the last one in the array of nodes of the parent.
You can't make any assumptions on the orders so this is not clearly what you want, you have to decide a policy to give sprites priority. Mind that editing the anchorPoint may alter the position of the sprite compared to the bounding box (so that the bounding box is even outside the sprite).
To be sure of it you should enable:
#define CC_SPRITE_DEBUG_DRAW 1
in ccConfig.h. This will render bounding boxes around sprites.

CCPanZoomController + Tappable Sprites

I am creating a zoomable and pan-able map for my game (using CCPanZoomController) . Within this map I would like to have a tappable sprite, and when it is tapped, "do something"…
I can get the two things to work perfectly in separate projects, however when I try to combine them, nothing happens when I tap my sprite.
I have included an image to demonstrate further:
//in my init section
self.isTouchEnabled = YES;
mapBase = [CCSprite spriteWithFile:#"MapBase.png"];
mapBase.anchorPoint = ccp(0, 0);
[self addChild:mapBase z:-10];
gym = [CCSprite spriteWithFile:#"Gym.png"];
gym.scale = 0.3;
gym.position = ccp(1620, 250);
[self addChild:gym z:1];
CGRect boundingRect = CGRectMake(0, 0, 2499, 1753);
_controller = [[CCPanZoomController controllerWithNode:self] retain];
_controller.boundingRect = boundingRect;
_controller.zoomOutLimit = _controller.optimalZoomOutLimit;
_controller.zoomInLimit = 2.0f;
[_controller enableWithTouchPriority:1 swallowsTouches:YES];
//end of init
-(void) registerWithTouchDispatcher
{
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self
priority:0 swallowsTouches:NO];
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
CGPoint touchPoint1 = [touch locationInView:[touch view]];
if (CGRectContainsPoint(gym.boundingBox, touchPoint1)) return YES;
return NO;
}
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event{
CGPoint touchPoint2 = [touch locationInView:[touch view]];
if (CGRectContainsPoint(gym.boundingBox, touchPoint2)){
CCLOG(#"SPRITE HAS BEEN TAPPED");
}
}
I want to beable to zoom in/out and pan the wholemap (including the ‘Gym’ sprite).
And if the sprite 'Gym' is tapped by the user, then i would like to “do something”.
If anyone can figure this out, I would be extremely grateful!
Thanks.

How to get a sprite rect in a convenient way?

In cocos2d game development, CGRectContainsPoint method often used to detect if touch on a CCSprite.
I use code fllow to get a sprite's (which in a CCNode) rect property
- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
CCLOG(#"ccTouchEnded");
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
CCLOG(#"location.x:%f, y:%f", location.x, location.y);
CGRect rect;
rect = CGRectMake(self.firstCard.face.position.x-(self.firstCard.face.contentSize.width/2), self.firstCard.face.position.y-(self.firstCard.face.contentSize.height/2),
self.firstCard.face.contentSize.width, self.firstCard.face.contentSize.height);
if (CGRectContainsPoint(rect, location)) {
CCLOG(#"first card touched");
[firstCard open];
}
rect = CGRectMake(self.secondCard.face.position.x-(self.secondCard.face.contentSize.width/2), self.secondCard.face.position.y-(self.secondCard.face.contentSize.height/2),
self.secondCard.face.contentSize.width, self.secondCard.face.contentSize.height);
if (CGRectContainsPoint(rect, location)) {
CCLOG(#"second card touched");
[secondCard open];
}
}
I want to know if there is a convenient way to get a CCSprite 's rect straightforward?
Please use boundingBox i think it will be a great option to use.
Like this:
- ( void ) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
locationTouchBegan = [touch locationInView: [touch view]];
//location is The Point Where The User Touched
locationTouchBegan = [[CCDirector sharedDirector] convertToGL:locationTouchBegan];
//Detect the Touch On sprite
if(CGRectContainsPoint([sprite boundingBox], locationTouchBegan))
{
isSpriteTouched=YES;
}
}
Kobold2D has a convenience method containsPoint as a CCNode extension (Objective-C category) which you can replicate in your project:
-(BOOL) containsPoint:(CGPoint)point
{
CGRect bbox = CGRectMake(0, 0, contentSize_.width, contentSize_.height);
CGPoint locationInNodeSpace = [self convertToNodeSpace:point];
return CGRectContainsPoint(bbox, locationInNodeSpace);
}
Your code then be simplified to this and it will work with rotated and/or scaled sprites as well (the boundingBox method fails to test rotated and scaled sprites correctly).
if ([firstCard.face containsPoint:location]) {
CCLOG(#"first card touched");
}

How to drag only one image with iPhone SDK

I want to create a little app that takes two images and i want to make only the image over draggable.
After research, i found this solution:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[ event allTouches] anyObject];
image.alpha = 0.7;
if([touch view] == image){
CGPoint location = [touch locationInView:self.view];
image.center = location;
}
It works but the problem is that the image is draggable from its center and I don't want that.
So I found another solution:
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
// Retrieve the touch point
CGPoint pt = [[touches anyObject] locationInView:self.view];
startLocation = pt;
[[self view] bringSubviewToFront:self.view];
}
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
// Move relative to the original touch point
CGPoint pt = [[touches anyObject] locationInView:self.view];
frame = [self.view frame];
frame.origin.x += pt.x - startLocation.x;
frame.origin.y += pt.y - startLocation.y;
[self.view setFrame:frame];
}
It works very well but when I add another image, all the images of the view are draggable at the same time. I'm a beginner with the iPhone development and I have no idea of how I can only make the image over draggable.
You can use if condition in the touchesBegan: method, See this-
-(void)ViewDidLoad
{
//Your First Image View
UIImageView *imageView1 = [UIImageView alloc]initWithFrame:CGRectMake(150.0, 100.0, 30.0, 30.0)];
[imageView1 setImage:[UIImage imageNamed:#"anyImage.png"]];
[imageView1 setUserInteractionEnabled:YES];
[self.view addSubview:imageView1];
//Your Second Image View
UIImageView *imageView2 = [UIImageView alloc]initWithFrame:CGRectMake(150.0, 200.0, 30.0, 30.0)];
[imageView2 setImage:[UIImage imageNamed:#"anyImage.png"]];
[imageView2 setUserInteractionEnabled:YES];
[self.view addSubview:imageView2];
}
//Now Use Touch begin methods with condition like this
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches]anyObject];
if([touch view] == imageView1)
{
CGPoint pt = [[touches anyObject] locationInView:imageView1];
startLocation = pt;
}
if([touch view] == imageView2)
{
CGPoint pt = [[touches anyObject] locationInView:imageView2];
startLocation = pt;
}
}
//Use same thing with touch move methods...
- (void) touchesMoved:(NSSet *)touches withEvent: (UIEvent *)event
{
UITouch *touch = [[event allTouches]anyObject];
if([touch view] == imageView1)
{
CGPoint pt = [[touches anyObject] previousLocationInView:imageView1];
CGFloat dx = pt.x - startLocation.x;
CGFloat dy = pt.y - startLocation.y;
CGPoint newCenter = CGPointMake(imageView1.center.x + dx, imageView1.center.y + dy);
imageView1.center = newCenter;
}
if([touch view] == imageView2)
{
CGPoint pt = [[touches anyObject] previousLocationInView:imageView2];
CGFloat dx = pt.x - startLocation.x;
CGFloat dy = pt.y - startLocation.y;
CGPoint newCenter = CGPointMake(imageView2.center.x + dx, imageView2.center.y + dy);
imageView2.center = newCenter;
}
}
These two images will move only when you touch on it and move it. I hope my tutorials will help you.
Simply use these two methods
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
myImage.center = location;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesBegan:touches withEvent:event];
}
Let's break it down. You should have a main containerView (object of UIView) in your view controller. Within that, you should have DragableImageView objects.
DragableImageView inherits UIImageView and within that, you add your touches code. (Right now you are doing self.frame = position which is wrong - and obviously it will move all images at once - because if I understand correctly, you are adding these touches in your view controller).
Create only DragableImageView first, test it. Then add two DragableImageView instances. test them in different configurations.. you might want to hit test in the containerView to see which DragableImageView should be dragged (e.g. if you have jigsaw pieces, you might want to pick the one that is at the back rather than the front one).