Creating a trail with SKEmitterNode and particles in SpriteKit

4.6k views Asked by At

I am trying to make it so a particle I made follows the player whenever the player is moved. The effect I am trying to replicate is like when you are on a website and they have some sort of set of objects following your mouse. I tried to do this by making the particle move by the amount the player does, but it is not reproducing the intended effect. Any suggestions? My code:

Declaring particle

NSString *myParticlePath = [[NSBundle mainBundle] pathForResource:@"trail" ofType:@"sks"];
self.trailParticle = [NSKeyedUnarchiver unarchiveObjectWithFile:myParticlePath];
self.trailParticle.position = CGPointMake(0,0);
[self.player addChild:self.trailParticle];

Move method

 -(void)dragPlayer: (UIPanGestureRecognizer *)gesture {

         if (gesture.state == UIGestureRecognizerStateChanged) {

              //Get the (x,y) translation coordinate
              CGPoint translation = [gesture translationInView:self.view];

              //Move by -y because moving positive is right and down, we want right and up
              //so that we can match the user's drag location (SKView rectangle y is opp UIView)
              CGPoint newLocation = CGPointMake(self.player.position.x + translation.x, self.player.position.y - translation.y);
              CGPoint newLocPart = CGPointMake(self.trailParticle.position.x + translation.x, self.trailParticle.position.y - translation.y);

              //Check if location is in bounds of screen
              self.player.position = [self checkBounds:newLocation];
              self.trailParticle.position = [self checkBounds:newLocPart];
              self.trailParticle.particleAction = [SKAction moveByX:translation.x y:-translation.y duration:0];
              //Reset the translation point to the origin so that translation does not accumulate
              [gesture setTranslation:CGPointZero inView:self.view];

         }

    }
2

There are 2 answers

1
Vaclav Elias On

Try this:

1) If your emitter is in the Scene, use this emitter's property targetNode and set is as Scene. That means that particles will not be a child of emitter but your scene which should leave a trail..

Not sure if this is correct (I do it in C#):

self.trailParticle.targetNode = self; // self as Scene

And some extra:

2) I think you could rather attach your emitter to self.player as child so it would move together and automatically with your player and then there is no need of this:

self.trailParticle.position = [self checkBounds:newLocPart];
self.trailParticle.particleAction = [SKAction moveByX:translation.x y:-translation.y duration:0];
0
Wharbio On

In your update loop Check if your player is moving along the X axis. Then create a sprite node each time this is happening. In this example name your player "player1" The key here is your particle must have a max set in the particles column near birthrate. The blow code works for me.

-(void)update:(CFTimeInterval)currentTime {
// Find your player
SKNode* Mynode = (SKSpriteNode *)[self childNodeWithName:@"player1"];  

// Check if our player is moving. Lower the number if you are not getting a trail. 
 if (Mynode.physicsBody.velocity.dx>10|
 Mynode.physicsBody.velocity.dy>10|
 Mynode.physicsBody.velocity.dx<-10|
 Mynode.physicsBody.velocity.dy<-10){       


// Unpack your particle
NSString *myParticlePath = [[NSBundle mainBundle] pathForResource:@"trail" ofType:@"sks"];

//Create your emitter
SKEmitterNode *myTrail = [NSKeyedUnarchiver unarchiveObjectWithFile:myParticlePath];

// This ensures your trail doesn't stay forever . Adjust this number for different effects
myTrail.numParticlesToEmit=10; 

// The length of your trail - higher number, longer trail. 
myTrail.particleLifetime = 2.0; 

//Set the trail position to the player position   
myTrail.position=Mynode.position;

//Add the trail to the scene
[self addChild:myTrail];
}

}