About the Project — Reddit Battets

A Reddit-native pixel creature battler where your karma becomes bananas, and your Battets become legends.

Inspiration

I love systems that feel alive—where rules are simple, but emergent outcomes surprise you. Battets grew from that itch: blend a playful monster battler with Reddit-native identity and economy (karma → bananas), then layer in AI-driven behaviors and clean, modular code. I wanted a game that could sit inside Reddit, feel fast, and still support deep mechanics and social play.

What I Built

Karma-powered economy: Reddit karma maps to bananas, the currency for buying Battets in a rotating shop (plus a weekly free Battet).

Daily shop + rarity tiers: Regular / Rare / Legendary variants with distinct names, descriptions, passives, and type spreads.

PvP lobbies (realtime): Host/join matches, auto-attach to ongoing games, and resolve turns with a battle log.

Wild battles + progression: Leveling, XP, and a growing roster designed for future evolutions.

Move systems:

A unified MoveGauge (0–20) for support effects (e.g., “chance to paralyze and raise defense”).

Status effects stored as an int array (e.g., [2, 4] for asleep + paralyzed).

How I Built It

Platform: Devvit (Reddit app runtime) with Redis for realtime state and pub/sub style updates.

Front end: Lightweight UI in Devvit components; emphasis on clarity over chrome so it runs smooth inside Reddit.

State & data design:

BattetData for full rarity-specific definitions and a simplified user Battet shape for storage and display.

Deterministic keys (e.g., matchKey(lobbyId)) to keep reads/writes predictable.

Battle engine:

Turn resolution queue + battle log for both players.

Consistent name matching helpers (e.g., unameEq) to decouple UI case differences from core state.

What I Learned

Race conditions are sneaky: Anything “realtime” needs idempotent writes, atomic lobby transitions, and consistent client hydration.

Designing for Reddit ≠ designing for the web: Tight render budgets and async APIs push you toward lean state, minimal re-renders, and careful retries.

Systems over special cases: The MoveGauge abstraction and status array keep complexity readable while still allowing expressive move combos.

Telemetry mindset: Even minimal logs (HP updates, join/host events, match status) are invaluable for debugging distributed timing issues.

Challenges I Faced

Joiner not transitioning to the battle view:

Fixes included normalizing usernames (unameEq), re-hydrating on mount, and auto-attach if a match exists for the current user.

Ensured both sides consume the same battle log and match status (pending → active → over) with atomic lobby removal.

HP sync & “ghost wins”:

Unified the battle log as the single source of truth, then derived UI state from it to prevent screen divergence.

Loading stalls (“stuck on loading match…”):

Added explicit state checks around Redis fetches, guarded JSON parses, and retried hydration with clear error paths.

To keep the engine transparent and tunable, core mechanics lean on simple math:

Trade-Offs & Design Choices

Two data shapes: A rich canonical definition for content and a thin runtime model for storage, rendering, and combat.

Deterministic keys & logs: Easier to reproduce bugs and reason about realtime edges.

What’s Next (If I Had More Time)

Proper UI to manage your Battets, one exists in menu but I dislike how unfriednly it is.

More Battets, More Moves, Custom BattleFields.

Leaderboards and seasonal ladders with rotating shop themes.

Closing

Reddit Battets aims to be snappy, social, and systemic—something you can jump into on Reddit, grab a Battet from the shop, and be in a lively match in seconds. It’s a compact engine with room to grow into evolutions, richer AI, and more social features—without losing the quick, punchy loop that makes it fun.

Built With

Share this project:

Updates