SpriteKit in Xamarin.iOS

SpriteKit, the 2D graphics framework from Apple, has some interesting new features in iOS 8 and OS X Yosemite. These include integration with SceneKit, shader support, lighting, shadows, constraints, normal map generation, and physics enhancements. In particular, the new physics features make it very easy to add realistic effects to a game.

Physics Bodies

SpriteKit includes a 2D, rigid body physics API. Every sprite has an associated physics body (SKPhysicsBody) that defines the physics properties such as mass and friction, as well as the geometry of the body in the physics world.

Creating a Physics Body from a Texture

SpriteKit now supports deriving the physics body of a sprite from its texture. This makes it easy to implement collisions that look more natural.

For example, notice in the following collision how the banana and monkey collide nearly at the surface of each image:

SpriteKit makes creating such a physics body possible with a single line of code. Simply call SKPhysicsBody.Create with the texture and size: sprite.PhysicsBody = SKPhysicsBody.Create (sprite.Texture, sprite.Size);

Alpha Threshold

In addition to simply setting the PhysicsBody property directly to the geometry derived from the texture, applications can set and alpha threshold to control how the geometry is derived.

The alpha threshold defines the minimum alpha value a pixel must have to be included in the resulting physics body. For example, the following code results in a slightly different physics body:

sprite.PhysicsBody = SKPhysicsBody.Create (sprite.Texture, 0.7f, sprite.Size);

The effect of tweaking the alpha threshold like this fine-tunes the previous collision, such that the monkey falls over when colliding with the banana:

Physics Fields

Another great addition to SpriteKit is the new physics field support. These allow you to add things such as vortex fields, radial gravity fields and spring fields to name just a few.

Physics fields are created using the SKFieldNode class, which is added to a scene just like any other SKNode. There are a variety of factory methods on SKFieldNode to create different physics fields. You can create a spring field by calling SKFieldNode.CreateSpringField(), a radial gravity field by calling SKFieldNode.CreateRadialGravityField(), and so on.

SKFieldNode also has properties to control field attributes such as the field strength, the field region, and the attenuation of field forces.

Spring Field

For example, the following code creates a spring field and adds it to the scene:

SKFieldNode fieldNode = SKFieldNode.CreateSpringField ();
fieldNode.Enabled = true;
fieldNode.Position = new PointF (Size.Width / 2, Size.Height / 2);
fieldNode.Strength = 0.5f;
fieldNode.Region = new SKRegion(Frame.Size);
AddChild (fieldNode);

You can then add sprites and set their PhysicsBody properties so that the physics field will affect the sprites, as the following code does when the user touches the screen:

public override void TouchesBegan (NSSet touches, UIEvent evt)
	var touch = touches.AnyObject as UITouch;
	var pt = touch.LocationInNode (this);
	var node = SKSpriteNode.FromImageNamed ("TinyBanana");
	node.PhysicsBody = SKPhysicsBody.Create (node.Texture, node.Size);
	node.PhysicsBody.AffectedByGravity = false;
	node.PhysicsBody.AllowsRotation = true;
	node.PhysicsBody.Mass = 0.03f;
	node.Position = pt;
	AddChild (node);

This causes the bananas to oscillate like a spring around the field node:

Radial Gravity Field

Adding a different field is similar. For instance, the following code creates a radial gravity field:

SKFieldNode fieldNode = SKFieldNode.CreateRadialGravityField ();
fieldNode.Enabled = true;
fieldNode.Position = new PointF (Size.Width / 2, Size.Height / 2);
fieldNode.Strength = 10.0f;
fieldNode.Falloff = 1.0f;

This results in a different force field, where the bananas are pulled radially about the field: