MEKAI Games Devlog

Designing a card system in Godot

How to design a data-driven Godot card system with reusable Resources, clear triggers, effect resolution, stacking rules, weighted offers, and practical tests.

ยท MEKAI Games

Upgrade cards offered in the Rock, Paper, Scissors, SHOOT! shop

Define cards as data

A card system scales when adding a card does not require editing the shop, UI and save code. Create a CardDefinition custom Resource with a stable ID, title, description, icon, rarity, price, tags, trigger and effect parameters.

Use the Inspector as the authoring tool, but keep the schema strict. A description is presentation; effect_type and values are game logic. Never parse rule text to discover what a card should do.

  • Stable ID for saves and analytics.
  • Rarity and shop weight as separate values.
  • Trigger such as run_start, before_choice, after_win or on_loss.
  • Effect parameters stored in explicit typed fields.

Resolve effects through one pipeline

Send every relevant game event through an effect resolver. The resolver finds eligible cards, orders them, checks conditions, applies effects and returns a result log. UI animation should replay that log rather than deciding which effect happens.

This separation makes fast-forward, debugging and automated simulation possible. It also prevents a skipped animation from skipping a reward.

The Demoniac Grimoire displays active cards and locked slots
The grimoire is presentation over stable card IDs, unlock rules and effect definitions.

Write stacking rules before adding content

Decide whether duplicates add, multiply, replace or cap. Then decide effect order. A flat bonus before a multiplier produces a different result from the same operations reversed. Make that order visible in code and in the player-facing description.

Use phases such as base, additive, multiplicative, override and final clamp. Cards can declare their phase and priority so the resolver remains deterministic.

  • Additive: +2 reward and +3 reward become +5.
  • Multiplicative: apply after additive bonuses unless explicitly stated.
  • Override: only the highest-priority override survives.
  • Cap: enforce limits after all effects resolve.

Build the offer pool deliberately

Weighted randomness should reflect the run. Filter cards that are invalid, exhausted or mutually exclusive before drawing. Then use explicit weights for rarity and context. A zero weight is clearer than drawing a card and rerolling until it disappears.

Record the run seed and offered card IDs. When a player reports an impossible shop, you can reproduce the same pool instead of guessing.

Test interactions, not only single cards

Most card bugs come from combinations. Create a small headless test that resolves a known event with a fixed set of cards and compares the final values and event log.

Maintain a matrix for the dangerous pairs: duplicate protection, reward multipliers, effects that cancel a loss, and cards that change the available actions. Every new card should add at least one interaction test.

Sources and further reading

Play on Steam