Search code examples
objective-ccocos2d-iphoneshapesccspritecgpath

Define sprite shapes for touch


I'm trying to add shapes to my sprites, wich are in NSArray, using this code:

theSprites = [[NSMutableArray alloc] init];

CCSprite *sprite1 = [CCSprite spriteWithSpriteFrameName:@"sprite1"];
sprite1.position = ccp(winSize.width/2, sprite1.contentSize.height/2);
[self addChild:sprite1 z:3];
sprite1Path=CGPathCreateMutable();
CGPathMoveToPoint(sprite1Path, NULL, 0, 286);
CGPathAddLineToPoint(sprite1Path, NULL, 0, 0);
CGPathAddLineToPoint(sprite1Path, NULL, 768, 0);
CGPathAddLineToPoint(sprite1Path, NULL, 768, 208);
CGPathAddLineToPoint(sprite1Path, NULL, 356, 258);
CGPathCloseSubpath(sprite1Path);
[theSprites addObject:sprite1];

CCSprite *sprite2 = [CCSprite spriteWithSpriteFrameName:@"sprite2"];
sprite2.position = ccp(winSize.width/2, sprite2.contentSize.height/2);
[self addChild:sprite2 z:4];
sprite2Path=CGPathCreateMutable();
CGPathMoveToPoint(sprite2Path, NULL, 0, 254);
CGPathAddLineToPoint(sprite2Path, NULL, 0, 0);
CGPathAddLineToPoint(sprite2Path, NULL, 768, 0);
CGPathAddLineToPoint(sprite2Path, NULL, 768, 144);
CGPathAddLineToPoint(sprite2Path, NULL, 494, 168);
CGPathAddLineToPoint(sprite2Path, NULL, 204, 212);
CGPathCloseSubpath(sprite2Path);
[theSprites addObject:sprite2];

Then i'm trying to specify that only theSprites are moovable. I created a function like in one of cocos2d tutorials.

- (void)selectSprite:(CGPoint)touchLocation {
CCSprite *touchSprite = nil;
for (CCSprite *sprite in theSprites) {
  if (CGRectContainsPoint(sprite.boundingBox, touchLocation)) {            
    touchSprite = sprite;
    }  }  }

And now i'm stack! And i don't understand how to change CGRectContainsPoint to CGPathContainsPoint... I don't know how to specify both shapes whith one statement... or create if () if () constraction...


Solution

  • I see two problems. First, you need to attach the path to the sprite. You should subclass CCSprite and give it a boundingPath property:

    MySprite.h

    @interface MySprite : CCSprite
    
    @property (nonatomic) CGPath shapePath;
    
    @end
    

    MySprite.m

    @implementation MySprite
    
    @synthesize shapePath = _shapePath;
    
    - (void)setShapePath:(CGPath)path {
        CGPathRetain(path);
        CGPathRelease(_shapePath);
        _shapePath = path;
    }
    
    - (void)dealloc {
        CGPathRelease(_shapePath);
        [super dealloc]; // if you're using ARC, omit this line
    }
    

    You then set the shapePath property when you create the sprite:

    MySprite *sprite1 = [MySprite spriteWithSpriteFrameName:@"sprite1"];
    // ... blah blah blah all the stuff you did to init sprite1 and sprite1Path
    CGPathCloseSubpath(sprite1Path);
    sprite1.shapePath = sprite1Path;
    [theSprites addObject:sprite1];
    

    Now you can test for the touch in the sprite like this:

    - (MySprite *)spriteAtPoint:(CGPoint)point {
        for (MySprite *sprite in theSprites) {
            CGPoint spriteOrigin = sprite.boundingBox.origin;
            CGPoint pointInSprite = CGPointMake(point.x - spriteOrigin.x, point.y - spriteOrigin.y);
            if (CGPathContainsPoint(sprite.shapePath, NULL, pointInSprite, false))
                return sprite;
            }
        }
    }