A Platform game in F# and SpriteKit – Part 7 – DSLs baby!

So far our (1) level is fairly painful code to look at – admittedly SpriteKit and F# take something that could have been horrific and simply make it tedious. Today we change that.

DSL

According to Wikipedia a DSL is

domain-specific language (DSL) is a computer language 
specialized to a particular application domain.

The domain in question for us is modelling a level.

F#’s light syntax mode means that it is ideal for building DSLs, along with record types, discriminated unions, and list comprehensions.

When building a DSL I tend to like to think about how I would like the “language” to look. Usually I want as little noise as possible, so that it almost looks like a plain text or simple markup/markdown file. Sometimes I want to include some F# code in the body but in a boiled down minimalist way.

When I think about the level I think of it as a couple of things –

  1. A bag of sprites I will interact with
  2. A music file I will play
  3. A non-interactive background I will draw but not interact with

You could expand this to include things like level rules (i.e. lower gravity for a level set in space), but the point of a DSL is to build it to suit your own domain – the above suits me for now. The great part about an internal DSL is that as it is real code, when “for now” changes, the compiler will tell me and don’t have to go into a bunch of (text? binary??!?) files and play with the content until I fix it up.

(Diversion) DSLs and Boolean Traps

A boolean trap is a term used for a part of the code where a boolean value is passed as a parameter and the intention is not clear or is counter intuitive to the expected behaviour. Languages like C# and Java allow you to define enums, which allow more expressive behaviour, but at the expense of added code (both the definition and the consumption of the enum).

F# allows for Discriminated unions, which allow you to define a new type and consume it with no ceremony.

Example (boolean trap version):

createPhysicsBody true

Obviously it’s pretty difficult to see what the true represents. C# can do it better by using enums, but the inclusion of the enum name every time is clumsy:

enum PhysicsBodyShape = { Circle, Rectangle }
createPhysicsBody(PhysicsBodyShape.Rectangle)

F# goes above and beyond with Discriminated Unions as the definition is lightweight and the consumption is trivial – F#’s type inference has your back:

type Shape = Rectangle | Circle
createPhysicsBody Rectangle

In F# it’s really easy to avoid these boolean traps, and there’s not really a good reason not to when designing an API/DSL.

Back to the language

Taking a look at the (1st pass) DSL for levels it’s really neat to see that it fits nicely on 1 page:

 [<AutoOpen>]
 module LevelDSL

 open MonoTouch
 open MonoTouch.CoreGraphics
 open MonoTouch.SpriteKit

 // Repeat action 1 time, n times or infinitely
 type RepeatAction = Once | Times of int | Forever
 type Seconds = float
 type TextureName = string

 type Path = 
 | Ellipse of int * int * int * int //Bounding rectangle
 // TODO Other path types

 // A thing can either be at a single point or follow a path over time (n times)
 type Location = 
 | Point of int * int
 | Path of Path * Seconds * RepeatAction 

 //The Shape used for Physics
 type Shape =
 | Rectangle 
 | Circle

 //Details about the Physics
 type Physics = 
 | NoPhysics
 | Static of Shape
 | Dynamic of Shape
 | DynamicNoGravity of Shape

 //Lightweight sprite definition
 type Sprite =
 | Sprite of TextureName * Location * Physics * Sprite list

 type Level = {
     Name : string
     Level : Sprite list
     Background : Sprite list }

Now with anything, there are parts I can see already that I think could be better, for example the background (parallax) layer is made up of “Sprite”s, which means you could inadvertantly enable physics for the background – this probably isn’t desirable! As with anything there’s a cost-benefit ratio and ultimately you need to decide how important some of these things are when building a DSL. In my case I am the sole consumer of this DSL so I’ll probably let it slide for now.

Also note that we use Type Abbreviations – this is yet another way we can avoid the boolean (or in this case float and string) trap in F#!

So let’s see how using our new shiny DSL looks when recreating level 1:

let level1 = {
     Name = "Level1"
     Level = [ for i in 0..100 -> Sprite("grass", Point(i * 70, 0), Static Rectangle, []) 
               for i in 104..200 -> Sprite("grass", Point(i * 70, 0), Static Rectangle, [])
               yield 
                 Sprite("stoneMid", 
                     Path(Ellipse(50,150,200,200), 3.0, Forever), 
                     Static(Rectangle),
                     [ Sprite("stoneLeft", Point(-70,0), Static Rectangle, [])
                       Sprite("stoneRight", Point(70,0), Static Rectangle, [])])
               ]

     Background = [ for i in 0..150 -> Sprite("hill_small", Point(i * 70, 50), NoPhysics, []) ]

Now this is all done inline in the level definition – as I’m storing the levels in modules I could even go a step further by adding another mini language on top of the DSL – so my level definition ends up something something like this:

Level = [ yield! platform 0
          yield! platform 104
          yield movingEllipsePlatform 50 150 ]

Ultimately it’s up to you to figure out what works best for you. Now, given we have spent so long defining a neat DSL, it would be a shame to not use it to spruce up the level with a new fixture – some steps:

let steps xpos = 
    [ for x in 1..3 do
        for y in 1..x do
            yield Sprite("grass", Point((x+xpos)*70, y*70), Static(Rectangle), []) ]

And consuming them to add more stuff to our level:

Level = [ yield! platform 0
          yield! platform 104
          yield! steps 20
          yield! steps 97
          yield! steps 110
          yield movingEllipsePlatform 50 150
          yield movingEllipsePlatform 1000 150
          yield movingEllipsePlatform 3000 150]

Finishing off

Today we’ve taken around 50 lines of code which was highly cohesive with SpriteKit and replaced it with a small DSL which allows us to break out the intent of those 50 lines into 3 lines, whilst also decoupling the API. Creating new levels is now much easier and any future changes to the level format will be caught by the F# compiler – an advantage that external DSLs cannot match.

Next time we’ll actually add a second level and a score which we can keep track of between levels until we either die or complete the game.

All the code for today is here

Advertisements
Posted in F#, iOS | Tagged , , , | 1 Comment

A Platform game in F# and SpriteKit – Part 6 – Death

If there’s one thing we can all be certain of in life, it’s death. And so the same rule must apply to our dude. It’s been good knowing you little guy.

F# shines again

The last few posts have been back on the “How SpriteKit works”, but this time I’m firmly back in “Why F# rocks” territory.

The shining example of F# goodness? First class events (again!) and discriminated unions.

Let’s start with the latter – if you haven’t come across discriminated unions before, then you can think of them as enums on steroids. Here’s our example today –

type LevelComplete = | Died | Continue

Now this is the most basic kind of discriminated union, which doesn’t give us anything more than an enum. But later I can embellish this to do something like:

type LevelComplete = | Died of int (*Final Score*) 
                     | Continue of int * int (*Score & Lives remaining*)

In short – it allows us to classify data under the LevelComplete type and pattern match to extract extra data. If you’re new to F# the concept may be new to you (buy this book NOW)- if you’re an old hand then you probably already know more than I do.

So we now have a type – but how do we use/consume this?

Well just like how we used the tap as an exit condition for the intro screen, or a timeout on the game over screen, we can set some rules in our update. For now the rules will be simple –

If the player falls off the bottom of the screen -> Died
If the player runs a certain distance -> Continue

Here’s the code:

let levelCompleteEvt = Event<_>()
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)
    if player.Position.X > 10000.f then 
    levelCompleteEvt.Trigger Continue
    if player.Position.Y < -100.f then
    levelCompleteEvt.Trigger Died
)

As you can see we trigger an event to say what happened (new code highlighted in bold) (did I mention before first class events in F# are cool?). Then like the other async workflows we AwaitEvent on the new event (why oh why oh why was this omitted from C# async/await?).

let! levelComplete = Async.AwaitEvent levelCompleteEvt.Publish
return levelComplete

But then we return the result – this way we can control flow in that main game loop –

//Define the loop
let rec gameLoop() = async {
   do! startScreen()
   let! levelEnd = level1()
   match levelEnd with
   | Continue -> do! success()
   | Died -> do! gameOver()
   return! gameLoop()
}

Now you can see that we are able to reward the player for succeeding, and humiliate them for dying.

I’m not going to cover the awesome success() screen – you should run it an experience it’s awesomeness :). Hint: it uses SpriteKit particles, which Dave Thomas wrote about righthere.

More levels

Now I’m not going to go into too much here, other than lay some groundwork, but as a goal it would be nice to

  1. Support multiple levels
  2. If it was easy to write levels
  3. Be scalable

In my latest checkin I’ve added in some comments in the level() async workflow to highlight the level loading code (which should be changeable) and the player code (which should be the same for every level).

There are a couple of ways I can think of to handle multiple levels:

  • Have level take a higher order function and I could pass in functions to build levels (this doesn’t address #2 as every function is going to be bogged down in SpriteKit code)
  • Define an external file format (probably XML or JSON based) – this supports #1 and #2, but changes to the format are very brittle and not too scalable.
  • Define an internal DSL to define the data and a parser to turn the data into a level – I think this addresses #3 as breaking changes will force the project to not build – less chance of runtime errors or breaking changes. Once again, this plays right into F# strengths.

If anyone has a 4th suggestion, please feel free to post a comment!

So next time I’ll probably build a simple DSL to represent a level and then cover loading it in in a future post.

Code for today

All the code

Posted in F#, iOS | Tagged , , , | 1 Comment

A Platform game in F# and SpriteKit – Part 5.5 – Sound Effects

Micro-post:

Playing sound effects in SpriteKit:

//Load the sound
use jumpSound = SKAction.PlaySoundFileNamed("Jump.wav", true)
//Play the sound
scene.RunAction jumpSound

Note that the File extension is important here – unlike the graphics formats loaded into SpriteKit.

Winning!

Next Time

So far our level plays for 10 seconds and then goes to game over. Next time I’ll add success and failure criteria, and we can start to contemplate how to handle multiple levels.

Source available here and assets from here

Posted in F#, iOS, Mono, Uncategorized | Tagged , , , | 1 Comment

A Platform game in F# and SpriteKit – Part 5 – Animation and Sound

Last time we added some scrolling to out game, but our main character looks rather static. Let’s let him move like Jagger (well maybe  Cliff Richard)

Animation!

SpriteKit is clever. It’s possible to give SpriteKit a bunch of textures and it will process them into a single large texture and allow you to look up into it to get the original image out by name. This is called an Atlas.

This is going to come in handy for animation as we can preload all our frames and then cycle through them. To achieve this, firstly we need to add a folder to Resources. The name of the folder is important here – if it ends in ‘.atlas’ then the files inside will be processed into a single SKTextureAtlas.

So in the project I’ve got Player.atlas filled with 11 frames of running animation:

Files

So now it builds lets look at loading the atlas:

let playerAtlas = SKTextureAtlas.FromName "Player"
let playerAnimationTextures = playerAtlas.TextureNames.[1..playerAtlas.TextureNames.Length-1]
    |>Array.sort
    |>Array.map playerAtlas.TextureNamed

Couple of interesting points
1: When you load the atlas it’s the name of the folder minus the .atlas.

2: Note the Array slicing on line 2 – the texture at position 0 is the complete texture  so we skip that using slicing – nice!

3: We sort the textures in the atlas by name – as the files are the same prefix, but numbered we get the right order – the array of TextureNames is unordered, so without the sort the animation would look – strange…

Once we’ve loaded in we’ll make our player SpriteNode use the atlas and animate it like this:

let animation = SKAction.AnimateWithTextures(playerAnimationTextures, 0.05) 
                |> SKAction.RepeatActionForever
player.RunAction animation

Again – a little gotcha – the 2nd parameter of AnimateWithTextures is not the total run time of the animation (as it is with the other SKActions we have come across so far) – it’s the time for EACH FRAME. So we run our animation at 20fps.

IMPORTANT NOTE:

I did the above and IT DIDNT WORK (first time). In the interest of sharing knowledge and saving you good readers time I found the command line util, documented it, ran it, found how to add the results to the project so it all worked. This took me around 3 hours.

After doing all that, I discovered that what I really need to do was to REBUILD the solution, and a little message popped up in the build messages saying “Generating Texture Atlases” – and it worked like magic.

So when in doubt – REBUILD!

Now our little fella looks a bit lively. But it sure is quiet in here:

Music

Now for adding music I’m going to step away from SpriteKit for now and use AVFoundation. SpriteKit does provide some support for sound effects, but for MP3s we have to look to other Apple APIs. Luckily due to Apple’s iPod heritage handling MP3 is fairly straightforward.

In an ideal world the code to load and play an MP3 would look something like this:

let mutable error : NSError = null
use audioplayer = new AVAudioPlayer(NSUrl.FromFilename song, "mp3", &error)
audioplayer.NumberOfLoops <- -1 //Loop forever
ignore <| audioplayer.Play()

But unfortunately when you run this code you get a fraction of a second of music then it stops. This seems to come up quite often on StackOverflow. The solutions there usually refer to workarounds for ARC in objective-C. Once again F# is going to make our lives easier than those native boys.

let playSong song = 
     let mutable error : NSError = null
     let audioplayer = new AVAudioPlayer(NSUrl.FromFilename song, "mp3", &error)
     ignore <| audioplayer.Retain() //Without this line the audio immediately stops
     audioplayer.NumberOfLoops <- -1 //Loop forever
     ignore <| audioplayer.Play()
     { new IDisposable with
           member __.Dispose() = 
               audioplayer.Stop()
               audioplayer.Release() 
               audioplayer.Dispose()}

The key parts here:
1: The Retain call ensures that the AVAudioPlayer is not automatically released.
2: We return an IDisposable which is an object expression to handle resource de-allocation.

So to consume this new method we simply:

use song = playSong "Level1.mp3"

Now when we finish up in the level async workflow, dispose is called and cleans up automatically.

Finishing off

Today we’ve got our dude looking a bit more lively and made his world a little a little nicer with some funky music (all once again thanks to open.commonly.cc). I personally struggled to get what should have been easy working, but hopefully my pain is your gain.

As always – complete source is here and the code from today is here.

Next time I’ll continue giving you aural pleasure by adding some sound effects.

Posted in F#, iOS | Tagged , , , | 1 Comment

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.

Posted in F#, iOS | Tagged , , , , | 1 Comment

A Platform game in SpriteKit and F# – Part 3 – A Jumping dude

I know you can't tell, but he really is jumping!

Today’s post is going to be a short one – I’m going to add a dude who we can make jump.

Before I go ahead and do that it’s important to add some physical properties to allow our player to land on – otherwise he’ll simply fall through the scenery!

So first lets set the following properties on all our existing bits of the level:

sprite.PhysicsBody <- SKPhysicsBody.BodyWithRectangleOfSize sprite.Size
sprite.PhysicsBody.AffectedByGravity <- false
sprite.PhysicsBody.Dynamic <- false<

And via a really quick refactor I can put all that into a single function and then replace all my “new SKSpriteNode” calls with the function. So

use grass = new SKSpriteNode("grass")

goes to

let createLevelSprite (name:string) = 
   let sprite = new SKSpriteNode(name)
   sprite.PhysicsBody <- SKPhysicsBody.BodyWithRectangleOfSize sprite.Size
   sprite.PhysicsBody.AffectedByGravity <- false
   sprite.PhysicsBody.Dynamic <- false
   sprite
use grass = createLevelSprite "grass"

Adding a player

Firstly here’s the code to add the player:

 //Add a player, with physics which are affected by gravity and are dynamic
 use player = new SKSpriteNode("player")
 player.PhysicsBody <- SKPhysicsBody.BodyWithRectangleOfSize player.Size
 player.PhysicsBody.AffectedByGravity <- true
 player.PhysicsBody.AllowsRotation <- false
 player.PhysicsBody.Dynamic <- true
 player.Position <- PointF(320.f,100.f)
 scene.AddChild player

The interesting points are that

  1. We aren’t allowing rotation
  2. We are letting the player be dynamic (for now at least)

When we run this we have a little dude onscreen (once again from the Kenney game in the open.commonly.cc asset bundle).

To add control (and I heartily recommend you read and digest this post by Dave Thomas for a more complete view as to what is going on) we are simply going to allow an upwards swipe to apply an impulse to the player character. I’m not adding a more complex system in (yet) as I just want to demonstrate input and get us onto the next post which will add even more movement.

let swipeUp = new UISwipeGestureRecognizer(Direction=UISwipeGestureRecognizerDirection.Up)
swipeUp.AddTarget (fun () -> 
    if swipeUp.State = UIGestureRecognizerState.Ended && player.PhysicsBody.Velocity.dy = 0.f then
        player.PhysicsBody.ApplyImpulse (CGVector(0.0f, 200.f))) |> ignore

x.View.AddGestureRecognizer swipeUp

Let’s break this down a little as I lied (a little) when I said “Simply”:
The 1st line determines that we are adding a swipe for recognizing the up swipe.
The 2nd line adds function to be called when the up swipe happens.
Line 3 says – when the swipe is complete AND when the player’s Y velocity is 0 (for example when they are not falling) then
Line 4 – apply an upwards force
Line 6 – add the recognizer to the view – without this the previous 4 lines don’t do anything.

So line 3 checks that we’re not falling so that we only can jump from the ground. Without this check we’d be able to jump mid-air and that’s just CRAZY!

So there you have it – a jumping dude who can land on the floor and the moving platform if timed correctly.

Code – as always at Github with the specific changes in this file.

Next time

I’m going to make this little guy run left to right and scroll with him in our 1st big change to the structure of the code (and by big I mean really pretty small as we’re only up to around 150 LOC so far…).

Posted in F#, iOS | Tagged , , , | 1 Comment

A Platform game in SpriteKit and F# – Part 2 – Start building a level

Today’s post is going to be fairly short and sweet. I’m going to start filling out the level1 method, by making the 1st step of drawing the basics of a level.

At the end of this post there will be

  1. A floor
  2. A moving platform

There wont be

  1. Scrolling
  2. Interaction

The graphics used for this come from Kenney in the open.commonly.cc bundle.

Let’s begin

The floor is simply added by repeatedly adding “grass” to the scene.

 //Pop in some floor
 for i in 0..10 do 
    use grass = new SKSpriteNode("grass")
    grass.Position <- PointF(float32 i * grass.Size.Width, 0.f)
    scene.AddChild grass

Hopefully this looks like fairly familiar territory and nothing earth-shattering. Note at the moment I’m not even going to set the physics properties of anything – nothing interacts yet, so there’s really no point!

Where SpriteKit begins to get a little more interesting (and something I haven’t really talked about yet) is that SpriteKit represents the scene hierarchically. The term Node in SpriteNode and LabelNode aren’t there simply to make us type more. You can add children to a node, and by moving the parent it will affect the children.

Let’s put this into practice by adding a platform

 //Lets create a moving platform from 3 connected sprites
 use platformLeft = new SKSpriteNode("stoneLeft")
 use platformCenter = new SKSpriteNode("stoneMid")
 use platformRight = new SKSpriteNode("stoneRight")
 //Position the left and right **relative** to the center one
 platformLeft.Position <- PointF(-platformLeft.Size.Width, 0.0f)
 platformRight.Position <- PointF(platformRight.Size.Width, 0.0f)
 //Add them as children of the center sprite
 platformCenter.AddChild platformLeft
 platformCenter.AddChild platformRight
 //Add the center sprite to the scene (this adds all 3)
 scene.AddChild platformCenter

Notice that when we add platformLeft and platformRight that we offset by the width of the sprite, but no the height – this is so the sides are to the left and right – relatively they are on the same Y-Axis so the position for Y is 0.

Now a stationary platform is pretty dull and Super Mario had lots of moving platforms (and people seem to like Mario), so lets move this platform in a big circle.

 //Next lets define a path that the platform will follow - like Super Mario World 
 let path = CGPath.EllipseFromRect(RectangleF(50.f,150.f,200.f,200.f), CGAffineTransform.MakeIdentity())
 let movePlatform = SKAction.FollowPath(path, false, false, 5.0)|>SKAction.RepeatActionForever
 platformCenter.RunAction movePlatform

Once again SpriteKit’s built in SKAction helps take something that could have been a painful task and turned it into 3 lines – define a path, create an SKAction from the path and then run the action. It’s so simple and yet so powerful.

Wrapping up

I told you this post would be short! So today we’ve added the start of a level. As there’s nothing to interact with there’s little to do, but in only a few lines we’ve managed to create a scene with some animation which we can use as a basis for building more on later.

Here’s a screenshot for those without a Mac and Xamarin License.

photo

Something you may notice from the code which is slightly unusual. The Y coordinate is the inverse of most 2D systems. 0 is at the bottom and n is at the top, whereas usually 0 is the top.

The code for this post is available here

Next time I’ll add in a character that can interact with the level to spice things up……

Posted in F#, iOS | Tagged , , , | 1 Comment