🦆 DuckTown — Where Gossip Is the Game Mechanic

# Demo: https://youtu.be/uarb4KIBCAo

Inspiration

We wanted to move past static dialogue trees and build something that directly targets the need for new forms of gameplay, intelligent worlds, and dynamic player experiences. Social dynamics in games are usually rigid — but what if words actually had consequences?

As a team of Stevens Institute of Technology freshmen, we set out to build a 2D social sandbox game where the things you say don't just progress a conversation — they create rumors that spread autonomously through a living town.


What It Does

DuckTown is a game where the player must convince the mayor to approve a duck party by recruiting key NPCs: a baker, a sign maker, and a venue manager.

Instead of traditional quest markers, your primary tool is gossip. Conversations generate rumor cards that spread to other NPCs, changing relationships, unlocking items, and shifting quest progress. After a 15–30 second delay, another NPC will reference the rumor with a "did you hear..." prompt — triggering visible behavior changes across town.

You must carefully manage these rumors, resolve conflicts, and earn the approvals needed to secure cupcakes, signs, and a venue to pull off the ultimate duck party. 🦆🎉


How We Built It

We architected DuckTown into distinct, interconnected layers during our QuackHacks sprint:

🎮 Game Client

Built 2D movement, interaction, UI, and quest logic in Godot 4.6, scripted in GDScript. We leveraged Godot built-ins like HTTPRequest and Jolt Physics for smooth gameplay.

🤖 AI Engine

We used the Google Gemini API (gemini-2.5-flash) to generate dynamic NPC dialogue alongside a structured JSON update for every conversation — driving the entire rumor and relationship system.

🖥️ Backend Server

To securely call Gemini without shipping API keys in the client, we set up a local Node.js (18+) and Express.js backend as a proxy layer.

📐 Rumor Mathematics

To quantify how gossip affects the town, we mathematically modeled trust score adjustments. When a rumor spreads, the new trust score \(T_{new}\) is calculated using the baseline trust and the relationship delta \(\Delta R\) returned by Gemini, factoring in an exponential decay based on the spread delay \(t\):

$$T_{new} = \max\left(0,\ \min\left(100,\ T_{old} + \Delta R \cdot e^{-\lambda t}\right)\right)$$

This ensures that rumors which take longer to spread carry less relational weight — rewarding players who act quickly and decisively.


Challenges We Faced

Building this entirely from scratch meant moving incredibly fast. Our biggest technical challenge was prompt engineering the Gemini API to strictly output a validated JSON schema containing the rumor_card, relationship_delta, and quest_delta fields — without ever breaking the game's state machine.

Handling the asynchronous game loop was equally tricky. We needed the game to store the rumor and update the UI immediately, while simultaneously communicating with our Node backend to schedule rumor propagation to other NPCs on a delay — all without blocking the main thread.


What We Learned

We learned the value of strict division of labor in rapid development. Splitting work into distinct lanes — sprites & UI layout, Godot gameplay, Firebase & cloud schemas, and Gemini prompt design — allowed our team (Adithya, Shrikar, Abhiram, and Daksh) to avoid merge conflicts and ship efficiently.

We also learned how to seamlessly connect a local game engine to a REST-style API to handle JSON state data and proxy external AI requests — a pattern we'll carry into every future project.

Built With

Share this project:

Updates