A Platform game in F# and SpriteKit – Part 4 – Running and Scrolling

So far in this series I’ve covered how to build a largely static screen in SpriteKit. Today I’m going to cover 2 things

  1. I’m going to move our dude from left to right under force
  2. I’m going to scroll the camera with him

The entirety of the code changed in this post is here.

Moving the player

So rather than build a Mario type game, I want this to be more like a continuos runner in the vein of Canabalt (for now at least), so to simulate our movement I’m going to apply a constant pressure to the player every frame. This is where we hit our 1st major problem in the current game code.

The problem is that so far I’ve use async workflows to give a nice linear look at game flow, and SpriteKit does enough ‘magic’ that it hangs together and it all works. But to apply force to the player, doing it once isn’t enough – I need to do it constantly – preferably every frame.

One approach is to subclass SKScene and move all our game into the Scene. I don’t like this for a number of reasons. The chief one is that it mean we have game logic code outside of our level async workflow, defeating the point of having it, and reducing us back to the classical OO game state management.

My approach is to subclass SKScene, but expose an event for when the Update method is called. Now using this we can subscribe to the event in our workflow, keep our logic local, and because of the use binding have it cleanup when exiting the async block! Here’s the code:

 type Scene(size:SizeF) = 
    inherit SKScene(size) 

    member val UpdateEvent = Event<_>()
    override s.Update time = 
       s.UpdateEvent.Trigger time

And later in the level code:

 //Add event to know when Update is called
 use _ = scene.UpdateEvent.Publish.Subscribe(fun time -> player.PhysicsBody.ApplyImpulse(CGVector(2.0f,0.0f)))

Scrolling the view

One of the areas I think a lot of sprite based APIs gets it wrong is by making scrolling about moving the sprites, whereas really you want to be moving the camera. Unfortunately SpriteKit makes this mistake and is about moving Sprites. This is a shame because it looks like it should work; An SKScene has a Position property, just like every other SKNode. Great! But if we set that we get no runtime behaviour other than a warning in the debug output:

2013-10-14 05:46:25.836 PlatformGame[13852:a0b] SKScene: Setting the position of a SKScene has no effect.

This is one of the ways that SpriteKit clearly misuses OO and ends up with a slightly wonky inheritance structure. No biggie, but it does mean that we cannot scroll by moving the scene.

Luckily for us SpriteKit helps us overcome this. I’m still going to take advantage of the Position of an SKNode, but I’m going to add in a “ScrollNode” (which is just an SKNode) an in the level workflow I’m going to take everything I added to the SKScene and add it to my Scroll Node instead. I’ll then move the scroll node.

use scrollNode = new SKNode()
scene.AddChild scrollNode

Now we can handle the scrolling the same way we handled the player updating, except we cant do it from the Update event. When we update the player physics nothing is applied until later, but SpriteKit offers another method in SKScene to override called DidSimulatePhysics(). If we follow the same pattern as above with the Update event we can fill in our new Scene so that it looks like this:

 type Scene(size:SizeF) = 
     inherit SKScene(size)
     member val UpdateEvent = Event<_>()
     member val DidSimulatePhysicsEvent = Event<_>()
     override s.Update time =
        s.UpdateEvent.Trigger time

     override s.DidSimulatePhysics() =
        s.DidSimulatePhysicsEvent.Trigger None

And once again we’ll consume this in the level async workflow:

 //Move the scroll node inversely to the players position so the player stays centered on screen
 use _ = scene.DidSimulatePhysicsEvent.Publish.Subscribe(fun _ -> 
 scrollNode.Position <- PointF(320.f - player.Position.X,0.0f))

Bonus!

Funny story – I was talking about the recent GameCraft event in London to a coworker, and mentioned the term parallax scrolling in our entry. He stared blankly and I felt very old. He’s 22.

But regardless of whether you have heard of it or not, Parallax scrolling is a cool effect. For those who havent heard of it, its the effect of moving something in the background more slowly than something in the foreground, creating a pseudo 3D effect.

So to do this in SpriteKit is similar to the scrolling method – first we add a scrollNode for the parallax layer, then we add some stuff to it (but this time with no physics – its purely background), and when we offset the scroll we do it at a fraction of the full speed.

Here’s the code broken into bits.

Setup:

use parallaxScrollNode = new SKNode()
scene.AddChild parallaxScrollNode
//Pop in a parallax layer
for i in 0..50 do 
    use hill = new SKSpriteNode "hill_small"
    hill.Position <- PointF(float32 i * 70.f, 50.f)
    hill.ZPosition <- -1.f
    parallaxScrollNode.AddChild hill

Note we set up the hill with a Z position to move the layer “back” into the scene. Then in the DidSimulatePhysics event we will offset the parallaxScrollNode –

//Move the scroll node inversely to the players position so the player stays centered on screen
use _ = scene.DidSimulatePhysicsEvent.Publish.Subscribe(fun _ -> 
scrollNode.Position <- PointF(320.f - player.Position.X,0.0f)
parallaxScrollNode.Position <- PointF(-player.Position.X / 2.f, 0.f))

Closing up:

Today I’ve taken 2 closely linked ideas (player movement and scrolling) and tackled them in SpriteKit. We’ve had to introduce some inheritance and OO code to get the results we need, but this is one of the key strengths of F# – the ability to mix and match OO and functional programming in a no-compromise solution. The code, as always is at https://github.com/neildanson/PlatformGame.

Obligatory screenshot (if you don’t have Xamarin iOS you’ll just have to trust me that this is scrolling!)

Parallax Scrolling

Next time, I’m going to tackle sprite animation and add some sound to the game.

Advertisements

About thedo666

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

One Response to A Platform game in F# and SpriteKit – Part 4 – Running and Scrolling

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

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