skills/thedivergentai/gd-agentic-skills/godot-genre-idle-clicker

godot-genre-idle-clicker

SKILL.md

Genre: Idle / Clicker

Expert blueprint for idle/clicker games with exponential progression and prestige mechanics.

NEVER Do

  • NEVER use standard float for currency — Floats overflow at ~1.8e308. Implement BigNumber (mantissa + exponent) from day 1.
  • NEVER use Timer nodes for revenue — Timers drift and pause when game pauses. Use _process(delta) accumulator for precise timing.
  • NEVER make prestige feel like punishment — Post-prestige runs should be 2-5x faster. Otherwise players feel like they lost progress.
  • NEVER update all UI labels every frame — Updating 50+ labels at 60fps causes lag. Use signals to update only when values change, or throttle to 10fps.
  • NEVER forget offline progress — Calculate seconds_offline * revenue_per_second on game start. Missing this destroys retention.

Available Scripts

MANDATORY: Read the appropriate script before implementing the corresponding pattern.

scientific_notation_formatter.gd

Big number formatter handling 1e303+. Uses K/M/B/T suffixes up to Vigintillion, falls back to scientific notation. Caching advice for high-label-count scenarios.


Core Loop

  1. Click: Player performs manual action to gain currency.
  2. Buy: Player purchases "generators" (auto-clickers).
  3. Wait: Game plays itself, numbers go up.
  4. Upgrade: Player buys multipliers to increase efficiency.
  5. Prestige: Player resets progress for a permanent global multiplier.

Skill Chain

Phase Skills Purpose
1. Math godot-gdscript-mastery Handling numbers larger than 64-bit float
2. UI godot-ui-containers, labels Displaying "1.5e12" or "1.5T" cleanly
3. Data godot-save-load-systems Saving progress, offline time calculation
4. Logic signals Decoupling UI from the economic simulation
5. Meta json-serialization Balancing hundreds of upgrades via data

Architecture Overview

1. Big Number System

Standard float goes to INF around 1.8e308. Idle games often go beyond. You need a custom BigNumber class (Mantissa + Exponent).

# big_number.gd
class_name BigNumber

var mantissa: float = 0.0 # 1.0 to 10.0
var exponent: int = 0     # Power of 10

func _init(m: float, e: int) -> void:
    mantissa = m
    exponent = e
    normalize()

func normalize() -> void:
    if mantissa >= 10.0:
        mantissa /= 10.0
        exponent += 1
    elif mantissa < 1.0 and mantissa != 0.0:
        mantissa *= 10.0
        exponent -= 1

2. Generator System

The core entities that produce currency.

# generator.gd
class_name Generator extends Resource

@export var id: String
@export var base_cost: BigNumber
@export var base_revenue: BigNumber
@export var cost_growth_factor: float = 1.15

var count: int = 0

func get_cost() -> BigNumber:
    # Cost = Base * (Growth ^ Count)
    return base_cost.multiply(pow(cost_growth_factor, count))

3. Simulation Manager (Offline Progress)

Calculating gains while the game was closed.

# game_manager.gd
func _ready() -> void:
    var last_save_time = save_data.timestamp
    var current_time = Time.get_unix_time_from_system()
    var seconds_offline = current_time - last_save_time
    
    if seconds_offline > 60:
        var revenue = calculate_revenue_per_second().multiply(seconds_offline)
        add_currency(revenue)
        show_welcome_back_popup(revenue)

Key Mechanics Implementation

Prestige System (Reset)

Resetting generators but keeping prestige_currency.

func prestige() -> void:
    if current_money.less_than(prestige_threshold):
        return
        
    # Formula: Cube root of money / 1 million
    # (Just an example, depends on balance)
    var gained_keys = calculate_prestige_gain()
    
    save_data.prestige_currency += gained_keys
    save_data.global_multiplier = 1.0 + (save_data.prestige_currency * 0.10)
    
    # Reset
    save_data.money = BigNumber.new(0, 0)
    save_data.generators = ResetGenerators()
    save_game()
    reload_scene()

Formatting Numbers

Displaying 1234567 as 1.23M.

static func format(bn: BigNumber) -> String:
    if bn.exponent < 3:
        return str(int(bn.mantissa * pow(10, bn.exponent)))
    
    var suffixes = ["", "K", "M", "B", "T", "Qa", "Qi"]
    var suffix_idx = bn.exponent / 3
    
    if suffix_idx < suffixes.size():
        return "%.2f%s" % [bn.mantissa * pow(10, bn.exponent % 3), suffixes[suffix_idx]]
    else:
        return "%.2fe%d" % [bn.mantissa, bn.exponent]

Godot-Specific Tips

  • Timers: Do NOT use Timer nodes for revenue generation (drifting). Use _process(delta) and accumulate time.
  • GridContainer: Perfect for the "Generators" list.
  • Resources: Use .tres files to define every generator (Farm, Mine, Factory) so you can tweak balance without touching code.

Common Pitfalls

  1. Floating Point Errors: Using standard float for money. Fix: Use BigNumber implementation immediately.
  2. Boring Prestige: Resetting feels like a punishment. Fix: Ensure the post-prestige run is significantly faster (2x-5x speed).
  3. UI Lag: Updating 50 text labels every frame. Fix: Only update labels when values actually change (Signal-based), or throttling updates to 10fps.

Reference

Weekly Installs
41
GitHub Stars
35
First Seen
Feb 10, 2026
Installed on
codex41
gemini-cli41
opencode41
github-copilot40
kimi-cli40
amp40