CrazyMoles
CrazyMoles is a memory-based whack-a-mole game with rhythm elements. Players must hit all 20 unique moles as they appear in time with the music, avoiding repeats, since previously hit moles reappear as puppet versions. Hitting a puppet three times ends the game, and failing to hit all moles before the song ends also results in a loss.
This is my first game made with Godot, so Iām by no means an expert. There are likely some mistakes in how I implemented certain systems, but Iām always learning and improving my approach.
__mobile Since youāre viewing this on a mobile device, I canāt provide a playable web demo here, but here is a full gameplay video showcasing all the main features. If you're interested in trying the game yourself, feel free to revisit this page from a desktop browser.
__pc Here is a full gameplay video, but you can also try it yourself as I made a web build just for this portfolio. Please note that minor audio looping issues may occur in the browser version, but these do not affect the gameplay experience.
Implementation Details
Moles
Entity Architecture
Each mole in CrazyMoles is an instanced scene containing its sprites, particles, sounds, animation logic, and hit detection. Each instance maintains its own state, including position, speed, mole skin, and hit status.
At the end of the day, each mole is basically a group of sprites behind a mask, with some extra sprites layered in front and behind.

Animation System
To animate the moles popping in and out, I controlled their vertical position using the
offset
property of aSprite2D
. A variable calledshow_offset
defines the maximum displacement on the Y-axis when the mole is fully visible. Another variable,show_percent
(ranging from 0 to 1), acts as a coefficient for alerp
between 0 andshow_offset
, determining how far the mole is currently out of its hole.Each frame,
show_percent
is incremented or decremented depending on the moleās state: ifshow_state
is true, it increases byshow_speed
; otherwise, it decreases byhide_speed
. The interpolated result is applied to the moleāsoffset.y
.To make the animation feel more organic, I added two curves,
show_curve
andhide_curve
. These take the currentshow_percent
value and apply it to the moleāsscale.y
, producing a squash-and-stretch effect that makes the motion more dynamic.

Hit System
The hit system is an extension of the existing pop-up animation. When a mole is clicked, a series of conditional checks determines if the hit is valid. If so, the touched
flag is activated, causing show_percent
to decrease at a separate speed (touched_speed
) for a linear downward movement.
No animation curves are applied in this case. Additionally, the moleās sprite is swapped to its 'hit' version, and a particle effect and small shake are triggered to visually reinforce the impact.

Skin System
Each mole has a Sprite2D
node containing an atlas with
all mole designs arranged in a grid. Each row corresponds to a
different mole, and each column represents a specific state: 0 =
normal, 1 = puppet, 2 = hit.
When selecting which mole appears, the Animation
properties of the Sprite2D
node are used:
- Y-index selects the mole.
- X-index sets the current state.


Public API and Usage
Moles provide a set of functions that let the rest of the game control their behavior. These functions allow external systems to show, hide, or manipulate moles without accessing their internal state directly.
-
show_mole(mole_index_: int, show_t: float, show_s: float, hide_s: float, delay_: float)
Shows a mole for a fixed duration, then hides it. Parameters allow controlling which skin to use, how fast it appears, how fast it hides, and an optional delay before showing.
Parameters:mole_index_:
mole skin to display.show_t:
time the mole stays visible.show_s:
speed at which the mole pops up.hide_s:
speed at which the mole retreats.delay_:
optional delay before the mole appears.
-
show_mole_no_hide(mole_index_: int, speed: float)
Shows a mole without automatically hiding it. If another mole is visible, it is first hidden. Useful for persistent displays such as previews or menus.
Parameters:mole_index_:
selects which mole skin to display.speed:
speed at which the mole pops up.
-
show_mole_no_hide_next(speed: float)
Shows the next mole skin from the atlas without automatically hiding it. If another mole is visible, it is first hidden. Useful for persistent displays such as previews or menus.
Parameters:speed:
speed at which the mole pops up.
-
show_mole_no_hide_prev(speed: float)
Shows the previous mole skin from the atlas without automatically hiding it. If another mole is visible, it is first hidden. Useful for persistent displays such as previews or menus.
Parameters:speed:
speed at which the mole pops up.
-
hide_mole(speed: float, hide_delay: float = 0)
Hides the currently visible mole.
Parameters:speed:
speed at which the mole goes down.hide_delay:
optional delay before hiding begins (default = 0).
Designing Rhythm Patterns
Designing the mole appearance patterns was one of the most
challenging aspects of the project.
To determine the exact moments when moles should appear in sync with
the music, I used Audacityās label system:
- Main song placed on the top track for visual inspection of the audio waveform.
- Secondary track contained short hits at key moments to verify the beat aurally.
- Labels were added at the same points, with content formatted as
JSON containing parameters for the
show_mole
function. - Labels are then exported and parsed in Godot to trigger mole appearances according to the songās playback time.


This approach ensured mole appearances matched the song's rhythm. However, designing the actual patterns, deciding which moles appear, their skins, and where they pop up, is still tricky, as editing labels in Audacity or the exported file is tedious and error-prone.
To simplify this, I created a small Python script that parses the labels into JSON and then back into a .txt
format. This allows me to conveniently edit mole sequences without having to modify the Godot code when importing them.
You can download it here. Itās a simple, unpolished tool made to speed up editing mole sequences.

Cursor Implementation
The game uses two cursors:
- A pointing hand for menus, with two sprites (pressed/released).
- A snapping hand for gameplay, with three sprites that animate on
click.
Cursor state is managed by cursor_controller
, which
checks the global game state (gameplay, pause, end menu, main menu)
and selects the appropriate cursor and sprite. On desktop, the native
Godot cursor system is used. On web, where cursor handling is
unreliable, the controller bridges to JavaScript: cursor sprites are
encoded in Base64 and assigned through a custom JS function.

Note: This project page is still a work in progress. More details and explanations about CrazyMoles will be added soon.