Building Fart Blaster Man

Some projects start with a business plan. Mine started with a question: what if a man could blast himself to the moon using nothing but beans and determination?

Thus was born Fart Blaster Man — a vertical endless-climber built with libGDX where you aim your, ahem, propulsion system with WASD (or a touch joystick), collect beans for fuel, dodge satellite debris, and climb from the city streets all the way to the lunar surface. Two weeks later, it runs on desktop, in the browser, on iOS, and inside a Reddit post. Here's how it came together.

Week One: Learning to Fly

The first big decision was also the most liberating one: I skipped Box2D entirely. The libGDX template ships with a full physics engine, but an endless climber doesn't need rigid-body dynamics — it needs a character that feels right. So I wrote a small custom kinematic physics layer: an integrator, a fuel model, and collision/bounce helpers, all as pure static methods.

The camera got its own personality: it ratchets. It follows you up but never scrolls down, which quietly turns gravity into the villain.

Then came the fun escalation, one commit at a time:

  • Beans and platforms, spawned by altitude intervals
  • Rest ledges you can actually land on and walk along, with a directional standing pose and auto foot-alignment (surprisingly fiddly — matching a rocket-flight sprite's height to a standing sprite's feet took multiple attempts)
  • Satellite debris once you leave the atmosphere — lethal, exploding, and speed-scaled by altitude
  • A health system, landing bonuses, and healing mechanics
  • Fuel pressure mechanics with quadratic drag and a low-fuel "sputter" — because running out of gas should feel like running out of gas

The Web Called, and It Had Opinions

Getting the game into the browser via gdx-teavm (TeaVM compiles Java bytecode to JavaScript) was the moment the project grew its most important constraint: the core module must compile with --release 8. No Java 9+ anything. Every modern-Java instinct — List.of(), var, records — had to be politely suppressed. The desktop launcher gets to enjoy Java 25; the game logic lives in 2014. It's a strange kind of time travel, and it works.

The web build also taught me not to trust abstractions blindly. libGDX has a nice isPeripheralAvailable(MultitouchScreen) API for detecting touch devices. The TeaVM backend stubs it to always return false. So I detect touch in the browser myself and let each platform launcher declare its own capabilities. Lesson learned: cross-platform frameworks are 95% magic and 5% "check the stub implementations."

Touch Controls and the iPhone Gauntlet

Mobile got a proper design spec before a line of code (a habit that paid off all project long — the boss fight got one too). The result: a translucent floating joystick that appears where you touch, feeding the exact same platform-agnostic input frame the keyboard produces. The game logic never knows or cares which one it's talking to.

Then iOS, via RoboVM, delivered the week's best trivia:

  1. My success jingle was silent on iOS Safari until I converted it to MP3.
  2. RoboVM's Gradle plugin demands JDK 21, while the rest of the build lives elsewhere — so there's now a wrapper script that temporarily swaps the Gradle daemon's JVM and politely puts it back afterward.
  3. The iPhone's physical silent switch mutes Web Audio entirely — music and effects. Not a bug. Just a tiny hardware switch capable of gaslighting you for an afternoon.

Week Two: To the Moon — Literally

With the platform work settled, the climb got a destination. The Moon Phase turned the background into an altitude-staged journey: city map segments → repeating space debris field → a three-screen moon approach → a single dramatic orbit screen → a procedurally tiled lunar landscape (a little hash function picks the tiles, so it never visibly repeats). Bean spawns and hazards adapt per stage, and the moon-surface transition fades in with dynamic alpha.

Then the hero got a weapon. The fart blast firing mechanic — spec'd first, naturally — let you shoot back. And once you can shoot back, you need something worth shooting at.

Enter the Air Freshener Baron

The finale is a proper boss fight against Fart Blaster Man's natural enemy: an Air Freshener Baron who locks the camera into an arena, strafes overhead, drops falling pine-tree fresheners (yes, the car kind), and sprays deodorant mist zones that debuff your thrust — an elegantly cruel move in a game where thrust is your entire identity.

Under the hood it's the tidiest system in the codebase: a state machine with punish-window damage gating (you can only hurt him when he's overheated and vulnerable), a boss-mode orchestrator that suppresses normal spawning and manages fuel/health refills so the fight stays fair, and custom sounds for the spray hiss, the overheat, and the extremely satisfying boss death. Beat him and you get a genuine win screen — an endless climber with an ending, which feels like getting away with something.

Epilogue: Fart Blaster Man Goes to Reddit

The latest chapter: packaging the whole game as a Devvit web app, so it runs inside a Reddit post. Reddit's webview enforces a strict Content Security Policy — no inline scripts, no inline event handlers — so the entrypoint HTML is hand-authored and a small TypeScript bridge module boots the game and syncs high scores. One Gradle task builds the TeaVM bundle and drops it straight into the Devvit app's public/ folder.

What I'd Tell Past Me

  • Write the physics yourself when the game is simple enough. You'll understand every frame of motion, and you can unit-test all of it.
  • Pure, GL-free game logic is the cheapest testing infrastructure you'll ever build.
  • Spec before feature scaled beautifully — touch controls, iOS, the firing mechanic, and the boss all got design docs first, and all landed clean.
  • Every platform will surprise you exactly once. Budget for it.

Not bad for two weeks and a man powered by beans.

You can currently play Fart Blaster Man on Reddit or on Itch.io