In my app, I need to draw a path where every coupe of frames, an additional point is added to the end of it.
I could implement this in the following way:
- (void) draw
{
glEnable(GL_LINE_SMOOTH);
glColor4f(0.0,0.0,1.0,1.0);
BOOL first = YES;
CGPoint prevPoint;
for (NSValue* v in points)
{
CGPoint p = [v CGPointValue];
if (first == YES)
first = NO;
else
ccDrawLine(prevPoint, p);
prevPoint = p;
}
}
But I'm afraid this will not scale well as the path could (and almost always would) get pretty long.
Is there a better more "economical" way to implement this?
Look at the standard cocos2d RenderTextureTest sample code which includes a fingerpainting class. A simplified version of the main method that does the drawing is shown below. You could take this logic and use it to just render the path under your control rather than driven by the touch events.
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint start = [touch locationInView: [touch view]];
start = [[CCDirector sharedDirector] convertToGL: start];
CGPoint end = [touch previousLocationInView:[touch view]];
end = [[CCDirector sharedDirector] convertToGL:end];
// begin drawing to the render texture
[target begin];
// for extra points, we'll draw this smoothly from the last position and vary the sprite's
// scale/rotation/offset
float distance = ccpDistance(start, end);
if (distance > 1)
{
int d = (int)distance;
for (int i = 0; i < d; i++)
{
float difx = end.x - start.x;
float dify = end.y - start.y;
float delta = (float)i / distance;
[brush setPosition:ccp(start.x + (difx * delta), start.y + (dify * delta))];
[brush setRotation:rand()%360];
float r = ((float)(rand()%50)/50.f) + 0.25f;
[brush setScale:r];
//[brush setColor:ccc3(CCRANDOM_0_1()*127+128, 255, 255) ];
// Call visit to draw the brush, don't call draw..
[brush visit];
}
}
// finish drawing and return context back to the screen
[target end];
}
Related
I have a CCSprite that is attached to body in a b2world .
When someone is touch it, i want to move it with the touch location.
With a regular sprite that works fine , but with a sprite that has a body- it does not .
it gets the touch but not move the sprite (the body follow the sprite or the opposite?)
How should i do that ? apply a force relative to the touch is a problem..
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView: [touch view]];
//detect a touch ont the button
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
{
CGPoint location=[[CCDirector sharedDirector] convertToGL: currentPosition];
CCSprite *tempSprite = (CCSprite *) b->GetUserData();
if( tempSprite.tag==2 )
{
if(CGRectContainsPoint([tempSprite boundingBox], location))
{
tempSprite.position=location;
NSLog(#"touched");
}
}
}
}
Try changing the position of the body using SetTransform function. I think it's looking something like:
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView: [touch view]];
//detect a touch ont the button
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
{
CGPoint location=[[CCDirector sharedDirector] convertToGL: currentPosition];
CCSprite *tempSprite = (CCSprite *) b->GetUserData();
if( tempSprite.tag==2 )
{
if(CGRectContainsPoint([tempSprite boundingBox], location))
{
b->SetTransform( b2Vec2( location.x/PTM_RATIO, location.y/PTM_RATIO ), 0 ); //change position of the body
NSLog(#"touched");
}
}
}
}
Don't forget, if you want to change body position apply force or set linear velocity you must use kinematic or dynamic body type.
I'm trying to simulate a flick in cocos2d and I need to create a ball every time the users touch is ended, but I can't get the ball to move during the tick method, and I can't destroy the ball (which is a b2body) afterwards without unscheduling the method every time.
- (void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
touch = [touches anyObject];
location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
endPoint = location;
force = b2Vec2(endPoint.x - startPoint.x ,endPoint.y - startPoint.y);
if ((force.x != 0) || (force.y != 0)) {
if (ballCount == 0) {
ball.position = startPoint;
[self createBall]; - Here i create the ball every time
[self schedule: #selector(tick:)]; -I schedule the tick method right after the ball is created
[self scheduleOnce:#selector(kick) delay:0]; - This is the only place the ball will launch. For some reason I can't get the kick method to work any where else
}
}
- (void)kick
{
int speed = 30;
float32 setSpeed = speed/sqrt(powf(force.x,2) + powf(force.y, 2));
b2Vec2 ballSpeed = b2Vec2(force.x * setSpeed, force.y * setSpeed);
_ballBody->SetLinearVelocity(ballSpeed);
}
- (void)tick:(ccTime) dt {
_world->Step(dt, 10, 10);
ballData = (__bridge CCSprite *)_ballBody->GetUserData();
ballData.position = ccp(_ballBody->GetPosition().x * PTM_RATIO,
_ballBody->GetPosition().y * PTM_RATIO);
ballData.rotation = -1 * CC_RADIANS_TO_DEGREES(_ballBody->GetAngle());
std::set<b2Body *>toDestroy;
//takes collisions from contact listener
std::vector<MyContact>::iterator pos;
for(pos = _contactListener->_contacts.begin();
pos != _contactListener->_contacts.end(); ++pos) {
MyContact contact = *pos;
bodyA = contact.fixtureA->GetBody();
bodyB = contact.fixtureB->GetBody();
if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL) {
spriteA = (__bridge CCSprite *) bodyA->GetUserData();
spriteB = (__bridge CCSprite *) bodyB->GetUserData();
contactPositionX = spriteA.position.x;
contactPositionY = spriteB.position.y;
if (spriteA.tag == kCurrentItem && spriteB.tag == 8)
{
NSLog(#"contact");
[self removeChild:spriteA cleanup:YES];
[self removeChild:spriteB cleanup:YES];
toDestroy.insert(bodyA);
toDestroy.insert(bodyB);
[self unschedule:#selector(tick:)]; (i unschedule the tick method every time which in turn messes up my other sprites.)
}
}
}
for(std::set<b2Body *>::iterator pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2)
{
b2Body *body = *pos2;
_world->DestroyBody(body);
}
toDestroy.clear();
}
I need to create an outline like this dynamically:
Not for a CCSprite, but for multiple animated CCSprites united in one CCNode. I'm thinking about:
copying CCNode's content to a texture (like canvasBitmapData.draw(sourceDisplayObject) in AS3)
creating CCSprite with the resulting texture
tinting the sprite to outline color and scaling it up a bit
placing the sprite behind other sprites in the node
I have no idea how to perform step 1. And maybe it is faster to draw "true stroke" around the texture's opaque pixels instead of tint-scale in step 3?
I totally forgot to post an answer for this question. Here's the code for a very smooth stroke. It's not fast but worked great for a couple of big sprites on the first iPad.
The idea is to draw tiny colored and blurred balls around the sprite and place them onto their own texture. It can be used both for CCNode and CCSprite. The code also shifts anchor points because the resulting sprites will have a bit larger width and height.
Resulting outline (body and 2 hands, about 0.3s on iPad1):
White balls examples:
5f: http://i.stack.imgur.com/e9kos.png
10f: http://i.stack.imgur.com/S5goU.png
20f: http://i.stack.imgur.com/qk7GL.png
CCNode category, for Cocos2d-iPhone 2.1:
#implementation CCNode (Outline)
- (CCSprite*) outline
{
return [self outlineRect:CGRectMake(0, 0, self.contentSize.width, self.contentSize.height)];
}
- (CCSprite*) outlineRect:(CGRect)rect
{
NSInteger gap = dscale(4);
CGPoint positionShift = ccp(gap - rect.origin.x, gap - rect.origin.y);
CGSize canvasSize = CGSizeMake(rect.size.width + gap * 2, rect.size.height + gap * 2);
CCRenderTexture* renderedSpriteTexture = [self renderTextureFrom:self shiftedFor:positionShift onCanvasSized:canvasSize];
CGSize textureSize = renderedSpriteTexture.sprite.contentSize;
CGSize textureSizeInPixels = renderedSpriteTexture.sprite.texture.contentSizeInPixels;
NSInteger bitsPerComponent = 8;
NSInteger bytesPerPixel = (bitsPerComponent * 4) / 8;
NSInteger bytesPerRow = bytesPerPixel * textureSizeInPixels.width;
NSInteger myDataLength = bytesPerRow * textureSizeInPixels.height;
NSMutableData* buffer = [[NSMutableData alloc] initWithCapacity:myDataLength];
Byte* bytes = (Byte*)[buffer mutableBytes];
[renderedSpriteTexture begin];
glReadPixels(0, 0, textureSizeInPixels.width, textureSizeInPixels.height, GL_RGBA, GL_UNSIGNED_BYTE, bytes);
[renderedSpriteTexture end];
//SEE ATTACHMENT TO GET THE FILES
NSString* spriteFrameName;
if (IS_IPAD) spriteFrameName = (CC_CONTENT_SCALE_FACTOR() == 1) ? #"10f.png" : #"20f.png";
else spriteFrameName = (CC_CONTENT_SCALE_FACTOR() == 1) ? #"5f.png" : #"10f.png";
CCSprite* circle = [CCSprite spriteWithSpriteFrameName:spriteFrameName];
circle.anchorPoint = ccp(0.48, 0.48);
float retinaScale = (CC_CONTENT_SCALE_FACTOR() == 1) ? 1.0 : 0.5;
CCRenderTexture* strokeTexture = [CCRenderTexture renderTextureWithWidth:textureSize.width height:textureSize.height pixelFormat:kCCTexture2DPixelFormat_RGBA8888];
[strokeTexture beginWithClear:0 g:0 b:0 a:0];
for (NSInteger x = 0; x < textureSizeInPixels.width; x++)
{
for (NSInteger y = 0; y < textureSizeInPixels.height; y++)
{
NSInteger idx = y * bytesPerRow + x * bytesPerPixel + 3;
NSInteger w = 1;
if (bytes[idx] <= 254)
{
BOOL shouldBeStroked = NO;
for (NSInteger nx = -w; nx <= w; nx++)
{
for (NSInteger ny = -w; ny <= w; ny++)
{
if (x + nx < 0 || y + ny < 0 || x + nx >= textureSizeInPixels.width || y + ny >= textureSizeInPixels.height)
continue;
if (bytes[idx + nx * bytesPerPixel + ny * bytesPerRow] == 255)
{
shouldBeStroked = YES;
break;
}
}
}
if (shouldBeStroked == YES)
{
circle.position = ccp(x * retinaScale, y * retinaScale);
[circle visit];
}
}
}
}
[strokeTexture end];
CCSprite* resultSprite = [CCSprite spriteWithTexture:strokeTexture.sprite.texture];
[resultSprite.texture setAntiAliasTexParameters];
resultSprite.flipY = YES;
if ([self isKindOfClass:[CCSprite class]]) {
CGPoint oldAnchorInPixels = ccp(roundf(self.contentSize.width * self.anchorPoint.x), roundf(self.contentSize.height * self.anchorPoint.y));
resultSprite.anchorPoint = ccp((oldAnchorInPixels.x + gap) / resultSprite.contentSize.width, (oldAnchorInPixels.y + gap) / resultSprite.contentSize.height);
resultSprite.position = self.position;
} else { //CCNode
resultSprite.anchorPoint = CGPointZero;
resultSprite.position = ccpAdd(self.position, ccp(rect.origin.x - gap, rect.origin.y - gap));
}
return resultSprite;
}
- (CCRenderTexture*) renderTextureFrom:(CCNode*)node shiftedFor:(CGPoint)posShift onCanvasSized:(CGSize)size
{
SoftAssertion(!CGSizeEqualToSize(size, CGSizeZero), #"node has zero size");
BOOL isSprite = [node isMemberOfClass:[CCSprite class]];
CGPoint apSave = node.anchorPoint;
CGPoint posSave = node.position;
BOOL wasVisible = node.visible;
CCRenderTexture* rtx = [CCRenderTexture renderTextureWithWidth:size.width
height:size.height
pixelFormat:kCCTexture2DPixelFormat_RGBA8888];
[rtx beginWithClear:0 g:0 b:0 a:0];
node.anchorPoint = CGPointZero;
node.position = posShift;
node.visible = YES;
if (isSprite) [node visit];
else [[self cloneCCNode:node] visit];
node.anchorPoint = apSave;
node.position = posSave;
node.visible = wasVisible;
[rtx end];
return rtx;
}
- (CCNode*) cloneCCNode:(CCNode*)source
{
CCNode* clone = [CCNode node];
void (^copyCCNodeProperties)(CCNode*, CCNode*) = ^(CCNode* source, CCNode* clone)
{
clone.visible = source.visible;
clone.rotation = source.rotation;
clone.position = source.position;
clone.anchorPoint = source.anchorPoint;
clone.zOrder = source.zOrder;
clone.tag = source.tag;
};
for (CCNode* srcSubnode in source.children) {
CCNode* subNode;
if ([srcSubnode isMemberOfClass:[CCSprite class]]) {
CCSprite* srcSprite = (CCSprite*)srcSubnode;
subNode = [CCSprite spriteWithTexture:srcSprite.texture];
CCSprite* subSprite = (CCSprite*)subNode;
subSprite.flipX = srcSprite.flipX;
subSprite.flipY = srcSprite.flipY;
subSprite.displayFrame = srcSprite.displayFrame;
subSprite.opacity = srcSprite.opacity;
}
else if ([srcSubnode isMemberOfClass:[CCLabelTTF class]]) {
CCLabelTTF* srcLabel = (CCLabelTTF*)srcSubnode;
subNode = [CCLabelTTF labelWithString:srcLabel.string fontName:srcLabel.fontName fontSize:srcLabel.fontSize dimensions:srcLabel.dimensions hAlignment:srcLabel.horizontalAlignment vAlignment:srcLabel.verticalAlignment];
CCSprite* subLabel = (CCSprite*)subNode;
subLabel.flipX = srcLabel.flipX;
subLabel.flipY = srcLabel.flipY;
subLabel.color = srcLabel.color;
}
else {
subNode = [self cloneCCNode:srcSubnode];
}
copyCCNodeProperties(srcSubnode, subNode);
[clone addChild:subNode];
}
copyCCNodeProperties(source, clone);
return clone;
}
I have a general purpose function I built up from various sources (that I'm ashamed to say I can't reference here). What it does is take a CCSprite, create a stroke that you can put behind it and return in a CCRenderTexture. If the sprite passed in has children (as yours might) I see no reason why it wouldn't do what you want, but I haven't tried.
Here it is in case it works:
#implementation Cocosutil
+(CCRenderTexture*) createStrokeForSprite:(CCSprite*)sprite size:(float)size color:(ccColor3B)cor
{
CCRenderTexture* rt = [CCRenderTexture renderTextureWithWidth:sprite.texture.contentSize.width+size*2 height:sprite.texture.contentSize.height+size*2];
CGPoint originalPos = [sprite position];
ccColor3B originalColor = [sprite color];
BOOL originalVisibility = [sprite visible];
[sprite setColor:cor];
[sprite setVisible:YES];
ccBlendFunc originalBlend = [sprite blendFunc];
[sprite setBlendFunc:(ccBlendFunc) { GL_SRC_ALPHA, GL_ONE }];
CGPoint bottomLeft = ccp(sprite.texture.contentSize.width * sprite.anchorPoint.x + size, sprite.texture.contentSize.height * sprite.anchorPoint.y + size);
CGPoint positionOffset = ccp(sprite.texture.contentSize.width * sprite.anchorPoint.x - sprite.texture.contentSize.width/2,sprite.texture.contentSize.height * sprite.anchorPoint.y - sprite.texture.contentSize.height/2);
CGPoint position = ccpSub(originalPos, positionOffset);
[rt begin];
for (int i=0; i<360; i+=30)
{
[sprite setPosition:ccp(bottomLeft.x + sin(CC_DEGREES_TO_RADIANS(i))*size, bottomLeft.y + cos(CC_DEGREES_TO_RADIANS(i))*size)];
[sprite visit];
}
[rt end];
[sprite setPosition:originalPos];
[sprite setColor:originalColor];
[sprite setBlendFunc:originalBlend];
[sprite setVisible:originalVisibility];
[rt setPosition:position];
return rt;
}
#end
and here is code where I use it:
- (id) initWithSprite:(CCSprite*)sprite color:(ccColor3B)color strokeSize:(float)strokeSize strokeColor:(ccColor3B)strokeColor {
self = [super init];
if (self != nil) {
strokeColor_ = strokeColor;
strokeSize_ = strokeSize;
CCRenderTexture *stroke = [CocosUtil createStrokeForSprite:sprite size:strokeSize color:strokeColor];
[self addChild:stroke z:kZStroke tag:kStroke];
[self addChild:sprite z:kZLabel tag:kLabel];
[self setContentSize:[sprite contentSize]];
}
return self;
}
I like to draw a line, but cocos2d inside ccDrawLine serrate, how to draw a blurring of the line, who can help me?
ccDrawLine( ccp(StartP.x, StartP.y), ccp(EndP.x, EndP.y) );
I did not use ccDrawLine but I created a line with a Sprite and I animated it (see code below). In this way I was able to use custom line images made (but nevermind. that's how I did).
If you want to stick to primitives I guess you should set the opacity of the line primitive (see this post which explains how) and then you could create a sequence of action that set the opacity level (e.g. start with opacity at 100%, then 75%, then back to 100% like I did with my images but using the method in the link above) to get the blurring effect..
Code using images:
CCSprite * string = [self getChildByTag:tag];
[string setOpacity:100];
NSMutableArray* frames = [[NSMutableArray alloc]initWithCapacity:3];
NSString*lineFrame = [NSString stringWithString:#"line0.png"];
CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache]spriteFrameByName:lineFrame];
[frames addObject:frame];
lineFrame = [NSString stringWithString:#"line1.png"];
frame = [[CCSpriteFrameCache sharedSpriteFrameCache]spriteFrameByName:lineFrame];
[frames addObject:frame];
lineFrame = [NSString stringWithString:#"line0.png"];
frame = [[CCSpriteFrameCache sharedSpriteFrameCache]spriteFrameByName:lineFrame];
[frames addObject:frame];
CCAnimation* anim = [CCAnimation animationWithFrames:frames delay:0.1f];
CCAnimate* animate = [CCAnimate actionWithAnimation:anim];
//CCRepeatForever* repeat = [CCRepeatForever actionWithAction:animate];
[string runAction:animate];
[string setOpacity:75];
Hope that this helps..
#import "cocos2d.h"
#interface CClineSprite : CCLayer
{
CCRenderTexture * renderTarget;
NSMutableArray * pathArray;
CCSprite * pathBrush;
CGPoint prePosition;
}
-(void)setLinePosition:(CGPoint)position;
-(void)setLineOpacity:(GLubyte) anOpacity;
-(void)setLineScale:(float) scale;
-(void)setLineColor:(ccColor3B) color;
#end
#import "CClineSprite.h"
#implementation CClineSprite
- (id) init
{
self = [super init];
if (self)
{
CGSize s = [[CCDirector sharedDirector] winSize];
renderTarget = [CCRenderTexture renderTextureWithWidth:s.width height:s.height];
[renderTarget setPosition:ccp(s.width/2, s.height/2)];
[self addChild:renderTarget z:1];
pathBrush = [CCSprite spriteWithFile:#"dots.png"];
pathBrush.color = ccWHITE;
[pathBrush setOpacity:100];
[pathBrush setScale:0.5];
pathArray = [[NSMutableArray alloc]init];
}
return self;
}
-(void)setLineOpacity:(GLubyte) anOpacity
{
[pathBrush setOpacity:anOpacity];
}
-(void)setLineScale:(float) scale
{
[pathBrush setScale:scale];
}
-(void)setLineColor:(ccColor3B) color
{
[pathBrush setColor:color];
}
-(void)setLinePosition:(CGPoint)position
{
[pathArray addObject:[NSValue valueWithCGPoint:position]];
[self renderPath];
}
- (void) renderPath
{
[renderTarget clear:0 g:0 b:0 a:0];
[renderTarget begin];
for (int i = 0; i < pathArray.count-1;i++)
{
CGPoint pt1;
CGPoint pt2;
[[pathArray objectAtIndex:i] getValue: &pt1];
[[pathArray objectAtIndex:i + 1] getValue: &pt2];
float distance = ccpDistance(pt1, pt2);
if (distance > 1)
{
int d = (int)distance;
for (int i = 0; i < d; i += 10)
{
float difx = pt2.x - pt1.x;
float dify = pt2.y - pt1.y;
float delta = (float)i / distance;
[pathBrush setPosition:ccp(pt1.x + (difx * delta), pt1.y + (dify * delta))];
[pathBrush visit];
}
}
}
[renderTarget end];
}
#end
USAGE:
CClineSprite* streak = [CClineSprite node];
[self addChild:streak z:999];
[streak setLinePosition:associatedTurtleObject.position];
[streak setLineScale:0.4];
To dynamically update or extend the line just use
[streak setLinePosition:ccp(x,y)];
Hope this will give you more flexibility for use
I am almost done with my game but I can't get my multi touch working :
I got in my appdelegate
[glView setMultipleTouchEnabled:YES];
(also tried [window setMultiTouchEnabled:YES];)
In my Bomb.h
#interface Bomb : CCLayer (I also tried CCNode with <ccTargetTouchDelegate>)
Bomb.m
-(void)onEnter
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:kCCMenuTouchPriority swallowsTouches:YES];
[super onEnter];
}
-(void)onExit
{
[[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
[super onExit];
}
(Also tried registerWithTouchDispatcher withouth onEnter and onExit and also tried with [super registerWithTouchDispatcher])
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
if(isPaused || !canBeDragged || LOST)
return NO;
//take the coordinates of the touch and transform them into the OpenGL system.
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
CGRect frame = CGRectMake(self.position.x, self.position.y, self.contentSize.width, self.contentSize.height);
if(!CGRectContainsPoint(frame, location))
return NO;
location.x *= factor;
location.y *= factor;
if(BombShape)
{
offsetX = BombShape->body->p.x – location.x;
offsetY = BombShape->body->p.y – location.y;
BombShape->body->v = cpvzero;
BombShape->collision_type++; //make it ‘Dragged’. For example RedNinja++ is DraggedRedNinja
}
return YES;
}
//****************************************************************************************
- (void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
if(isPaused || !canBeDragged)
return;
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
CGPoint prevLocation = [touch previousLocationInView: [touch view]];
prevLocation = [[CCDirector sharedDirector] convertToGL: prevLocation];
location.x *= factor;
location.y *= factor;
prevLocation.x *= factor;
prevLocation.y *= factor;
if(BombBody)
{
//during the dragging, the bomb must not have velocity. Otherwise, it will “run” beneath your finger.
//so we are constantly calculating the velocity and ,when you end the draging, assign that value to the velocity of the bomb.
velocity = cpv((location.x – prevLocation.x) * 30 , (location.y – prevLocation.y)*30);
CGPoint newPosition = cpv(location.x + offsetX, location.y + offsetY);
//test per X
canMoveOnX = CheckOnX(BombBody->p , newPosition,radius);
canMoveOnY = CheckOnY(BombBody->p , newPosition,radius);
if(canMoveOnX)
BombBody->p.x = newPosition.x;
if(canMoveOnY)
BombBody->p.y = newPosition.y;
}
}
//****************************************************************************************
- (void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
if(!canBeDragged || isPaused)
return;
//set velocity back
BombShape->body->v = velocity;
BombShape->collision_type–;
offsetX = 0;
offsetY = 0;
}
//****************************************************************************************
-(void) ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event
{
}
Somehow I can't seem to detect my second touch :S.
I am loading my Bomb.h in a GameScene that is a CCLayer without touches.
Please help. Thanks.
I had the same problem.
If you have another view, like a view for ad, you should do the same thing to that.
ex.
[yourAnotherView setMultipleTouchEnabled:YES];
If you don't, sorry I cannot answer any more...