SpriteKit and Physics in F#

In my last post I covered the absolute most basic thing you can do with Apple’s new Sprite Kit API – put a single sprite onscreen. Dave Thomas wrote a much more in depth (and interesting) post on the topic which you should check out here.

Today I’d like to introduce the physics portion of Sprite Kit.

The physics in SpriteKit come courtesy of Box2D, a rich 2D-only physics engine written in C++. SpriteKit and Xamarin exposes this smoothly to all .NET languages. There’s also an excellent pure C# version called Farseer which is fully usable from Xamarin iOS and Android if cross-platform is your thing.

Creating a world

Just like in the previous post, all the code I’m going to include will live in the ViewDidLoad method on the ViewController from the default F# SingleViewController project.

So first a quick recap – let set up a SpriteKit scene

 let skView = new SKView()
 skView.Bounds <- RectangleF(0.f,0.f, 
                             x.View.Bounds.Width * UIScreen.MainScreen.Scale, 
                             x.View.Bounds.Height * UIScreen.MainScreen.Scale)
 skView.ShowsFPS <- true
 skView.ShowsNodeCount <- true
 x.View <- skView

 let scene =  new SKScene(skView.Bounds.Size)
 scene.BackgroundColor <- UIColor.Cyan
 scene.ScaleMode <- SKSceneScaleMode.AspectFit

Now, a Scene comes with a PhysicsWorld property, pre-allocated to something that will allow use to set settings on our scene’s physics properties. By default the world is set up with Gravity at (0,-9.8). Should you want to change gravity, its as simple as

scene.PhysicsWorld.Gravity <- CGVector(0.f,-198f) //Really strong gravity!!

Having a scene with gravity is great, but by default nothing is affected by gravity or anything else in the scene! To do this, lets rewind again to loading a sprite.

 let spriteNode = new SKSpriteNode "Filename"
 scene.AddChild spriteNode

To add physical properties (which is what lets SpriteKit know we want the physics engine to control it) you have to set the PhysicsBody property of the sprite:

 spriteNode.PhysicsBody <- SKPhysicsBody.BodyWithCircleOfRadius 10.f

Now this will set up the object as a circle, but of course you’re not limited to a Circle – there are a number of methods to set the shape as almost anything using boxes and polygon shapes – for example:

 BodyWithRectangleOfSize
 BodyWithPolygonFromPath

By default the bodies created will have a the following (useful) properties set to true – AffectedByGravity and Dynamic. AffectedByGravity means that when you run the scene the sprite will automatically drop from its initial position under the force of gravity until something stops it. Dynamic means that when something hits it it too responds (Newton’s 3rd law). Setting Dynamic to false makes it an immovable object (think wall or floor).

So here’s a complete code sample – nothing too exciting – a bunch of balls (well, owls) dropping to the floor.

     override x.ViewDidLoad () =
         base.ViewDidLoad ()

         //Create SpriteKit view
         let skView = new SKView()
         skView.Bounds <- RectangleF(0.f,0.f, 
                                     x.View.Bounds.Width * UIScreen.MainScreen.Scale, 
                                     x.View.Bounds.Height * UIScreen.MainScreen.Scale)
         skView.ShowsFPS <- true
         skView.ShowsNodeCount <- true
         x.View <- skView

         //Create a SpriteKit Scene
         let scene =  new SKScene(skView.Bounds.Size)
         scene.BackgroundColor <- UIColor.Cyan
         scene.ScaleMode <- SKSceneScaleMode.AspectFit

         let r = Random()
         //Load a texture and create 100 sprite in random locations
         //With physical properties
         let texture = SKTexture.FromImageNamed "Owl"
         for i in 0..100 do
             let spriteNode = new SKSpriteNode(texture)
             spriteNode.Position <- PointF(float32 <|r.Next 650,float32 <| r.Next 2000)
             spriteNode.PhysicsBody <- SKPhysicsBody.BodyWithCircleOfRadius 10.f
             scene.AddChild spriteNode

         //Add an immovable floor for the owls to bounce off
         let floor = new SKSpriteNode "Floor"
         floor.Position <- PointF(x.View.Bounds.Width / 2.0f ,0.0f)
         floor.PhysicsBody <- SKPhysicsBody.BodyWithRectangleOfSize(SizeF(640.f,32.f))
         floor.PhysicsBody.AffectedByGravity <- false
         floor.PhysicsBody.Dynamic <- false
         scene.AddChild floor

         //Run the scene
         skView.PresentScene scene

Note the owls are all dynamic and affected by gravity and the floor is not.

The result of the above code is this rather impressive demo:

Half Life 2 eat your heart out!

This simple demo shows how easy it is to add sprites with realistic physics to a scene in SpriteKit. There are lots of properties to play with on the PhysicsBody, to adjust the mass, density, restitution and more.

Next Time…..

I’ll walk through how to react when something happens (think play sound effect when 2 objects collide) and how to apply forces to add gameplay using touch control.

About thedo666

Software developer trying to learn a new language - English!
This entry was posted in F#, iOS and tagged , , . Bookmark the permalink.

3 Responses to SpriteKit and Physics in F#

  1. Pingback: F# Weekly #39, 2013 | Sergey Tihon's Blog

  2. Pingback: A Platform game in SpriteKit and F# – Part 1 – Game State Management | Neil Danson's Blog

  3. Pingback: F# Summer of Code 2014

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s