0

I am attempting to add a particle effect in the touchesBegan method, so when the user touches the drawn sprite(SKSpriteNode), it draws the particle effect. However, I receive an error Attempted to add a SKNode which already has a parent: SKEmitterNode. To add some context... The game is of the bejeweled/candy crush style where blocks(deleteNode) are deleted based upon neighboring colors. In the touch event I iterate recursively, checking neighboring blocks and add them to an array to later be removed. Prior to each block(deleteNode) being removed I would like the particle event to occur. They both inherit from SKNode (right?), so I don't understand the conflict...

@interface
{
   NSString *blockParticlePath;
   SKEmitterNode *blockParticle;
}

in the initialization method...

blockParticlePath = [[NSBundle mainBundle] pathForResource:@"blockParticle" ofType:@"sks";
blockParticle = [NSKeyedUnarchiver unarchiveObjectWithFile:blockParticlePath];

in touchesBegan...

blockParticle.position = deleteNode.position;
blockParticle.particleColor = deleteNode.color;
[self addChild:blockParticle];

To make sure I wasn't crazy, I checked other forums and have seen this same logic for adding particle effects to a scene. Thanks in advance. If you need any more info let me know.

whfissler
  • 1
  • 1
  • If your simply adding your particle to self (I.e. SKScene) you should be ok, check that particle does not have a parent. Try creating a new project, create the particle and then add it to the SKScene, if that works you probably have something going on that your missing. – fuzzygoat Feb 16 '14 at 10:38
  • @fuzzygoat: I did perform that test. In the SpriteKit default project, I added my 6 lines of code, minus the deleteNode variable. Instead using a CGMakePoint for the position and a SKColor for the color, and it works fine. My next step is to assign similar values in the original project. Could the compiler confuse the emmitter node with a sprite node simply because I am assigning values related to the sprite node? After further testing I'll comment again. Thanks. – whfissler Feb 16 '14 at 15:14
  • Ok, so I tried setting the position as a new CGPoint: blockParticle.position = CGMakePoint(deleteNode.position.x, deleteNode.position.y); which I probably should have anyway. But, still same error. I then removed all my particle logic from the touch event and added the particle to the scene from within the initialization method, it works. It's not dynamic to my blocks, but it is drawn in the scene... – whfissler Feb 16 '14 at 15:51
  • 1
    Derp! I had created a class BlockNode that handle the blocks' behavior. That was where the conflict was coming from, not the SKNode class. I added a AddParticle method to my BlockNode class and voila dynamically placed particles. Now on to the zPosition of the particle, because CGPointMake only takes in x and y values. @fuzzygoat thanks for sparking the correct train of thought. BTW is there a way to "thank" for the comment, if it wasn't an answer? – whfissler Feb 16 '14 at 17:01

1 Answers1

0

@whfissler, you explanations helped a lot to pinpoint this solution.

This error occurred only when I had many SKSpriteNodes active (ballon game). On each ballon click it pops and a SKEmitterNode (explosion) is added. It seems that when the particles created by the explosion touch each other I recieve the same error like you. I changed my code from:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    SKEmitterNode *explosion = [SKEmitterNode orb_emitterNamed:@"ballonEksplosion"];
    CGPoint positionInScene = [touch locationInNode:self];
    explosion.position = positionInScene;
    SKSpriteNode *touchedSprite;
    for ( int i = 0; i < [[self nodesAtPoint:positionInScene] count]; i++)
    {
        touchedSprite = (SKSpriteNode *)[[self nodesAtPoint:positionInScene] objectAtIndex:i];
        if ([touchedSprite.name isEqualToString:@"BALLON"])
        {


            [(MBDBallon *)touchedSprite popAndRemoveWithSoundEffect];
            [self addChild:explosion];
        }
    }
}

to:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint positionInScene = [touch locationInNode:self];
    SKSpriteNode *touchedSprite;
    for ( int i = 0; i < [[self nodesAtPoint:positionInScene] count]; i++)
    {
        touchedSprite = (SKSpriteNode *)[[self nodesAtPoint:positionInScene] objectAtIndex:i];
        if ([touchedSprite.name isEqualToString:@"BALLON"])
        {
            SKEmitterNode *explosion = [SKEmitterNode orb_emitterNamed:@"ballonEksplosion"];
            explosion.position = positionInScene;
            [(MBDBallon *)touchedSprite popAndRemoveWithSoundEffect];
            [self addChild:explosion];
        }
    }
}

and it worked. To me it seems that my explosion SKEmitterNode had been kept somehow to long on the SKScene and therefore adding another SKEmitterNode for the currentPosition lead to problems with the:

self nodesAtPoint:positionInScene

nodesAtPoint stack.

I don´t understand it fully, maybe this helps you in further understanding.

MB_iOSDeveloper
  • 4,178
  • 4
  • 24
  • 36