Frog Crossing
A one-tap arcade game about crossing a road that really does not want you to.
Inspiration
I wanted to know why a game from 1981 still makes my hands sweat. So I played the original for an afternoon, and I think the answer is that it isn't nostalgia, it's that the safe ground moves. On the road, standing still saves you. One hop north, in the water, standing still kills you, and the only footing is a log that's already carrying you toward the edge of the screen. You have to flip your whole idea of "safe" halfway through every crossing.
That's the game. Everything else I built was to protect that one feeling.
How I built it
Flutter and Flame. Flutter for the menus, store, collection and settings, Flame for the board itself. 72,590 lines of Dart, 231 tests, 127 commits between June and August.
The decision I'm happiest about is that the rules don't know what anything looks
like. Every row on the board declares a LaneFunction (safeZone, traffic,
deadlyBand, goal) and survival is one switch over that enum. Traffic kills
on overlap. A deadly band kills unless you're standing on a platform, and while
you are, you drift with it. The goal row is solid wall except at the home bays.
That's the whole ruleset. Twelve worlds run on it because not one of them is a
special case.
What I learned
A green build proves nothing. My release APK crashed on launch while every debug build was fine. AdMob pulled in WorkManager, which pulled in Room, and R8 stripped the classes Room looks up by reflection. Now I install the real signed artifact on a real phone before I believe anything.
Profile the long session, not the first minute. Frames fell off a cliff about four minutes into a run, because I was playing every sound effect through a fresh audio player, which meant a fresh decoder, until the OS quietly stopped handing them out. No 30 second test was ever going to catch that.
Stored data outlives your code. The tutorial records which hints you've seen using the enum value's name, so renaming a case isn't a refactor, it re-teaches the tutorial to everyone who already plays. I caught that one by thinking instead of by shipping, which felt like getting away with something.
Challenges
Google Play caps a bundle at 200 MB and mine was 311 MB of art. I dropped the 3x asset tier, moved every sprite to WebP and re-encoded the audio to get down to 181.5 MB. Deciding which quality to give up, alone, at 1am, is not a fun engineering problem.
Audio worked perfectly on the phone speaker and was completely silent over
Bluetooth headphones. Hours of bisecting, for one enum: an audio focus mode of
none.
The worst one was self-inflicted. Ripping out the old difficulty model after the game was already playable meant retuning every level in the campaign. It was the right call and I resented every hour of it.
What's next
Marketing and creating awareness about the game to get feedback from real users
Built With
- dart
- flame
- flutter
- revenuecat
Log in or sign up for Devpost to join the conversation.