I have to remove one when contact with enemy target.I tried this,but this removes all cats.I have remove only contact cat.
-(void)didBeginContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (enemyCategory | catsCategory)) {
[self enumerateChildNodesWithName:#"cats" usingBlock:^(SKNode *node, BOOL *stop) {
[node removeFromParent];
}];
NSLog(#"test 1");
}
The code:
[self enumerateChildNodesWithName:#"cats" usingBlock:^(SKNode *node, BOOL *stop) {
[node removeFromParent];
}];
Will remove all nodes whose name property is #"cats". Hence it is removing all the cats on screen.
You need to check whether the contact cat is the same as the one being enumerated, and then remove it.
[self enumerateChildNodesWithName:#"cats" usingBlock:^(SKNode *node, BOOL *stop) {
if ([contact.bodyA.node isEqual:node] || [contact.bodyB.node isEqual:node])
{
[node removeFromParent];
stop = YES;
}
}];
You can read more about the enumerateChildNodesWithName:usingBlock: method here.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm using a tutorial to create a game where if the rocketship is hit by an asteroid, the ship will show an image using SKEmitterNode and will blink then play a sound. This part of the game is working, however the game will not end. How do I fix this error?
Here's my code where I believe the error is
- (void)didBeginContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (asteroidCategory | shipCategory)) {
SKNode *asteroid, *spaceship;
if (contact.bodyA.categoryBitMask == shipCategory) {
spaceship = contact.bodyA.node;
asteroid = contact.bodyB.node;
[self runAction:[SKAction playSoundFileNamed:#"explosion_large.caf" waitForCompletion:NO]];
SKAction *blink = [SKAction sequence:#[[SKAction fadeOutWithDuration:0.1],
[SKAction fadeInWithDuration:0.1]]];
SKAction *blinkForTime = [SKAction repeatAction:blink count:6];
[self.spaceship runAction:blinkForTime];
NSString *explosionPath = [[NSBundle mainBundle] pathForResource:#"RocketFlame" ofType:#"sks"];
SKEmitterNode *explosion = [NSKeyedUnarchiver unarchiveObjectWithFile:explosionPath];
CGVector emitterVector = CGVectorMake(spaceship.frame.size.width * 2.0, 0);
explosion.particlePositionRange = emitterVector;
[self.spaceship addChild:explosion];
}
else {
spaceship = contact.bodyB.node;
asteroid = contact.bodyA.node;
[self runAction:[SKAction playSoundFileNamed:#"explosion_large.caf" waitForCompletion:NO]];
SKAction *blink = [SKAction sequence:#[[SKAction fadeOutWithDuration:0.1],
[SKAction fadeInWithDuration:0.1]]];
// SKAction *blinkForTime = [SKAction repeatAction:blink count:6];
[self.spaceship runAction:blink];
NSString *explosionPath = [[NSBundle mainBundle] pathForResource:#"RocketFlame" ofType:#"sks"];
SKEmitterNode *explosion = [NSKeyedUnarchiver unarchiveObjectWithFile:explosionPath];
CGVector emitterVector = CGVectorMake(spaceship.frame.size.width * 2.0, 0);
explosion.particlePositionRange = emitterVector;
[self.spaceship addChild:explosion];
}
[self asteroid:(SKSpriteNode *) asteroid didCollideWithasteroid:(SKSpriteNode *) spaceship];
}
else if (collision == (projectileCategory| asteroidCategory)) {
SKNode *Projectile, *asteroid;
if (contact.bodyA.categoryBitMask == asteroidCategory) {
Projectile= contact.bodyA.node;
asteroid = contact.bodyB.node;
}
else {
Projectile = contact.bodyB.node;
asteroid = contact.bodyA.node;
}
[self projectile:(SKSpriteNode *) Projectile didCollideWithasteroid:(SKSpriteNode *) asteroid];
self.asteroidsDestroyed++;
if (self.asteroidsDestroyed > 30) {
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:NO];
[self.view presentScene:gameOverScene transition: reveal];
}
}
}
The game is not ending because you are not calling the end-game transition in case of the collsion between the spaceship and asteroid as you do in the case where the collision is between the projectile and the asteroid.
- (void)didBeginContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (asteroidCategory | shipCategory)) {
SKNode *asteroid, *spaceship;
if (contact.bodyA.categoryBitMask == shipCategory) {
spaceship = contact.bodyA.node;
asteroid = contact.bodyB.node;
}
else {
spaceship = contact.bodyB.node;
asteroid = contact.bodyA.node;
}
[self runAction:[SKAction playSoundFileNamed:#"explosion_large.caf" waitForCompletion:NO]];
SKAction *blink = [SKAction sequence:#[[SKAction fadeOutWithDuration:0.1],
[SKAction fadeInWithDuration:0.1]]];
SKAction *blinkForTime = [SKAction repeatAction:blink count:6];
[self.spaceship runAction:blinkForTime];
NSString *explosionPath = [[NSBundle mainBundle] pathForResource:#"RocketFlame" ofType:#"sks"];
SKEmitterNode *explosion = [NSKeyedUnarchiver unarchiveObjectWithFile:explosionPath];
CGVector emitterVector = CGVectorMake(spaceship.frame.size.width * 2.0, 0);
explosion.particlePositionRange = emitterVector;
[self.spaceship addChild:explosion];
[self asteroid:(SKSpriteNode *) asteroid didCollideWithasteroid:(SKSpriteNode *) spaceship]; //What does this do?
[self runAction:[SKAction sequence:#[[SKAction waitForDuration:3.0], [SKAction runBlock:^{
[self gameEndedWithSuccess:NO];
}]]]];
}
else if (collision == (projectileCategory| asteroidCategory)) {
SKNode *Projectile, *asteroid;
if (contact.bodyA.categoryBitMask == asteroidCategory) {
Projectile= contact.bodyA.node;
asteroid = contact.bodyB.node;
}
else {
Projectile = contact.bodyB.node;
asteroid = contact.bodyA.node;
}
[self projectile:(SKSpriteNode *) Projectile didCollideWithasteroid:(SKSpriteNode *) asteroid];
self.asteroidsDestroyed++;
if (self.asteroidsDestroyed > 30) {
[self gameEndedWithSuccess:YES];
}
}
}
-(void) gameEndedWithSuccess:(BOOL)success
{
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:success];
[self.view presentScene:gameOverScene transition: reveal];
}
I tried so much methods but i didn't stop the cats when begin contacts.Here is node moving method:
[self enumerateChildNodesWithName:#"cat" usingBlock:^(SKNode *node, BOOL *stop){
SKSpriteNode *tempCat = (SKSpriteNode *) node;
float actionDuration = 0.1;
CGPoint offset = CGPointSubtract(_zombie.position, tempCat.position);
CGPoint direction = CGPointNormalize(offset);
CGPoint amountToMovePerSec = CGPointMultiplyScalar(direction, CAT_MOVE_POINTS_PER_SEC);
CGPoint amountToMove = CGPointMultiplyScalar(amountToMovePerSec, actionDuration);
node.position = CGPointMake(node.position.x+amountToMove.x, node.position.y+amountToMove.y);
_velocityCat = CGPointMultiplyScalar(direction, CAT_MOVE_POINTS_PER_SEC);
[self rotateNode:tempCat toFace:_velocityCat rotateRadiansPerSec:CAT_ROTATE_RADIANS_PER_SEC];
How can I stop cat when begin contact?
-(void)didBeginContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (enemyCategory | catsCategory)) {
[self enumerateChildNodesWithName:#"cat" usingBlock:^(SKNode *node, BOOL *stop) {
if ([contact.bodyA.node isEqual:node] || [contact.bodyB.node isEqual:node])
{
node.physicsBody = NO;
SKAction *wait = [SKAction waitForDuration:2];
SKAction *catDie = [SKAction runBlock:^{
[node removeFromParent];
}];
SKAction *animation = [SKAction sequence:#[wait, catDie]];
[self runAction:animation];
}
}]; NSLog(#"test 1");
}
Enumerating over all cat nodes is not necessary since you can get the node involved in the contact from the SKPhysicsContact object. The following shows how to do that...
EDIT: you can change the cat node's name to prevent it from chasing the zombie
-(void)didBeginContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (enemyCategory | catsCategory)) {
SKNode *node = contact.bodyA.node;
if (contact.bodyB.categoryBitMask == catsCategory) {
node = contact.bodyB.node;
}
// One way to stop the cat from chasing zombie is by changing its name
node.name = #"not cat";
}
}
I am trying to make a SpriteKit game but I cannot figure out or find a good example of multiple collision detection.
My code:
-(void)didBeginContact:(SKPhysicsContact *)contact{
SKPhysicsBody *firstBody;
SKPhysicsBody *secondBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
firstBody = contact.bodyA;
secondBody = contact.bodyB;
}
else
{
firstBody = contact.bodyB;
secondBody = contact.bodyA;
}
if ((firstBody.categoryBitMask & bulletCategory) != 0) {
[self updateScore];
SKNode *applenode = [self childNodeWithName:(#"Apple")];
applenode.removeFromParent;
[self updateScore];
SKScene *sampleScene = [[Level2 alloc] initWithSize:self.size];
SKTransition *transition = [SKTransition flipVerticalWithDuration:0.5];
[self.view presentScene:sampleScene transition:transition];
}
Worked great for one collision but I cannot seem to get it to work for multiple.
//for multiple collision you can add code like something that
(void)didBeginContact:(SKPhysicsContact *)contact
{
CGPoint contactPoint=CGPointMake(0, 0);
//multiple collision
if (contact.bodyA.categoryBitMask || contact.bodyB.categoryBitMask)
{
//first collision
if(([contact.bodyA.node.name isEqualToString:#"hero"] && [contact.bodyB.node.name isEqualToString:#"coin"] ) || ([contact.bodyA.node.name isEqualToString:#"coin"] && [contact.bodyB.node.name isEqualToString:#"hero"]) )
{
if([contact.bodyA.node.name isEqualToString:#"coin"] )
{
[contact.bodyA.node removeFromParent];
}
else
{
[contact.bodyB.node removeFromParent];
}
}
//second collision
else if(([contact.bodyA.node.name isEqualToString:#"hero"] && [contact.bodyB.node.name isEqualToString:#"enemy"] ) || ([contact.bodyA.node.name isEqualToString:#"enemy"] && [contact.bodyB.node.name isEqualToString:#"hero"]) )
{
if([contact.bodyA.node.name isEqualToString:#"hero"] )
{
[contact.bodyA.node removeFromParent];
}
else
{
[contact.bodyB.node removeFromParent];
}
}
}
}
Why the created name of a sprite isn't saved or even returned ?
I add several objects (SKSpriteNode) in the init of the Scene
-(id)initWithSize:(CGSize)size {
NSArray *oxyObjects = [self.oxygens objectsNamed:#"oxy"];
for (NSDictionary *enemyObj in oxyObjects) {
SKSpriteNode *oxyNode = [SKSpriteNode spriteNodeWithImageNamed:#"oxygen"];
NSString *valeurX=enemyObj[#"x"];
float x = [valeurX floatValue];
NSString *valeurY=enemyObj[#"y"];
float y = [valeurY floatValue];
CGPoint oxyPosition = CGPointMake(x, y);
oxyNode.position = oxyPosition;
oxyNode.name = #"ballOxygen";
NSLog(#"oxy %#",oxyNode);
[self.map addChild:oxyNode];
}
The log give me this with the correct name for the sprite
oxy name:'ballOxygen' texture:[ 'oxygen#2x.png' (24 x 24)] position:{454, 99} size:{12, 12} rotation:0.00
To check collision, I tried to use
[[self children] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
SKNode *node = (SKNode *)obj;
NSLog(#"obj : %#", obj);
Or this
NSArray *nodes = self.children;
for(SKNode * node in nodes){
SKSpriteNode *obj = (SKSpriteNode *) node;
NSLog(#"obj : %#", obj);
But It return always a null name
obj : name:'(null)' texture:[ 'Bird1#2x.png' (8 x 24)] position:{100, 100} size:{17, 12} rotation:0.00
My best guess:
You are adding oxyNode to self.map but you are enumerating self.children where you probably should be enumerating self.map.children.
Try this:
[self.map.children enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
SKNode *node = (SKNode *)obj;
NSLog(#"obj : %# (%p)", obj, obj);
}];
My game keeps crashing around this particular block of code.
The error message is Thread1: EXC_Bad_ACCESS(code =1) and the highlighted code is the following:
-(void)updateForArrays:(ccTime)delta
{
for (CCSprite *child in [self children]){
if (child.tag==2) {
if (CGRectIntersectsRect(child.boundingBox, _ship.boundingBox)) {
[self removeChild:child cleanup:YES];
_score += 1;
[_scoreLabel setString:[NSString stringWithFormat:#"Score : %d",_score]];
}
}if (child.tag ==3){
if (CGRectIntersectsRect(child.boundingBox, _ship.boundingBox)) {
CCScene *gameOverScene = [GameOverLayer gameOverScene];
[[CCDirector sharedDirector] replaceScene:gameOverScene];
}
}
}
}
You shouldn't modify ([self removeChild:child cleanup:YES]) collections (the [self children] array) while iterating. One way to go around this is to add objects for removal in a separate array and remove them after you're done checking for collisions.
Edit:
NSMutableArray *cleanupArray = [NSMutableArray array];
for (CCSprite *child in [self children]) {
// ...
[cleanupArray addObject:child]; // instead of [self removeChild:child cleanup:YES];
// ...
}
// actual removal of children
for (CCSprite *child in cleanupArray) {
[self removeChild:child cleanup:YES];
}
[cleanupArray removeAllObjects];
If all the children of self is of type CCSprite then your code will work. If not then you will face a crash. Because there is a chance that you might be forcefully typecasting a child which is of no CCSprite class. See if this code helps
-(void)updateForArrays:(ccTime)delta
{
for (id item in [self children]){
if((item isKindOfClass:(CCSprite class)])
{
CCSprite *child = (CCSprite *)item;
if (child.tag==2) {
if (CGRectIntersectsRect(child.boundingBox, _ship.boundingBox)) {
[self removeChild:child cleanup:YES];
_score += 1;
[_scoreLabel setString:[NSString stringWithFormat:#"Score : %d",_score]];
}
}if (child.tag ==3){
if (CGRectIntersectsRect(child.boundingBox, _ship.boundingBox)) {
CCScene *gameOverScene = [GameOverLayer gameOverScene];
[[CCDirector sharedDirector] replaceScene:gameOverScene];
}
}
}
}
}