A Platform game in SpriteKit and F# – Part 1 – Game State Management

So as I wrote some previous articles on SpriteKit I was planning on doing a few small bits that covered really small focussed parts of SpriteKit. The thing is that I actually really like SpriteKit and want to write an actual game. So like an overweight person announcing they are going on a diet to force themselves to stick to it, I hereby publicly state I’m going to write a game for iOS using SpriteKit and F#. There. I cant back out now.

Manifesto

So before going any further, I’m going to set some ground rules

  • The source will be free and open for anyone to use – the repository is here – I’ll try to marry up majorly interesting checkins with blog posts, so the source doesn’t get too far ahead of the blog.
  • There will be posts on interesting bits of code, challenges, thoughts.
  • I’m not an artist, so I paid (a few months ago) for this open source artwork and music – http://open.commonly.cc. I will be using this largely unmodified.
  • The result of the work will be free on the iOS App Store
    • Not everyone has Xamarin and MacOS to do iOS development so its easier to visualize whats going on where if there’s a thing to download

Today’s post

So my previous posts focussed heavily on how to make SpriteKit work in F#, but the results were

  1. Fairly boring
  2. Not really showing off what F# can do

So today, I’m going to keep #1 going on a little longer but tackle #2

The entire source for this post is available here, and largely builds on my previous 2 posts on SpriteKit.

Game State Management

One of the key challenges in games is state. It’s everywhere – whether you’re in the intro screen, the game screen, the pause screen, the game over screen or whether you’re alive or whether you’re dead or whether you’re powered up because of a mushroom or small because you just got hit.

Now googling Game State Management will bring you up with posts like this – Managing Game States in C++ (this happened to be the top Google result). The approach taken in most of these kind of posts is usually about the same – define some states (usually using inheritance) and implement a state manager to handle transitions between them. Which is absolutely fine and proven to work, but…..

I believe F# offers a better solution.

Wouldn’t it be nice if….

Game code looked sequential? How awesome would it be if you could write something like

loop
   do IntroScreen
   do Level1
   do GameOver

In F# you can! The magic part (as it so often is in F#) is the elegant Async Workflows. Let’s take a look at how Async helps.

Let’s define what we want to do for an Intro Screen –

  1. Show some text that tells the user to tap to begin
  2. Move to the next state when the user taps

Similarly for the Game Over screen we’ll

  1. Berate the user for failing (probably by saying “Game Over”)
  2. Wait 5 seconds before going back to the intro screen.

Let’s start with the Intro Screen

 let startScreen() = async {
             let tapEvent = Event<_>()
             let tapRecognizer = new UITapGestureRecognizer(Action<_>(fun x -> tapEvent.Trigger(null)))
             x.View.AddGestureRecognizer tapRecognizer

             //Add some text to the screen
             use tapToBegin = new SKLabelNode("Papyrus", Text="Tap to Begin", FontSize=42.f)
             tapToBegin.Position <- PointF(320.f, 240.f)
             scene.AddChild tapToBegin

             //Give a little animation
             let scale = SKAction.Sequence [| SKAction.ScaleTo(1.5f,0.5)
                                              SKAction.ScaleTo(1.0f,0.5) |]
                         |> SKAction.RepeatActionForever                     
             tapToBegin.RunAction(scale)

             //Wait for the tap
             let! _ = Async.AwaitEvent tapEvent.Publish

             //Cleanup!!
             scene.RemoveAllChildren()
             x.View.RemoveGestureRecognizer tapRecognizer
         }

So what do we have here? First create a new Event – in F# events are first class citizens which comes in really handy in game code. We set up a TapGestureRecognizer which triggers the event (we could pass extra information in here, but for now the naughty null will suffice). Down near the bottom we AwaitEvent asynchronously while SpriteKit takes care of playing a nice scale in and out animation for us. Note the pipelining makes the code much easier to read than if it was burdened with nested parentheses. Once the tap happens we cleanup after ourselves.

The Game Over code is similar – same basic idea, but for giggles rather than await an event we’ll simply Async.Sleep while the message spins and scales away:

 let gameOver() = async {            
             //Add some text to the screen
             use gameOverText = new SKLabelNode("Papyrus", Text="Game Over", FontSize=42.f, Scale=10.f)
             gameOverText.Position <- PointF(320.f, 240.f)
             scene.AddChild gameOverText  

             //Give a little animation
             let action = SKAction.Group [| SKAction.ScaleTo(1.0f,2.) 
                                            SKAction.RotateToAngle(float32 Math.PI * 2.f, 1.9)|] 
             gameOverText.RunAction(action) 

             //Wait 5 seconds, to rub in the player's abject failure             
             do! Async.Sleep 5000

             //Cleanup!!
             scene.RemoveAllChildren()
         }

Couple of interesting points:

  1. The SKAction API in SpriteKit is really quite cool and looks like it was designed as a native F# API. The Sequence and Group operations allow for nice declarative animations in code.
  2. The SKAction API takes time in seconds, while most .NET APIs are in milliseconds. This really threw me for a while (my animations were **really** slow!).

Tying it all together (Doesn’t this look an awful lot like my code further up – spooky eh?)-

 //Define the loop
 let rec gameLoop() = async {
    do! startScreen()
    do! level1()
    do! gameOver()
    return! gameLoop()
 } 

 //Run the loop
 gameLoop() |> Async.StartImmediate

First we define a loop, and do! our way through the states. The level1 state is currently empty, and will be the focus of the next post (tackling the “Fairly boring” issue), but for now we can do Game State Management in F# using primitive F# code.

In closing

In this post I’ve shown how to use the following F# features to simplify writing games in F# using SpriteKit on iOS. Those features are

  • Async Workflows
  • Events as first class language features
  • Pipeline operators for clarity

The C# team omitted the useful AwaitEvent function in C# 5 when they copied from F# invented async/await, which is something we can use frequently in game state management.

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 SpriteKit and F# – Part 1 – Game State Management

  1. Pingback: F# Weekly #41, 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