Swift comes bundled with Sprite Kit, which is a graphics rendering and animation infrastructure and includes, amongst other things, support for physics and particle systems. Inspired by this post from Thibault Imbert, I thought I'd attempt to create a scene containing a handful of bouncing balls, each emitting particles.
The first step is to create a game application project and define the game technology as Sprite Kit:
Our main class in this project defaults to GameScene.swift and, in this case, I override the didMoveToView() method to start adding the physics bodies. Each body is an instance of an SKShapeNode with a SKPhysicsBody attached. The SKPhysicsBody has properties such as friction, mass and restitution (the elasticity).
let shape = SKShapeNode(circleOfRadius: 20);
[...]
shape.physicsBody = SKPhysicsBody(circleOfRadius: 20);
shape.physicsBody.friction = 0;
shape.physicsBody.charge = 4;
The next step is to create a particle system. Scene Kit has a set of predefined particle systems built in and these are added as a separate sks file via file -> new -> file -> resource -> SpriteKit Particle File. From there, you can select which preset to use:
Once the sks file is imported into the project, its properties can be edited with the SKNode Inspector under view -> utilities.
This editor sets the initial emitter properties, I can access all those properties at runtime using dot syntax, for example:
emitter.particleLifetimeRange
Inside my loop to create the bouncing balls, I need to create an instance of the newly created emitter and link it to my ball. This is done by unarchiving the sks file and then casting to a SKEmitterNode:
let untypedEmitter : AnyObject = NSKeyedUnarchiver.unarchiveObjectWithFile(NSBundle.mainBundle().pathForResource("MyParticle", ofType: "sks"));
let emitter:SKEmitterNode = untypedEmitter asSKEmitterNode;
My initial thought was to add the emitter as a child of the shape, but this resulted in the entire particle field following the shape as it moved. What I needed to do was set the emitter's shapePosition to that of the shape's position and update the particlePosition with each frame.
In the creation loop, I populate an array with a tuple of the shape and emitter.
var shapeEmitterTuples : [(SKShapeNode,SKEmitterNode)];
let shapeEmitterTuple = (shape, emitter);
shapeEmitterTuples.append(shapeEmitterTuple);
In ActionScript, I would have created a shape/emitter value object and populated a vector, but for these lightweight objects, a tuple is perfect.
Finally, I override the update() method (which works like enterFrame in AS3), I loop over my array of shape/emitter tuples to update the emitter's particlePosition with its shape's position.
for (shape, emitter) inshapeEmitterTuples
{
emitter.particlePosition = shape.position;
}
After adding some touch handlers to update a radial gravity field to follow the touch point, we have a simple demo of some bouncing balls emitting basic particles.
The entire project is available in my Git Hub repository here.