Cocos2d + box2D remove sprite from world - ios

Should be easy but i don't have find...
I have a lot of sprites in my world and on a moment X, i need to destroy multiples sprites.
With the code below, i can remove this sprite by tag number:
CCSprite *sprite = (CCSprite *)[self getChildByTag:TagFromMyArray];
[self removeChild:sprite cleanup:YES];
The problem is the body that remain on screen...and crash the game on the next tick.
With the code below i can find "a body":
for(b2Body *b = world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *sprite = (CCSprite *)b->GetUserData();
if (sprite.tag = [[[myGrille.grille objectAtIndex:point.x] objectAtIndex:point.y]blockTag]) {
[self removeChild:sprite cleanup:YES];
world->DestroyBody(b);
}
}
}
The problem is that it remove every body on the world.
Isn't b a reference to a unique body ?

I was around this for hours and it was a small error...
Just have to replace "=" with "==" in the last if condition.

Related

Coco2d v3 How to remove sprite from parent node like candy crush game?

When I select the sprite type I want to remove the sprites from the node, Its only doing scale and its not removing from the node. Please help me.
Thanks in advance.
for (ImageView *cookie in chain.cookies) {
// 1
if (cookie.sprites != nil) {
// 2
CCActionScaleTo *Scaleaction =[CCActionScaleTo actionWithDuration:0.3 scale:0.1];
CCActionCallBlock *action2=[CCActionCallBlock actionWithBlock:^{
[self removeFromParentAndCleanup:YES];
}];
// CCAction *scaleAction = [SKAction scaleTo:0.1 duration:0.3];
//scaleAction.timingMode = SKActionTimingEaseOut;
[cookie.sprites runAction:[CCActionSequence actionWithArray:#[Scaleaction,action2]]];
// 3
cookie.sprites = nil;
}
}
}

SpriteKit - Detect if node hits another nodes children and perform action

I have a Cat node, and a Bird node. The bird nodes are nested together in a container node called a birdBlock. Everything is contained in a WorldNode. If I add a bird to the WorldNode, the Cat can interact with it appropriately, but when the birds are in the birdBlock, the Cat just shoves them out of the way and they go flying.
I am using the following to find my birds:
[worldNode enumerateChildNodesWithName:kBirdName usingBlock:^(SKNode *node, BOOL *stop)
{
SKSpriteNode *newBird = (SKSpriteNode *)node;
if (CGRectIntersectsRect(newBird.frame,cat.frame))
{
//Do Something
//This is never reached when the birds are in the SKSpriteNode birdBlock.
//They just get shoved all over the screen.
}
}];
The birds in the block have the correct name.
They are now being enumerated, but still do not interact with the cat other than flying around the screen.
Now I am doing this:
[[worldNode children] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
SKSpriteNode *blockNode = (SKSpriteNode *)obj;
if ([blockNode.name isEqualToString:kBirdBlockName])
{
[blockNode enumerateChildNodesWithName:kBirdName usingBlock:^(SKNode *node, BOOL *stop)
{
SKSpriteNode *nbird = (SKSpriteNode *)node;
NSLog(#"FOUND BIRDS HERE");
//THIS IS FOUND! But below still does not work
if (CGRectIntersectsRect(nbird.frame, cat.frame))
{
NSLog(#"Hit BIRD");
[nbird removeFromParent];
}
}
}
}];
So this does not work either. How do you change the coordinate system of a sprite?
You can search the node tree in many ways. The SKNode documentation explains it clearly under the section Searching the Node Tree.
If you have a node named #"node" then you can search through all descendants by putting a // before the name. So you would search for #"//node".
Try changing your constant kBirdName to equal #"//my_bird_name"
An example using a string literal would be -
[worldNode enumerateChildNodesWithName:#"//nodeName" usingBlock:^(SKNode *node, BOOL *stop)
{ // Do stuff here... }
I could not get this to work, so I just gave all the birds a physicsBody, and moved the detection to didBeginContact
Now it does not matter what their parent is and I don't need to worry about changing coordinates.
- (void)didBeginContact:(SKPhysicsContact *)contact
{
SKSpriteNode *firstNode = (SKSpriteNode *)contact.bodyA.node;
SKSpriteNode *secondNode = (SKSpriteNode *) contact.bodyB.node;
if ((firstNode.physicsBody.categoryBitMask == catCategory && secondNode.physicsBody.categoryBitMask == birdCategory) || (firstNode.physicsBody.categoryBitMask == birdCategory && secondNode.physicsBody.categoryBitMask == catCategory))
{
NSLog(#"DID HIT BIRD");
if (firstNode.physicsBody.categoryBitMask == catCategory) {
//do something to secondNode.
}
if (firstNode.physicsBody.categoryBitMask == birdCategory) {
//do something to firstNode.
}
}
}

CCNode remove not working Cocos2d

For some reason my remove function on my CCNode is not working after the animation is run.
I am adding a CCNode on click, running a animation then running the remove function.
// loads the Coin
CCNode* coin = [CCBReader load:#"heros/coin"];
coin.name =#"coin";
// position
coin.position = ccpAdd(_touchNode.position, ccp(0, 0));
//Add to Parent
[_touchNode addChild:coin z:-1];
id action1 = [CCActionMoveTo actionWithDuration:0.7f position:ccpAdd(_touchNode.position, ccp(0, 200))];
id action2 = [CCActionMoveTo actionWithDuration:0.7f position:ccpAdd(_touchNode.position, ccp(0, 100))];
CCActionCallFunc *callAfterMoving = [CCActionCallFunc actionWithTarget:self selector:#selector(cleanupSprite:)];
[coin runAction: [CCActionSequence actions:action1, action2, callAfterMoving, nil]];
using the following delete function produces a crash error with This node does not contain the specified child
- (void) cleanupSprite:(CCNode*)inSprite
{
// call your destroy particles here
// remove the sprite
[self removeChild:inSprite cleanup:YES];
}
Using the following delete also doesn't work
- (void) cleanupSprite:(CCNode*)inSprite
{
// call your destroy particles here
// remove the sprite
[self removeChildByName:#"coin" cleanup:YES];
}
self does not contain coin, _touchNode does. Do this in your callback :
[_touchNode removeChildByName:#"coin" cleanup:YES];

CCJumpBy on a sprite

These are my first Cocos2D projects, I'm trying to make a sprite jump in the same place when touched, but I can't make it response because I don't know how to set touch actions on sprites.
Here is the code :
-(void) spriteEffect
{
CCSprite *actionEffect = avatar;
id jump = [CCJumpBy actionWithDuration:1 position: ccp(0, 0) height:50 jumps:2];
id sequence = [CCSequence actions: jump, nil];
[actionEffect runAction:sequence];
return yes
}
Should I use a
- (BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
Thanks!
Your comment that avatar is an array of sprites helps clarifying why you don't see any effects. Try to do something like:
-(void) spriteEffect
{
CCSprite *actionEffect = <get a sprite from avatar array>;
id jump = [CCJumpBy actionWithDuration:1 position: ccp(0, 0) height:50 jumps:2];
[actionEffect runAction:jump];
}
I don't know what kind of array avatar is, so I can't provide syntax for accessing its elements. If avatar is an NSArray, you can make all of your sprites jump by using:
-(void) spriteEffect
{
foreach (CCSprite* actionEffect in avatar) {
id jump = [CCJumpBy actionWithDuration:1 position: ccp(0, 0) height:50 jumps:2];
[actionEffect runAction:jump];
}
}

Box2D b2ContactListener (Collision Detection)

In my game, I have about 6 different variations of objects. Each object has a b2Body, b2BodyDef, and b2FixtureDef attached to it.
In my case, my b2Bodys are following my CCSprites since Cocos2D is easier with animations.
Anyway I am trying to follow Ray Wenderlich's tutorial: http://www.raywenderlich.com/606/how-to-use-box2d-for-just-collision-detection-with-cocos2d-iphone
The thing is I am quite confused on what he is actually doing!
Questions:
1. Does my Contact Listener code in my CCScene need to be in my game loop?
2. This is his main code for his collision detection in his CCScene:
3. Also I see that in the below code he uses tags for his CCSprites, does that mean my CCSprites do not have to be ivars? Also what about my b2Bodys, b2BodyDefs, and b2FixtureDefs, do they have to be ivars? Does he just do it by tags?
std::vector<b2Body *>toDestroy;
std::vector<MyContact>::iterator pos;
for(pos = _contactListener->_contacts.begin();
pos != _contactListener->_contacts.end(); ++pos) {
MyContact contact = *pos;
b2Body *bodyA = contact.fixtureA->GetBody();
b2Body *bodyB = contact.fixtureB->GetBody();
if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL) {
CCSprite *spriteA = (CCSprite *) bodyA->GetUserData();
CCSprite *spriteB = (CCSprite *) bodyB->GetUserData();
if (spriteA.tag == 1 && spriteB.tag == 2) {
toDestroy.push_back(bodyA);
} else if (spriteA.tag == 2 && spriteB.tag == 1) {
toDestroy.push_back(bodyB);
}
}
}
std::vector<b2Body *>::iterator pos2;
for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) {
b2Body *body = *pos2;
if (body->GetUserData() != NULL) {
CCSprite *sprite = (CCSprite *) body->GetUserData();
[_spriteSheet removeChild:sprite cleanup:YES];
}
_world->DestroyBody(body);
}
if (toDestroy.size() > 0) {
[[SimpleAudioEngine sharedEngine] playEffect:#"hahaha.caf"];
}
The thing is, like before he only has 2 things that CAN collide. In my case I have 6. So would I have to modify that code in any way to work with my 6 possible b2Bodys?
Thanks!

Resources