Last summer, I created a few Flash based applications recreating Hiroki Sayama's Swarm Chemistry. I thought that as a follow on from my recent experiments with NSOperation and threading for iOS, I'd try the same in Swift.
Swarm Chemistry is another great example of morphogenesis. It simulates systems of heterogeneous particles that have genomes that describe simple kinetic rules, such as separation and cohesion, and emergent phenomena including self organization and mitosis can be observed.
It's computationally pretty heavy going. Each individual particle, or swarm member, interrogates every other. So, for 100 members, each update requires 10,000 steps. One technique to optimise this is Bin Lattice Spatial Subdivision and I'll be looking to implement that in my next release.
My initial experiments used Sprite Kit and each particle was a small sprite, however it quickly became apparent that with large number of sprites, redrawing became a performance bottleneck. I decided to render my own bitmap, much like I did with my reaction diffusion experiment. However, Joseph Lord had kindly revisited this code and I've implemented his code to create a UIImage instance of my swarm.
Another great tip from Joseph was returning to typed Swift Arrays of structs rather than using NSMutableArrays of classes. Although in the default build configuration of Debug, NSMutableArray is considerably faster than Array, switching to Release configuration turns that around and Arrays become amazingly fast.
This code runs at about a frame a second in Debug configuration, so be sure to edit the configuration and set it to Release:
Each swarm member is represented by a SwarmMember struct. Its rules are represented by an instance of a SwarmGenome class. The reason I decided on the latter being a class is because, as a class, instances of it are passed by reference rather than value. This means that when I edit one of the rule parameters, such as alignment, every member implementing that genome is affected by the change. If SwarmGenome was a structure, I'd have to loop through every member and update its genome's properties.
One of the nice things in Xcode 6 release 6 is class functions on classes - much like a static on a structure.
I've also avoided NSOperation in this release and used Tobias Due Munk's Async library. This offers some nice syntactic sugar for Grand Central Dispatch and makes writing asynchronous code even simpler. No dodgy timer code like last time - my two functions for dispatching solve and render tasks look like this:
func dispatchSolve()
{
Async.background
{
self.swarmMembers = solveSwarmChemistry(self.swarmMembers);
}
.main
{
self.dispatchRender();
self.dispatchSolve();
}
}
func dispatchRender()
{
Async.background
{
self.image = renderSwarmChemistry(self.swarmMembers);
}
.main
{
self.uiImageView.image = self.image;
}
}
The code inside the .background block executes in the background and once that's finished, the code inside the .main block is executed in my UI thread, so everything updates nicely.
The user interface is pretty basic. In this version, the user has four genomes (cyan, red, blue and yellow) they can edit. By selecting the genome in the top button bar and then selecting a parameter in the bottom button bar, the slider sets the value of that genome/parameter.
The number of members is hard coded to 800 right now. It runs beautifully under my iOS simulator on my iMac, but is a bit clunky on my A6X based iPad. I'm holding off buying an A7 iPad, hoping that a shiny new A8 based one will be released soon, but I'd be very interested to hear how it runs on an A7.
All the source code is available at my GitHub repository here.
Add a comment