Skip to main content

Architecture Overview

Nyuron is built as a modular ecosystem of minigames in Godot 4, with shared systems for progression, transitions, and state management. This architecture allows each minigame to be developed, tested, and maintained independently while contributing to a unified player experience.

Core Architecture Principles

Modularity

Each minigame is a self-contained scene with its own logic, UI, and assets

Shared Systems

Autoloaded singletons handle scoring, transitions, and save data

Mobile-First

Dynamic resolution scaling and orientation switching per minigame

Scene Independence

Minigames can be tested in isolation without loading the full menu

Project Configuration

From project.godot:11-22, Nyuron is configured as a mobile game:
[application]
config/name="nyuron"
run/main_scene="uid://7q1r7r4yp7fa"
config/features=PackedStringArray("4.5", "Mobile")

[autoload]
TransitionBlocks="*res://TransitionBlocks.gd"
ScoreManager="*res://scripts/ScoreManager.gd.gd"

[display]
window/size/viewport_width=270
window/size/viewport_height=480
window/stretch/mode="canvas_items"
window/stretch/scale_mode="integer"
window/handheld/orientation=6
The base viewport is 270x480 (portrait), but minigames dynamically switch to 480x270 (landscape) when needed.

Core Systems

Nyuron relies on two critical autoloaded singletons that are accessible from any scene:

ScoreManager (Global State)

The ScoreManager autoload (scripts/ScoreManager.gd.gd:1-125) handles all persistent game data:
# High scores for all 6 minigames (ScoreManager.gd.gd:9-16)
var high_scores = {
    "memorice": 0,
    "turtle_runner": 0,
    "worm_catch": 0,
    "food_catch": 0,
    "counting_animals": 0,
    "nyuron_color": 0
}
var coins := 0
var inventory: Array = []
var equipped_items = {
    "caparazon": "default", 
    "accesorio": "none"
}
Key Methods:
  • save_high_score(game_name: String, new_score: int) - Updates high score if beaten
  • get_high_score(game_name: String) - Retrieves current high score
  • add_coins(amount: int) - Awards coins for gameplay
  • get_coins() - Returns current coin balance
  • equip_item(category: String, item_name: String) - Equips cosmetic items
  • save_to_file() / load_high_scores() - Persistence to user://high_scores.cfg
All minigames should call ScoreManager.save_high_score() when the game ends to track player progress.

TransitionBlocks (Scene Transitions)

The TransitionBlocks autoload (TransitionBlocks.gd:1-97) provides animated scene transitions:
# Creates a spiral wipe effect with colored blocks (TransitionBlocks.gd:54-70)
func wipe_to(scene_path: String, duration := 0.1):
    visible = true
    var delay_per_block := 0.004
    for i in range(blocks.size()):
        var idx = block_order[i]
        var block = blocks[idx]
        block.visible = true
        block.modulate.a = 0.0
        var tween := create_tween()
        tween.tween_property(block, "modulate:a", 1.0, duration)\
            .set_delay(i * delay_per_block)
    
    var total_time := duration + blocks.size() * delay_per_block
    get_tree().create_timer(total_time).timeout.connect(func():
        get_tree().change_scene_to_file(scene_path)
        wipe_out_fade()
    )
Key Features:
  • Spiral block-based wipe transition
  • transition_finished signal for UI timing
  • Smooth fade-in/fade-out on scene load
  • Used for visual polish between menu and minigames
The main menu (scripts/main_menu.gd:1-294) serves as the game’s hub:
# UI references from main_menu.gd:4-12
@onready var menu_panel := $CanvasLayer/MenuSlidePanel
@onready var turtle_button := $CanvasLayer/MenuSlidePanel/.../TurtleButton
@onready var worm_button := $CanvasLayer/MenuSlidePanel/.../WormButton
@onready var food_button := $CanvasLayer/MenuSlidePanel/.../FoodButton
@onready var memorice_button := $CanvasLayer/MenuSlidePanel/.../MemoriceButton
@onready var counting_button := $CanvasLayer/MenuSlidePanel/.../CountingButton
@onready var color_button := $CanvasLayer/MenuSlidePanel/.../ColorButton
@onready var coin_label: Label = $CanvasLayer/CoinDisplay/.../CoinLabel

Minigame Launcher Pattern

Each minigame button follows this pattern (main_menu.gd:204-233):
func _on_turtle_pressed():
    DisplayServer.screen_set_orientation(DisplayServer.SCREEN_LANDSCAPE)
    get_tree().root.set_content_scale_size(Vector2i(480, 270))
    get_tree().change_scene_to_file("res://minigames/turtle_run/scenes/main.tscn")

func _on_worm_pressed():
    DisplayServer.screen_set_orientation(DisplayServer.SCREEN_PORTRAIT)
    get_tree().root.set_content_scale_size(Vector2i(270, 480))
    get_tree().change_scene_to_file("res://minigames/worm_bucket/Scenes/main.tscn")
Important: Each minigame must set the correct orientation and viewport size before transitioning to ensure proper rendering.

Character Customization

The menu dynamically updates the player character’s appearance (main_menu.gd:98-137):
func update_menu_skin():
    var id_cuerpo = ScoreManager.get_equipped_item("caparazon")
    var id_accesorio = ScoreManager.get_equipped_item("accesorio")
    
    var color_suffix = menu_color_codes.get(id_cuerpo, "")
    var acc_suffix = menu_accessory_codes.get(id_accesorio, "")
    
    var folder_path = "res://Accesorios/global/"
    var base_filename = "spr_rest" 
    
    var final_path = folder_path + base_filename + color_suffix + acc_suffix + ".png"
    
    if ResourceLoader.exists(final_path):
        var new_texture = load(final_path)
        _apply_texture_to_menu_anim(new_texture)

Minigame Architecture

Each minigame follows a consistent structure:
1

Main Scene

Root node (usually Control or Node2D) with a main controller script (main.gd)
2

UI Layer

CanvasLayer containing:
  • HUD (score, lives, timer)
  • Start panel
  • Game over panel
  • Pause menu (optional)
3

Game Logic

  • Spawners with Timer nodes
  • Player/character nodes
  • Collectibles/obstacles
  • Physics/collision handling
4

Audio

  • Background music (AudioStreamPlayer)
  • Sound effects for actions
  • Feedback sounds (success/failure)

Directory Structure

nyuron/
├── minigames/
│   ├── turtle_run/         # Landscape runner game
│   ├── worm_bucket/        # Portrait catching game
│   ├── food_catch/         # Portrait food collection
│   ├── memorice/           # Portrait memory card game
│   ├── counting_animals/   # Landscape counting game
│   └── nyuron_color/       # Portrait color matching
├── scripts/
│   ├── main_menu.gd        # Main menu controller
│   └── ScoreManager.gd.gd  # Global state management
├── scenes/
│   ├── main_menu.tscn      # Hub scene
│   └── intro.tscn          # First-time intro sequence
├── tienda/                  # Shop system for cosmetics
├── Accesorios/              # Character customization assets
├── TransitionBlocks.gd      # Scene transition system
└── project.godot            # Project configuration

Mobile Optimization

Nyuron is optimized for mobile devices:

Rendering Settings

From project.godot:40-46:
[rendering]
textures/canvas_textures/default_texture_filter=0
renderer/rendering_method="mobile"
textures/vram_compression/import_etc2_astc=true
2d/snap/snap_2d_transforms_to_pixel=true
  • Pixel-perfect filtering for crisp pixel-art
  • Mobile renderer for performance
  • Integer scaling to prevent blur
  • ETC2/ASTC compression for reduced memory usage

Input Handling

Simple touch controls mapped to mouse input (project.godot:33-38):
[input]
click={
"events": [InputEventMouseButton, button_index=1]
}
Touch events are automatically translated to mouse button events by Godot, making testing on desktop straightforward.

Aesthetic & Theme

Nyuron features a cohesive underwater/beach pixel-art aesthetic:
  • Vibrant, child-friendly color palette
  • Low-resolution sprites for nostalgic pixel-art feel
  • Animated sprites for characters and UI elements
  • Consistent visual language across all minigames
The pixel-art style keeps file sizes small (important for mobile) while maintaining visual appeal for young players.

Next Steps

Installation

Clone the repository and set up Godot 4

Minigames

Deep dive into each minigame’s mechanics

Build docs developers (and LLMs) love