Skip to content

Fundamentals

Understand the core architecture and design patterns that power Brine2D. This section is for developers who want to:

  • 🏗️ Understand how Brine2D works internally
  • 🔧 Extend the engine with custom systems
  • 🎯 Build custom renderers or input backends
  • 🚀 Optimize advanced scenarios
  • 🤝 Contribute to Brine2D development

New to Brine2D?

If you're just getting started, begin with Get Started instead. This section assumes you've already built games with Brine2D and want to go deeper.


In This Section

Core Architecture

Topic Description Level
Architecture High-level system design, ASP.NET-inspired patterns, and service scoping ⭐⭐⭐ Advanced
Dependency Injection DI container internals, service lifetimes, and registration patterns ⭐⭐⭐ Advanced
Scene Management How SceneManager works, scene scoping, and lifecycle implementation ⭐⭐⭐ Advanced

Engine Systems

Topic Description Level
Game Loop Frame timing, update/render loop, and execution order ⭐⭐ Intermediate
Builder Pattern GameApplicationBuilder internals and service configuration ⭐⭐ Intermediate
ECS Deep Dive Entity-Component-System architecture, queries, and performance ⭐⭐⭐ Advanced

Quick Start Guide

For Different Goals

Goal: Learn how Brine2D is structured internally

Path:

  1. Architecture - Overall system design
  2. Dependency Injection - Service container
  3. Scene Management - Scene lifecycle

Time: 2-3 hours reading

Goal: Build custom implementations (renderer, input, etc.)

Path:

  1. Architecture - Understand abstractions
  2. Dependency Injection - Service registration
  3. Builder Pattern - Extension methods

Time: 3-4 hours + implementation time

Goal: Optimize advanced game scenarios

Path:

  1. Game Loop - Frame timing
  2. ECS Deep Dive - Entity performance
  3. Scene Management - Memory management

Time: 2-3 hours + profiling time

Goal: Contribute to the engine codebase

Path:

  1. Architecture - Design philosophy
  2. Dependency Injection - Service patterns
  3. Contributing Guide - Code style

Time: 2-3 hours + contribution time


Key Concepts

Service Lifetimes

Understanding service lifetimes is critical for working with Brine2D's DI system:

graph TB
    subgraph Application["Application Lifetime"]
        SINGLETON["Singleton Services<br/><small>IRenderer, IInputContext, IAudioService</small>"]
    end

    subgraph Scene1["Scene 1 Scope"]
        SCOPED1["Scoped Services<br/><small>IEntityWorld, CollisionSystem</small>"]
        TRANS1["Transient<br/><small>MenuScene instance</small>"]
    end

    subgraph Scene2["Scene 2 Scope (Fresh)"]
        SCOPED2["Scoped Services<br/><small>New IEntityWorld, CollisionSystem</small>"]
        TRANS2["Transient<br/><small>GameScene instance</small>"]
    end

    SINGLETON --> SCOPED1
    SINGLETON --> SCOPED2
    SCOPED1 --> TRANS1
    SCOPED2 --> TRANS2

    style SINGLETON fill:#2d5016,stroke:#4ec9b0,stroke-width:3px,color:#fff
    style SCOPED1 fill:#1e3a5f,stroke:#569cd6,stroke-width:2px,color:#fff
    style SCOPED2 fill:#1e3a5f,stroke:#569cd6,stroke-width:2px,color:#fff
    style TRANS1 fill:#3d3d2a,stroke:#dcdcaa,stroke-width:2px,color:#fff
    style TRANS2 fill:#3d3d2a,stroke:#dcdcaa,stroke-width:2px,color:#fff

Key Insight: Each scene gets its own isolated scope with fresh IEntityWorld instances. This prevents memory leaks and provides automatic cleanup.

Learn more in Dependency Injection


ASP.NET Core Parallels

Brine2D's architecture mirrors ASP.NET Core patterns you already know:

ASP.NET Core Brine2D What It Does
WebApplication.CreateBuilder() GameApplication.CreateBuilder() Configure services
Controllers Scenes Handle logic
ILogger<T> ILogger<T> Structured logging
Request Scope Scene Scope Isolated per-request state
Middleware Pipeline System Pipelines Sequential processing
appsettings.json gamesettings.json Configuration

If you've built ASP.NET apps, Brine2D will feel immediately familiar.

Learn more in Architecture


Scene Lifecycle

Understanding the scene lifecycle is essential for advanced scenarios:

stateDiagram-v2
    [*] --> Unloaded

    Unloaded --> Initializing: LoadSceneAsync()

    Initializing --> Loading: OnInitializeAsync()
    note right of Initializing
        - DI resolves scene
        - Sets Logger, World, Renderer
        - Creates scene scope
    end note

    Loading --> Active: OnLoadAsync()
    note right of Loading
        - Load assets
        - Create entities
        - Setup systems
    end note

    Active --> Active: OnUpdate()\nOnRender()
    note right of Active
        - Game loop runs
        - Entities updated
        - Rendering happens
    end note

    Active --> Unloading: Scene transition

    Unloading --> Unloaded: OnUnloadAsync()
    note right of Unloading
        - Scene scope disposed
        - EntityWorld disposed
        - Assets released
    end note

    Unloaded --> [*]

Learn more in Scene Management


Comparison to Unity & Godot

If you're coming from other engines:

Feature Unity Godot Brine2D
DI Container ❌ Manual ❌ Manual ✅ Built-in (ASP.NET style)
Scene Isolation ⚠️ Manual cleanup ⚠️ Manual cleanup ✅ Automatic (scoped services)
ECS ✅ DOTS (strict) ❌ None ✅ Hybrid (flexible)
Configuration ⚠️ ScriptableObjects ⚠️ .tres files ✅ JSON with hot reload
Async/Await ⚠️ Limited ⚠️ Limited ✅ First-class .NET async

Brine2D's advantage: Leverages battle-tested .NET patterns from enterprise web development.


Common Advanced Scenarios

Custom Renderer Implementation

public class MyCustomRenderer : IRenderer
{
    // Implement all IRenderer methods
    // Register in DI container
}

// In Program.cs
// builder.Services.AddSingleton<IRenderer, MyCustomRenderer>();

Full guide in Architecture


Custom Input Backend

public class MyCustomInputService : IInputContext
{
    // Implement input polling
    // Register as singleton
}

// builder.Services.AddSingleton<IInputContext, MyCustomInputService>();

Full guide in Dependency Injection


Scene-Specific Services

// Register a scoped service (per-scene instance)
builder.Services.AddScoped<ILevelManager, LevelManager>();

public class GameScene : Scene
{
    private readonly ILevelManager _levelManager; // Fresh instance per scene

    public GameScene(ILevelManager levelManager)`n    {
        _levelManager = levelManager;
    }
}

Full guide in Scene Management


Best Practices

✅ DO

  • Read Architecture first - Understand the big picture before diving into specifics
  • Use scoped services - For scene-specific state (prevents leaks)
  • Follow ASP.NET patterns - They're proven and familiar
  • Leverage async/await - Don't block the game loop
  • Test with DI - Mock dependencies for unit tests

❌ DON'T

  • Don't create singletons manually - Use DI container
  • Don't share state between scenes - Use scoped services
  • Don't block in OnUpdate - Use async methods for I/O
  • Don't inject IServiceProvider - Inject specific services
  • Don't fight the framework - Follow the established patterns

Performance Considerations

Service Resolution Cost

Service resolution is fast, but not free:

Lifetime Resolution Cost When to Use
Singleton Once (cached) Heavy objects, global state
Scoped Once per scene (cached) Scene-specific state
Transient Every resolution Lightweight, stateless

Rule of thumb: Use the most restrictive lifetime that makes sense.

Learn more in Dependency Injection


Memory Management

Scene scoping provides automatic memory management:

public class GameScene : Scene
{
    protected override async Task OnLoadAsync(CancellationToken ct)
    {
        // Create 1000 entities
        for (int i = 0; i < 1000; i++)
        {
            World.CreateEntity($"Entity_{i}");
        }
    }

    // ✅ No cleanup needed - World disposed automatically when scene unloads!
    // All 1000 entities destroyed, no memory leaks
}

Learn more in Scene Management


Internal Documentation

External Resources


Contributing

Found an issue or have a question about Brine2D's internals?


Ready to dive deep? Start with Architecture to understand Brine2D's design philosophy.