In this article, I take a look at the development of Floe through the history of a single level from the game. A finished game, with smooth gameplay and polished graphics, gives little evidence of the many twists and turns along the path of development. Here, in twenty-four screenshots of level 24, I show some of the trials, mistakes, and modest triumphs from the development of Floe.
On the first afternoon of the project, Floe was called “Slidy” and looked like this.
It was text only, but fully interactive (the command s meant “slide the blocks to the south”) and nearly all the gameplay was already present. You could move the @ sign around, slide blocks in four directions, and freeze and unfreeze them.
(If you’ve ever played a roguelike, you’ll recognize the presentation.)
Some games start with settings, some with stories, and some with characters, but this one started with pure gameplay. At this stage I had no idea what setting these blocks would eventually inhabit, or what kind of character would navigate them.
Although it’s now level 24 in Floe, this was the first level I implemented, and it was the level that convinced me that I would be able to make interesting and challenging puzzles.
The first implementation in Unity 3D, running on Mac OS X. I used built-in Unity models (spheres, cubes and cylinders) and built-in wood and stone textures. The player character became a pink and white beach-ball.
Arrow keys made the blocks slide, and you could drag the beach-ball with the mouse.
This was my first experience of working with Unity 3D, and initially I wasn’t at all sure about how to go about developing the implementation. At first I tried to use Unity’s built-in physics engine to handle block movement, friction, collisions and so on. But I couldn’t make the physics reproduce all the constraints of the puzzle, so I just programmed it all explicitly.
The first iPhone version. This elegant design and colour scheme were sketched out by Ed Sludden.
Tilting the iPhone made the blocks slide, you could drag the beach-ball around with your finger, and you could freeze or unfreeze a block by touching it.
Here’s a character model from Ed. Is she a mouse or a bear?
The black block is frozen: the blackness is a placeholder waiting for a proper ice texture.
In the early versions of Floe, I had tutorial text that explained what you had to do in the game. But hardly anyone reads tutorials, so I tried to make as much of the game as possible self-explanatory. Originally there was an instruction telling you to head for the exit, but it was simpler to put an arrow there and let the player figure it out. Later on, it became apparent that even the arrow was unnecessary: the mere presence of an exit was enough to suggest to players that they should go there.
A point light gave a bit of variation over the level. (At this point in development, I didn’t realise that the iPhone has no hardware support for point lights, so Unity’s implementation draws all triangles twice, with unfortunate consequences for framerate.)
After some experience of dragging Flo around with my finger, it became clear that there was a big problem with this control scheme: my finger was always on top of Flo, so I couldn’t see her. How are you supposed to relate to a cute character if you can’t see her because your finger is in the way?
I solved this by waiting until the finger is lifted before starting to move Flo. While your finger is touching the screen, a cursor (the red circle) shows which cell you’re touching, and a line shows the path that Flo will follow. This control scheme has lots of other advantages:
- You can see what action you’ll take before it happens. This reduces inadvertent errors due to misplaced fingers.
- You can cancel an action if you didn’t like it, by dragging your finger off the edge of the playing area.
- The cursor is large, so you could see some of it around your fingertip.
- The navigation is done for you: Floe is a game about solving the combinatorial puzzles with the blocks, not about navigating fiddly mazes.
Turning the board around so that Flo starts at the top meant that the path is (most of the time) above your finger on the screen, and so visible, instead of below your finger, and so hidden by your hand.
Some water made the playing area look more like an ice floe, using one of Unity’s standard water implementations. This shader looks great on the Mac, but falls back to the very basic approach shown here on the iPhone.
The blocks around the edge of the floe play little role in the game, so I shrank them to make them less distracting.
Also, a pause button.
Flo now had feet, but she had become rather dark.
A new camera position shows water all around the floe, to give more of a sense of place.
There were new textures for the pause button and the exit arrow.
This screenshot shows some minor improvements: better lighting for Flo, block textures, frozen block texture, and an improved cursor. (It was still not big enough for players with big fingers, though. This was something that would become a bit of a theme during development, as we kept finding playtesters with even bigger fingers.)
Instead of a simple line, I drew footsteps to show the path Flo is going to take. This makes it much clearer that the line indicates a path that Flo would walk along.
These footsteps were fiddly to get right. Flo takes a path that zigzags from square to orthogonally adjacent square, but it looks inelegant if the footsteps followed this zigzag path. It looks much better if the footsteps curve smoothly, so I used a quadratic spline with control points at the centres of the squares that Flo visits. The locations of the footprints along this curvy path have to be carefully handled so as to avoid a “marching ants” effect when you drag the cursor around. Footsteps have to be added or removed only at the end of the path, while footsteps near the beginning of the path have to remain fixed, or nearly so.
The camera position shown here was a breakthrough for us. It was suggested by one of Ed’s sketches, and makes an enormous difference to the appeal of the game: you can see Flo’s face, which means that she will be able to have expressions and emotions.
Of course this created some difficulties: it became trickier to determine the player’s intent when they touch the screen (do they intend to move Flo or freeze a block?), because the blocks now obscure part of the floor behind them.
The floe surround was starting to look good, though you can still see seams where the pieces abut.
A new water implementation made waves by moving the vertices of the mesh up and down.
Someone turned up the lights!
New textures for the floe boundaries removed the seams and gave more of a cartoony feel.
This screenshot shows a move count, a bigger cursor (though still not big enough!) and Flo turning to look at the cursor.
This model for Flo was much more appealing. Big heads provide more room for expressions.
The boundary went all the way around the floe, but you can see a draw order problem where the footprints meet the entrance to the level.
The draw order was fixed, and the cursor was animated.
It was necessary to visually distinguish the pause button (which was pressable) from the move count (purely informational).
I made the cursor even bigger.
Every puzzle game that’s hard enough to be interesting and challenging runs the risk of having puzzles that are too hard for some players. I didn’t want those players to give up in frustration, since there are probably later levels that they could enjoy. So there needed to be some way to skip levels for now and come back to them later.
It’s common to have some kind of unlocking scheme whereby each time you complete a level you typically unlock more than one other puzzle. (Some examples. Tumbledrop tries to keep five levels unlocked but not completed: you start each section with five levels unlocked, and each time you complete a level another is unlocked if possible. In Colorbind the levels are set out in a grid, and completing a level unlocks both the level to the right and the level below.)
But in Floe’s less abstract setting I wanted to have an in-world mechanism for skipping levels. So the pink-and-white capsule that appeared in this screenshot was a token that Flo could collect, and which you could use to skip a level that you found too hard.
At this point I had no idea what it would be (maybe a magic wand of some kind?) but I knew how it had to work.
Ed suggested that the level-skipping token should be a balloon, and Richard suggested that you should be able to use it to float over the level.
I struggled with how to represent the tilt. For a while I kept the ice floe stationary, as if was glued to the iPhone, and tilted the water in the opposite direction.
In this screenshot you can see that I reversed this: the floe now tilted on screen when you tilted the iPhone! In some ways this doesn’t make sense: you are already tilting the phone, so why should the floe tilt further on screen? But it makes the game much more playable, because you can get continuous visual feedback as to when the blocks will start to slide. Previously players had the perception that the game was unfair or capricious because they would find that blocks occasionally slid when they hadn’t intended them to.
Flo now cast a shadow.
The UNDO button appeared for the first time. Lots of play-testers asked for this, and I thought it would be easy to implement, since I had already written a level serializer and deserializer in order to save and restore the game. (In fact it caused a lot of trouble, since my initial implementation destroyed and recreated the level objects, which generated a lot of garbage and in some cases caused out-of-memory crashes. Eventually I had to rewrite it to reposition the existing blocks instead of destroying and recreating them.)
At about this point I started trying to improve the framerate, which had dropped to an abysmal 13 frames per second on my iPhone 3GS. The most obvious culprit was the point light, which was doubling the number of triangles to be rendered. So out it had to come.
More framerate improvements: I merged the meshes for the floe boundary objects, and reimplemented the cursor as a particle system. (These changes saved draw calls, which are surprisingly expensive.)
You can see some seams around the corner blocks. That’s because the UV coordinates on the model ran all the way to 0 and 1 at the edges, which was OK when the model was drawn by itself (because UV clamping ensure the edge pixels got the right colour) but not when the model’s texture was combined with other models to make a “texture atlas” (UVs of 0 or 1 got bleed from adjacent textures in the atlas).
Blocks now gave off clouds of ice when they collided, and when you froze or unfroze them. These clouds were implemented using Unity’s “mesh particle emitter”, which emitted particles randomly from the triangles of the mesh. Since the blocks were chamfered (rounded off at the corners and edges), the triangles were concentrated around the corners of the cubes, and hence so were the particles.
An adjusted camera position prevented Flo’s head from being cut off by buttons on larger levels.
Yet another water implementation, this time using a spheremap to reflect a sky texture. The spheremap implementation on the iPhone is very basic: it uses the normal at each pixel to look up a corresponding texel in the spheremap (on a more sophisticated graphics card one would use the angle between the normal and the camera to look up the texel). So this only gives a shiny effect on rounded surfaces: I tried using this shader on the floor of the floe, but it didn’t look right at all.
With this water implementation, I could adjust the normal vectors at each vertex each frame to make the sky reflections move around. This made quite a realistic effect using only a single shader pass.
There were sparkles too, applying a mesh particle emitter to the water mesh.
Ed was never happy with the lighting that I was able to implement on the iPhone. So I turned it off completely for Flo: now you’re seeing the lighting baked in to the textures using 3DS Max.
By using a different mesh (a simple 12-triangle cube) for the particle emitter, ice particles were now generated evenly over the surface of the blocks.
In this screenshot, Flo shows off her dangling-from-a-balloon animation, and an improved balloon model and shader.
The realistic water was distracting, and discordant with the cartoony graphical style of the rest of the game. So we replaced it with this cartoon water, based on a sketch by Ed. Animating the UVs of the water mesh creates ripples around the floe.
The buttons had become rather numerous, but it’s hard to see what we could do without. The RESET button used to be on the menu, but play-testers failed to find it there when they wanted it, and ended up pressing UNDO many times. I used to only allow players to use the SKIP button on levels that they had not yet completed. But it seemed less arbitrary and more fun to allow them to use it whenever they have a balloon to hand.
We liked the new water but everything was looking blue, so Ed drew some white buttons to vary the colour palette a little.
And that’s the history of level 24! I hope you enjoyed playing it as much as I enjoyed making it.