SKEmitterNode not acting as expected - sprite-kit

In my SK game, I have a helicopter that launches rockets. The heli can only have one rocket on the screen at a time, the reason being that I didn't want to have to create a new SKEmitterNode every time a rocket is launched, because it seems this would be taxing on the CPU, having to unarchive the emitter every time.
Therefore, the rocket is a single instance. When someone launches a rocket, it is added to the scene as a child of the scene, launched, and when it hits something, removed from it's parent.
In my update{} metho, here's some psuedo-code:
if ([rocket parent]) {
rocketSmoke.position = rocket.position;
rocketSmoke.numParticlesToEmit = 0;
}else{
rocketSmoke.numParticlesToEmit = 1;
}
So basically, the emitter follows the rocket if it exists and if it doesn't exist, the emitter turns itself off. No, I cannot just add the emitter as a child of the rocket because then when the rocket hits an object and I call removeFromParent the smoke trail behind the rocket will instantly dissapear and that's not the effect I'm going for.
The problem is, when a new rocket is launched and numParticlesToEmit is set back to zero, the particle emitter acts like it's been emitting particles the entire time! I want the particle emitter to simply turn back on, but a bunch of smoke instantaneously appears behind the helicopter as well. You can observe this effect by playing with an emitter file in SK and setting the "max" on the particles to emit to 1, and then setting it back to zero: your screen will instantaneously fill back up as if it had been emitting particles the whole time. Obviously that's not what I want.
I also can't call resetSimulation, because that will remove all existing particles, and so any lingering smoke from the last launch will instantaneously disappear, which would look pretty unnatural if two rockets were launched one after another.
Is my only option to write my own emitter?

Create new instances of the emitter for each different rocket. That will resolve your problem.
If it becomes "Too Taxing on the CPU" then create two emitters and alternate which one is used.
Ex. Fire rocket 1, use emitter 1.
Fire rocket 2, use emitter 2.
Fire rocket 3, use emitter 1.
This will give you time for the emitter to finish the effect you want when a rocket hits something while also allowing your next rocket's emitter to behave as desired.

Related

Drawable presented late, causes steady state delay

I have a little Swift playground that uses a Metal compute kernel to draw into a texture each time the mouse moves. The compute kernel runs very fast, but for some reason, as I start dragging the mouse, some unknown delays build up in the system and eventually the result of each mouse move event is displayed as much as 4 frames after the event is received.
All my code is here: https://github.com/jtbandes/metalbrot-playground
I copied this code into a sample app and added some os_signposts around the mouse event handler so I could analyze it in Instruments. What I see is that the first mouse drag event completes its compute work quickly, but the "surface queued" event doesn't happen until more than a frame later. Then once the surface is queued, it doesn't actually get displayed at the next vsync, but the one after that.
The second mouse drag event's surface gets queued immediately after the compute finishes, but it's now stuck waiting for another vsync because the previous frame was late. After a few frames, the delay builds and later frames have to wait a long time for a drawable to be available before they can do any work. In the steady state, I see about 4 frames of delay between the event handler and when the drawable is finally presented.
What causes these initial delays and can I do something to reduce them?
Is there an easy way to prevent the delays from compounding, for example by telling the system to automatically drop frames?
I still don't know where the initial delay came from, but I found a solution to prevent the delays from compounding.
It turns out I was making an incorrect assumption about mouse events. Mouse events can be delivered more frequently than the screen updates — in my testing, often there is less than 8ms between mouse drag events and sometimes even less than 3ms, while the screen updates at ~16.67ms intervals. So the idea of rendering the scene on each mouse drag event is fundamentally flawed.
A simple way to work around this is to keep track of queued draws and simply don't begin drawing again if another drawable is still queued. For example, something like:
var queuedDraws = 0
// Mouse event handler:
if queuedDraws > 1 {
return // skip this frame
}
queuedDraws += 1
// While drawing
drawable.addPresentedHandler { _ in
queuedDraws -= 1
}

SKEmitterNode tied to a moving SKNode

I am attempting to move a SKEmitterNode to follow a bullet in my game to give it a trailing effect however, no matter which way I attempt to implement this, it doesn't seem to work how I want it to and I'm at a loss for how to make this.
I have attempted to add the emitter to my main scene and manually moved the node a few times per second but it ends up not leaving a trail and keeping all the particles in one place like this:
Next I attempted to set the target node, however when I do this the trail goes for a bit then stops rather than following the bullet like it's supposed to. It also rotates and distorts from the rotation of the projectile like shown here:
For reference of the type of effect I'm looking for:
You should populate the targetNode property of your emitter with a node that is not moving like the scene.
emitterNode.targetNode = self // where self is the current scene

SceneKit memory management issues

So I am playing around with SceneKit (in Swift), and for pure fun, creating an endless runner style game. In the game scene, I have a character moving forward on the z-axis. I have setup a few objects that are repeatedly created when the last expires. Most of these objects are under a node hierarchy. So, I have attempted these two methods for memory management:
Method 1: I have an invisible plane. Only 'special' parent node bodies can collide with this plane. So when the parent node's physics body collides with it, I remove it from the parent, which in result the node removes all of its children.
Method 2: Again I have an invisible plane. Except in this method everything I would potentially like to remove, can and does collide with the invisible plane on it's own accord. So in plain, everything collides with the invisible plane and removes itself from it's parent.
Now. Everything runs and works well. Except when it comes to removing nodes from their parents, I see a noticeable jolt in the framerate or speed of the game. Just for a second or so. With method 1, the jolt happens once for every time a parent node collides with my invisible plane. With method 2, the jolts are continuous and framerate is continuously low and jumpy.
I would be interested in hearing knowledge on ways of achieving something like this smoothly!
A big thanks in advance.

Restart SKEmitterNode without removing particles

I have a particle effect for a muzzle flare set up. What I'm currently using is a low numParticlesToEmit to limit the emitter to a short burst, and doing resetSimulation() on the emitter whenever I want to start a new burst of particles.
The problem I'm having is that resetSimulation() removes all particles onscreen, and I often need to create a new burst of particles before the previous particles disappear normally so they get erased early.
Is there a clean way start up the emitter again without erasing the particles already onscreen?
Normally particle systems have a feature missing from SKEmitters: a duration. This controls how long a system emits. I don't see this in SKEmitter, despite being in SCNParticleSystems
Never mind, a work around:
SKEmitters have a numParticlesToEmit property and a particleBirthRate. Combined, these determine how long the particle system emits before shutting down.
Using these as a control of the emission it's possible to create pulses of particles emitted in the way you want for something like a muzzle flash or explosion.
I'm not sure if it remvoes itself when it reaches this limit. If not, you'll have to create a removal function of some sort. Because the way to get your desired effect (multiple muzzle flashes on screen) is to copy() the SKEmitter. This is quite efficient, so don't worry about overhead.
There is a targetNode on SKEmitters that are suppose to move the particles to another node so that when you reset the emitter, the previous particles still stay. Unfortunately, this is still bugged from what I can tell, unless somebody else has figured out how to get it working and I just missed it. Keep this in mind though in case they do ever fix it.
Hi to help future readers, the code that I use to calculate the duration of the emitter is this:
let duration = Double(emitter.numParticlesToEmit) / Double(emitter.particleBirthRate) + Double(emitter.particleLifetime + emitter.particleLifetimeRange/2)
It works perfectly for me
Extension:
extension SKEmitterNode {
var emitterDuration: Double {
return Double(numParticlesToEmit) / Double(particleBirthRate) + Double(particleLifetime + particleLifetimeRange/2)
}
}

Positioning particles and life span of particle system in AndEngine GLES2

I am using particle system in my game, in andEngine GLES2, to produce a glittering effect.
I could not find a way to position particles after these are attached to the scene(run time).
Secondly i want to know if there is a way to make a check on the particles movement like listener in animations because I want to stop particles to emit after they expire first time.
Any help in this regard will be much appreciated.
First positioning particle system, There is a method setCenter that you can use in following manner.
particleEmitter.setCenter(pSceneTouchEvent.getX(), pSceneTouchEvent.getY());
Also you can see basic andengine example to clear your concept.
Second stop particle system, As per my consideration there is no listener for particle system. So to satisfy you need you have to think differently. You have to use TimerHandler to satisfy your need. When first time onTimer method of TimerHandler gets executed at that time you have to detach particle system or whatever you want to do.
if you want to move particles in different directions then add
new VelocityParticleInitializer<Sprite>(30,-42, -40, 40)
to the partial system.
Example:
systemBallParticleSystem.addParticleInitializer(new VelocityParticleInitializer<Sprite>(30,-42, -40, 40));
Second point
when partical effect started register a delay modifier and detach your system after that time
Example:
registerEntityModifier(new DelayModifier(pDuration, pEntityModifierListener));
in this pEntityModifierListener you can detach your partical system