Game Sprint 3: FLOP
June 29, 2025
I've been watching Devil's Plan, a Korean game show where contestants battle each other in new games each episode. As a game designer, I have the unique privilege of calling this research.
The show is full of brilliantly designed games that are simple to understand but leave infinite room for strategy. As someone whose favourite genre is puzzle games that start incredibly simple and introduce complexity and strategy over time (see: The Witness, Cut the Rope), letting players discover the depths of the games for themselves.
I didn't aim to create a worthy peer to The Witness in two weeks, but I did want to build a puzzle game that's easy to understand but gets interesting quickly, and maybe seeing all the mancala beads and go stones on Devil's Plan made me want to follow in those aesthetic footsteps.
The concept was simple: flip all the tiles over to win. After adding simple rules that reveal themselves to players over time, that simple, tactile concept developed into FLOP, a delightful little puzzle game.
As puzzle games are my favourite genre, I really wanted to do this concept justice by fleshing out the mechanics and building a swathe of engaging puzzles.
I started as I usually do when designing puzzle games: on paper.
This allowed me to experience the game at its simplest and rapidly prototype new mechanics — which was great, up until I'd redrawn a grid of tiles for the thirtieth time. This lead me to my second physical prototype for puzzle designing: 3D printed tokens.
Playing with physical tokens was fun enough on its own that I'm considering a print-and-play board game for a future Game Sprint — within the bounds of this project as itch.io accepts analog games.
Still, you may be wondering: Why wouldn't I just move to designing puzzles in the game engine at this point?
And you'd be right to. Unfortunately, thanks to a poorly timed bout of flu, I spent the first week exclusively playing with paper and plastic tokens instead of in front of my computer screen. When I finally opened Godot and threw together the core gameplay loop, solving the puzzles felt magical.
Last Sprint, I made a 3D game. I must have been nostalgic for the leg-melting CPU temperatures and brain-numbing compile times of Unity, because, in an effort to recreate to go stone aesthetic I was heading toward, I opened Blender for the first time in years to make normal maps for every frame of my token flip animation.
This added a lot to the tactile experience of the game, and was quite easy after figuring out Blender's MatCap lighting system has a surface normals texture.
If you're working in Godot and want to add normals to the frames of an AnimatedSprite, you might be confused by the lack of info online. I thought I might have to stop using an AnimatedSprite altogether, but I figured out that SpriteFrames can generate frames from any texture file (not just images). All you have to do is create a CanvasTexture resource, add your sprite sheet to the diffuse texture and your normal map sheet to the normal map texture, and use that texture to generate your frames. As a bonus, you can adjust things like the specular as well.
Coming back from Unity, there was one thing (besides the ECS paradigm) I really missed — the audio manager I made to manage music and sfx. So when it came time to add sound to FLOP, I built a very similar system with the following as an autoload:
@export_dir var sfx_directory
@export_file var bg_music
@export_range(0, 1) var bg_intensity: float
@export var mute_sfx_with_music: bool = false
@onready var bg_music_player: AudioStreamPlayer = addAudioStreamPlayer(bg_music)
var players: Dictionary[StringName, AudioStreamPlayer]
var muted: bool = false
func _ready():
bg_music_player.volume_linear = bg_intensity
bg_music_player.play()
bg_music_player.finished.connect(bg_music_player.play)
var dir = DirAccess.open(sfx_directory)
if dir:
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name != "":
if dir.current_is_dir():
print("Found directory: " + file_name)
elif file_name.get_extension() == "import":
addAudioStreamPlayer(sfx_directory
+ "/"
+ file_name.replace(".import", ""))
print("Found file: " + file_name)
file_name = dir.get_next()
else:
print("An error occurred when trying to access the path.")
func addAudioStreamPlayer(file_path: String) -> AudioStreamPlayer:
var player = AudioStreamPlayer.new()
player.stream = load(file_path)
player.max_polyphony = 6
players[file_path.get_file().split(".")[0]] = player
add_child(player)
return player
func toggle_mute() -> void:
muted = !muted
bg_music_player.volume_linear = 0 if muted else bg_intensity
func play(name: StringName, intensity: float = 1.0, delay: float = 0) -> void:
if muted and mute_sfx_with_music:
return
var player = players.get(name) as AudioStreamPlayer
if player:
await get_tree().create_timer(delay).timeout
player.volume_linear = intensity
player.play()
This made adding sounds to everything in the game incredibly simple, and I look forward to plugging it into my future projects. Feel free to use it if you've been looking for something similar. I know how annoying adding an AudioStreamPlayer to every sound-producing node in your game can be! To use it, just add it to an autoload scene, then call [autoload name].play(&"[sfx file name]", [intensity], [delay])
. The &
before the name is to use a StringName, which makes lookup marginally faster.
The core concept of the game, flipping over tiles until they're all upside down, is something I'd seen a simplified version of in a few puzzle games here and there — usually with switches in a line — but I'm surprised it's never been fleshed out into a full game. With new mechanics and engaging puzzles, FLOP is intuitive to understand but has room for infinite puzzle complexity.
There are still tons of mechanics to explore with this puzzle concept (like blockers, moving tiles, and many other flipping behaviours), but I'm very proud of the 20 puzzles I made for FLOP and can't wait to take my learning forward into my next Game Sprint!
I'm excited to hear what you think about FLOP!
See you in two weeks for my next Game Sprint game: Catching Wind.