Sinete: a 2-player bluffing card game in Godot 4.6, and what I learned making it (looking for Android testers)

I’m Rapha, a solo dev from Brazil. Sinete is a 2-player bluffing card game made in Godot 4.6, and it’s in closed testing on Google Play right now. I’m looking for Android testers. Before the link, here are a few things Godot taught me while making it.

The game

Two brothers split a dead king’s estate, and each noble sides with whoever hands over more of his land. The key move is the offer. You show 3 deeds, your brother takes 1 and you keep the other 2. Pick the wrong 3 and you’ve just paid for his best noble. You can play the computer, pass the phone around, or play online at your own pace. A match takes under 10 minutes. No ads, nothing to buy.

Answering an offer in Sinete

What Godot taught me

The whole UI is built in code, no scenes from the editor. I can review a screen by reading one file, and the headless tests can build every screen and play full matches with simulated taps.

Scripts run with -s don’t see autoloads. All my tooling broke on that, so Settings and the save store became static classes instead.

My random-match test passed while the game was broken. A function would hit an error, Godot would abort it, and the run still exited green. Now every headless tool listens to the engine log, and any script error or push_error fails the run.

A lambda that captures a node dies with that node. My card animations kept breaking until I switched to Callable.bind() on methods of the screen.

In 4.6 a Label with autowrap and clip_text inside a container can come out 1 px tall, and the text just disappears. size_flags_vertical = SIZE_FILL fixes it.

The strongest AI level needs up to a second per move on my PC, so it thinks on a Thread. That only works because the AI code is pure. Any shared mutable static state would turn into a race.

Online play is server-authoritative, because in a game that’s mostly hidden information the client can’t hold the full state. The rules engine exists twice, in GDScript and in TypeScript on Supabase, and a JSON test corpus runs on both in CI. I also dropped Godot’s RandomNumberGenerator for a tiny xorshift32, so the server can deal the exact same cards from the same seed.

Joining the test

Fill in the form with the email of the Google account on your phone. I add you to the list and send the Play Store link. Google wants testers to stay 14 days in a row, so please keep it installed after the first match. There’s a feedback form in the release notes and I read all of it.

Sign up: Sinete: teste fechado / closed test

Happy to go deeper on any of this, especially the headless testing setup.