Configuration¶
Brine2D uses JSON-based configuration just like ASP.NET Core. Settings are loaded from gamesettings.json and can be bound to strongly-typed option classes.
The ASP.NET Way¶
If you've used ASP.NET Core, this will be instantly familiar:
| ASP.NET Core | Brine2D | Purpose |
|---|---|---|
appsettings.json |
gamesettings.json |
Main configuration file |
appsettings.Development.json |
gamesettings.Development.json |
Environment-specific settings |
IOptions<T> |
IOptions<RenderingOptions> |
Strongly-typed configuration |
builder.Configuration |
builder.Configuration |
Configuration API |
Quick Example¶
// Load from gamesettings.json
builder.Services.AddSDL3Rendering(options =>
{
builder.Configuration.GetSection("Rendering").Bind(options);
});
// Or configure in code
builder.Services.AddSDL3Rendering(options =>
{
options.WindowTitle = "My Game";
options.WindowWidth = 1920;
options.WindowHeight = 1080;
options.VSync = true;
});
The gamesettings.json File¶
Create a gamesettings.json file in your project root:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Brine2D": "Debug",
"Brine2D.Rendering": "Information",
"Brine2D.Input": "Warning"
}
},
"Rendering": {
"WindowTitle": "My Brine2D Game",
"WindowWidth": 1280,
"WindowHeight": 720,
"Fullscreen": false,
"VSync": true,
"Resizable": true,
"Backend": "GPU",
"PreferredGPUDriver": null
}
}
Make Sure It's Copied to Output¶
Update your .csproj to copy the file:
<ItemGroup>
<None Update="gamesettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
Configuration Sections¶
Logging¶
Controls logging output for different parts of the engine.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Brine2D": "Debug",
"Brine2D.Rendering": "Information",
"Brine2D.Input": "Warning",
"Brine2D.Audio": "Information",
"Microsoft": "Warning"
}
}
}
Log Levels:
- Trace - Very detailed, for deep debugging
- Debug - Detailed debugging information
- Information - General informational messages
- Warning - Warning messages
- Error - Error messages
- Critical - Critical failures
- None - No logging
Example Usage:
builder.Logging.SetMinimumLevel(LogLevel.Debug);
builder.Logging.AddConsole();
builder.Logging.AddDebug(); // Visual Studio Output window
Rendering¶
Controls window and rendering settings.
{
"Rendering": {
"WindowTitle": "My Game",
"WindowWidth": 1280,
"WindowHeight": 720,
"Fullscreen": false,
"VSync": true,
"Resizable": true,
"Backend": "GPU",
"PreferredGPUDriver": "Vulkan"
}
}
Options:¶
| Property | Type | Default | Description |
|---|---|---|---|
WindowTitle |
string |
"Brine2D Game" |
Window title text |
WindowWidth |
int |
1280 |
Window width in pixels |
WindowHeight |
int |
720 |
Window height in pixels |
Fullscreen |
bool |
false |
Start in fullscreen mode |
VSync |
bool |
true |
Enable vertical sync |
Resizable |
bool |
true |
Allow window resizing |
Backend |
string |
"GPU" |
Graphics backend: "GPU", "LegacyRenderer", or "Auto" |
PreferredGPUDriver |
string? |
null |
GPU driver: "Vulkan", "Metal", "D3D11", "D3D12", or null (auto) |
Graphics Backends:¶
GPU- Modern SDL3 GPU API (recommended)- Supports Vulkan, Metal, D3D11, D3D12
- Better performance
-
Cross-platform shader system
-
LegacyRenderer- SDL3's traditional 2D renderer - More compatible with older hardware
- Simpler API
-
Faster startup
-
Auto- Automatically selects GPU if available, falls back to Legacy
GPU Drivers:¶
If using Backend: "GPU", you can specify a preferred driver:
{
"Rendering": {
"Backend": "GPU",
"PreferredGPUDriver": "Vulkan"
}
}
null(default) - Auto-select best driver for platformVulkan- Windows, Linux, AndroidMetal- macOS, iOSD3D11- Windows (older GPUs)D3D12- Windows (modern GPUs)
Environment-Specific Configuration¶
Just like ASP.NET, you can have different settings per environment.
File Structure:¶
MyGame/
├── gamesettings.json # Base settings
├── gamesettings.Development.json # Development overrides
├── gamesettings.Production.json # Production overrides
└── Program.cs
Example: Development Settings¶
gamesettings.Development.json:
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Brine2D": "Trace"
}
},
"Rendering": {
"WindowTitle": "My Game [DEV]",
"VSync": false
}
}
Set the Environment:¶
# Windows (PowerShell)
$env:DOTNET_ENVIRONMENT = "Development"
dotnet run
# Linux/macOS
DOTNET_ENVIRONMENT=Development dotnet run
Or in Visual Studio, set it in Project Properties > Debug > Environment Variables.
Code-Based Configuration¶
You can configure options entirely in code:
using Brine2D.Hosting;
using Brine2D.Rendering.SDL;
var builder = GameApplication.CreateBuilder(args);
// Method 1: Inline configuration
builder.Services.AddSDL3Rendering(options =>
{
options.WindowTitle = "My Game";
options.WindowWidth = 1920;
options.WindowHeight = 1080;
options.Fullscreen = true;
options.VSync = true;
options.Backend = GraphicsBackend.GPU;
options.PreferredGPUDriver = "Vulkan";
});
// Method 2: Bind from configuration
builder.Services.AddSDL3Rendering(options =>
{
builder.Configuration.GetSection("Rendering").Bind(options);
// Override specific values
options.WindowTitle = "Overridden Title";
});
// Method 3: Mix both
builder.Services.AddSDL3Rendering(options =>
{
// Load base from JSON
builder.Configuration.GetSection("Rendering").Bind(options);
// Override based on logic
if (args.Contains("--fullscreen"))
{
options.Fullscreen = true;
}
});
Accessing Configuration in Scenes¶
You can inject IConfiguration or IOptions<T> into your scenes:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
public class GameScene : Scene
{
private readonly IConfiguration _configuration;
private readonly RenderingOptions _renderingOptions;
public GameScene(
IConfiguration configuration,
IOptions<RenderingOptions> renderingOptions,
ILogger<GameScene> logger
) : base(logger)
{
_configuration = configuration;
_renderingOptions = renderingOptions.Value;
}
protected override void OnInitialize()
{
// Access configuration
var windowTitle = _configuration["Rendering:WindowTitle"];
// Access strongly-typed options
var width = _renderingOptions.WindowWidth;
var height = _renderingOptions.WindowHeight;
Logger.LogInformation("Window: {Title} ({Width}x{Height})",
windowTitle, width, height);
}
}
Custom Configuration Sections¶
You can add your own configuration sections:
1. Define Your Options Class¶
public class GameplayOptions
{
public const string SectionName = "Gameplay";
public int StartingLives { get; set; } = 3;
public float PlayerSpeed { get; set; } = 200f;
public bool EnableCheats { get; set; } = false;
public string Difficulty { get; set; } = "Normal";
}
2. Add to gamesettings.json¶
{
"Gameplay": {
"StartingLives": 5,
"PlayerSpeed": 250.0,
"EnableCheats": false,
"Difficulty": "Hard"
}
}
3. Register and Use¶
// Register in Program.cs
builder.Services.Configure<GameplayOptions>(
builder.Configuration.GetSection(GameplayOptions.SectionName)
);
// Inject into scene
public class GameScene : Scene
{
private readonly GameplayOptions _gameplay;
public GameScene(
IOptions<GameplayOptions> gameplay,
ILogger<GameScene> logger
) : base(logger)
{
_gameplay = gameplay.Value;
}
protected override void OnInitialize()
{
Logger.LogInformation("Starting with {Lives} lives at {Difficulty} difficulty",
_gameplay.StartingLives, _gameplay.Difficulty);
}
}
Hot Reload¶
Configuration files support hot reload by default:
// In GameApplicationBuilder, this is already set up:
Configuration.AddJsonFile("gamesettings.json",
optional: true,
reloadOnChange: true); // ← Hot reload enabled
Using IOptionsMonitor for Hot Reload¶
If you need to detect configuration changes at runtime:
using Microsoft.Extensions.Options;
public class GameScene : Scene
{
private readonly IOptionsMonitor<RenderingOptions> _renderingMonitor;
public GameScene(
IOptionsMonitor<RenderingOptions> renderingMonitor,
ILogger<GameScene> logger
) : base(logger)
{
_renderingMonitor = renderingMonitor;
// Subscribe to changes
_renderingMonitor.OnChange(options =>
{
Logger.LogInformation("Configuration changed! New window size: {Width}x{Height}",
options.WindowWidth, options.WindowHeight);
});
}
protected override void OnUpdate(GameTime gameTime)
{
// Always get current value
var currentOptions = _renderingMonitor.CurrentValue;
}
}
Command-Line Arguments¶
Override configuration with command-line arguments:
# Command-line args are already added by default in CreateBuilder
# They override JSON settings
# Run with:
dotnet run --Rendering:WindowWidth=1920 --Rendering:Fullscreen=true
In gamesettings.json:¶
{
"Rendering": {
"WindowWidth": 1280,
"Fullscreen": false
}
}
Override via CLI:¶
dotnet run --Rendering:WindowWidth=1920 --Rendering:Fullscreen=true
Result: Window will be 1920 pixels wide and fullscreen.
Configuration Providers¶
Brine2D uses Microsoft's configuration system, which supports multiple providers:
var builder = GameApplication.CreateBuilder(args);
// JSON files (default)
builder.Configuration.AddJsonFile("gamesettings.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("secrets.json", optional: true);
// Environment variables
builder.Configuration.AddEnvironmentVariables(prefix: "GAME_");
// Command-line arguments (already added by default)
builder.Configuration.AddCommandLine(args);
// User secrets (for development)
if (builder.Environment.IsDevelopment())
{
builder.Configuration.AddUserSecrets<Program>();
}
// In-memory values (for testing)
builder.Configuration.AddInMemoryCollection(new Dictionary<string, string?>
{
["Rendering:WindowTitle"] = "Test Window"
});
Priority Order (last wins): 1. JSON files 2. Environment variables 3. Command-line arguments 4. In-memory overrides
Common Patterns¶
Pattern 1: Debug vs Release Settings¶
builder.Services.AddSDL3Rendering(options =>
{
builder.Configuration.GetSection("Rendering").Bind(options);
#if DEBUG
options.WindowTitle += " [DEBUG]";
options.VSync = false; // Better for debugging
#endif
});
Pattern 2: Dynamic Resolution¶
builder.Services.AddSDL3Rendering(options =>
{
builder.Configuration.GetSection("Rendering").Bind(options);
// Let user override via CLI
if (args.Contains("--720p"))
{
options.WindowWidth = 1280;
options.WindowHeight = 720;
}
else if (args.Contains("--1080p"))
{
options.WindowWidth = 1920;
options.WindowHeight = 1080;
}
});
Pattern 3: Platform-Specific Settings¶
builder.Services.AddSDL3Rendering(options =>
{
builder.Configuration.GetSection("Rendering").Bind(options);
// Auto-select best backend per platform
if (OperatingSystem.IsWindows())
{
options.PreferredGPUDriver = "D3D12";
}
else if (OperatingSystem.IsMacOS())
{
options.PreferredGPUDriver = "Metal";
}
else if (OperatingSystem.IsLinux())
{
options.PreferredGPUDriver = "Vulkan";
}
});
Best Practices¶
✅ DO: Use JSON for User-Configurable Settings¶
Settings players might want to change (resolution, volume, graphics quality) should be in JSON.
✅ DO: Use Code for Developer Settings¶
Settings developers control (debug flags, profiling) can be in code.
✅ DO: Validate Configuration¶
builder.Services.AddSDL3Rendering(options =>
{
builder.Configuration.GetSection("Rendering").Bind(options);
// Validate
if (options.WindowWidth < 640 || options.WindowHeight < 480)
{
throw new InvalidOperationException("Window size too small!");
}
});
✅ DO: Use Strongly-Typed Options¶
Avoid magic strings—create option classes for your settings.
❌ DON'T: Hardcode Secrets¶
Never put API keys, passwords, or tokens in gamesettings.json that gets committed to Git. Use User Secrets or environment variables.
❌ DON'T: Reload Configuration Mid-Frame¶
If you need to apply new settings (like resolution), do it between scenes, not during rendering.
Example: Complete Configuration¶
gamesettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Brine2D": "Debug"
}
},
"Rendering": {
"WindowTitle": "My Awesome Game",
"WindowWidth": 1280,
"WindowHeight": 720,
"Fullscreen": false,
"VSync": true,
"Resizable": true,
"Backend": "GPU",
"PreferredGPUDriver": null
},
"Gameplay": {
"StartingLives": 3,
"PlayerSpeed": 200.0,
"Difficulty": "Normal"
}
}
Program.cs:
using Brine2D.Hosting;
using Brine2D.Input.SDL;
using Brine2D.Rendering.SDL;
var builder = GameApplication.CreateBuilder(args);
// Configure rendering from JSON
builder.Services.AddSDL3Rendering(options =>
{
builder.Configuration.GetSection("Rendering").Bind(options);
});
builder.Services.AddSDL3Input();
// Register custom options
builder.Services.Configure<GameplayOptions>(
builder.Configuration.GetSection("Gameplay")
);
builder.Services.AddScene<GameScene>();
var game = builder.Build();
await game.RunAsync<GameScene>();
Next Steps¶
- Your First Game - Build a complete game
- Project Structure - Understanding the architecture
- Scene Management - Deep dive into scenes
- Logging Guide - Using
ILogger<T>effectively
Configuration in Brine2D works exactly like ASP.NET—if you know one, you know the other! 🎯