Skip to content

What's New in v0.6.0-beta

Released: [Date TBD]

Version 0.6.0-beta brings significant performance optimizations, enhanced query capabilities, and improved developer experience with zero-allocation systems and comprehensive profiling tools.


Major Features

Performance Monitoring & Profiling

Built-in performance overlay with real-time metrics and detailed profiling:

// Enable performance monitoring
builder.Services.AddPerformanceMonitoring(options =>
{
    options.EnableOverlay = true;
    options.ShowFPS = true;
    options.ShowFrameTime = true;
    options.ShowMemory = true;
});

Features: - FPS Counter - Min/max/average tracking with 60-frame history - Frame Time Graph - Visual representation of frame timing - Memory Statistics - GC collection counts and managed memory usage - Rendering Stats - Sprites rendered, draw calls, batch efficiency - Per-System Profiling - Identify performance bottlenecks

Hotkeys: - F1 - Toggle overlay visibility - F3 - Toggle detailed stats (includes frame time graph and memory)

See Performance Monitoring Guide


Zero-Allocation Systems

Optimized hot paths using ArrayPool<T> and custom object pools to minimize GC pressure:

Entity Component Iteration:

// Safe iteration without allocations
protected internal virtual void OnUpdate(GameTime gameTime)
{
    var count = _components.Count;
    var array = ArrayPool<Component>.Shared.Rent(count);
    try
    {
        _components.CopyTo(array, 0);

        for (int i = 0; i < count; i++)
        {
            array[i].OnUpdate(gameTime);
        }
    }
    finally
    {
        ArrayPool<Component>.Shared.Return(array, clearArray: true);
    }
}

Particle System Pooling:

private readonly ObjectPool<Particle> _particlePool;

// Get from pool instead of 'new'
var particle = _particlePool.Get();
particle.Position = spawnPos;
particle.Velocity = velocity;

// Return to pool when done
_particlePool.Return(particle);

Query System Optimization:

// Random entity selection uses ArrayPool
var randomEnemy = _world.Query()
    .With<EnemyComponent>()
    .Random(); // Zero allocation!

See Performance Optimization Guide


Sprite Batching & Culling

Automatic batching with intelligent layer sorting and frustum culling:

var sprite = entity.AddComponent<SpriteComponent>();
sprite.TexturePath = "assets/player.png";
sprite.Layer = 10; // Higher layers render on top
sprite.Tint = Color.White;

// Check batching efficiency
var (renderedCount, drawCalls) = spriteSystem.GetBatchStats();
Logger.LogInfo($"Rendered {renderedCount} sprites in {drawCalls} draw calls");

Features: - Automatic Batching - Groups sprites by texture to minimize draw calls - Layer Sorting - Correct rendering order with configurable layers - Frustum Culling - Off-screen sprites automatically skipped - Batch Statistics - Real-time efficiency metrics

Performance: - 10,000+ sprites at 60 FPS with proper batching - 10-50x reduction in draw calls vs naive rendering - Zero allocation during rendering


Advanced Query System

Powerful spatial queries, component filtering, and sorting:

Spatial Queries:

// Find entities within radius
var nearbyEnemies = _world.Query()
    .WithinRadius(playerPos, 200f)
    .With<EnemyComponent>()
    .Execute();

// Find entities within bounds
var visibleEntities = _world.Query()
    .WithinBounds(new Rectangle(0, 0, 1280, 720))
    .Execute();

Component Filtering:

// Filter by component properties
var lowHealthEnemies = _world.Query()
    .With<HealthComponent>(h => h.CurrentHealth < 50)
    .With<EnemyComponent>()
    .Execute();

Sorting & Pagination:

// Get 5 nearest enemies
var nearest = _world.Query()
    .With<EnemyComponent>()
    .OrderBy(e => Vector2.Distance(
        e.GetComponent<TransformComponent>().Position, 
        playerPosition))
    .Take(5)
    .Execute();

// Paginate results
var page2 = _world.Query()
    .With<ItemComponent>()
    .Skip(10)
    .Take(10)
    .Execute();

Multi-Tag Queries:

// Must have ALL tags
var bosses = _world.Query()
    .WithAllTags("Enemy", "Boss", "Elite")
    .Execute();

// Must have ANY tag
var targets = _world.Query()
    .WithAnyTag("Enemy", "NPC", "Breakable")
    .Execute();

Query Cloning:

// Create base query
var enemyQuery = _world.Query()
    .With<EnemyComponent>()
    .Without<DeadComponent>();

// Clone and customize
var weakEnemies = enemyQuery.Clone()
    .With<HealthComponent>(h => h.CurrentHealth < 30)
    .Execute();

var strongEnemies = enemyQuery.Clone()
    .With<HealthComponent>(h => h.CurrentHealth > 80)
    .OrderByDescending(e => e.GetComponent<HealthComponent>().CurrentHealth)
    .Execute();

See Query System Guide


Camera Follow System

Automatic camera tracking with smooth movement and constraints:

var cameraFollow = player.AddComponent<CameraFollowComponent>();
cameraFollow.CameraName = "Main";
cameraFollow.Smoothing = 5f; // Higher = slower, smoother follow
cameraFollow.Offset = new Vector2(0, -50); // Camera offset from target
cameraFollow.Deadzone = new Vector2(50, 30); // Don't move within deadzone
cameraFollow.FollowX = true; // Follow horizontal movement
cameraFollow.FollowY = true; // Follow vertical movement
cameraFollow.Priority = 10; // Higher priority targets take precedence

Features: - Smooth Following - Configurable smoothing/lerp speed - Deadzone Support - Reduce camera jitter - Offset Control - Position camera relative to target - Priority System - Multiple targets with automatic switching - Axis Control - Enable/disable X or Y following independently

See Camera System Guide


Enhanced Particle System

Pooled particle effects with zero GC pressure:

var emitter = entity.AddComponent<ParticleEmitterComponent>();
emitter.IsEmitting = true;
emitter.EmissionRate = 50f; // Particles per second
emitter.MaxParticles = 200;
emitter.ParticleLifetime = 2f;

// Appearance
emitter.StartColor = new Color(255, 200, 0, 255);
emitter.EndColor = new Color(255, 50, 0, 0); // Fade to transparent
emitter.StartSize = 8f;
emitter.EndSize = 2f;

// Physics
emitter.InitialVelocity = new Vector2(0, -50);
emitter.VelocitySpread = 30f; // Random angle variance
emitter.Gravity = new Vector2(0, 100);
emitter.SpawnRadius = 10f; // Random spawn area

// Statistics
Logger.LogInfo($"Active particles: {emitter.ParticleCount}");

Features: - Object Pooling - Particles reused, zero GC allocations - Color Interpolation - Smooth color transitions - Size Interpolation - Shrink/grow over lifetime - Physics Simulation - Gravity and velocity - Configurable Emission - Rate, lifetime, and spawn area - Performance Stats - Track active particle count

See Particle System Guide


API Improvements

Cached Entity Queries

High-performance queries that automatically update:

// Create cached query (one-time setup)
var movingEntities = _world.CreateCachedQuery<TransformComponent, VelocityComponent>();

// Use in systems (zero allocation!)
public void Update(GameTime gameTime)
{
    foreach (var entity in movingEntities.Execute())
    {
        var transform = entity.GetComponent<TransformComponent>();
        var velocity = entity.GetComponent<VelocityComponent>();

        transform.Position += velocity.Velocity * deltaTime;
    }
}

Benefits: - Results cached and automatically invalidated on entity/component changes - Zero allocation per frame - Supports up to 3 component types - Perfect for system hot paths


Transform Hierarchy Improvements

Better memory management for parent/child relationships:

// Clear all children efficiently (uses ArrayPool)
transform.ClearChildren();

// Iterate children without allocation
foreach (var child in transform.Children)
{
    // Process child
}

Bug Fixes

Performance

  • Fixed memory leak in particle system when particles expired
  • Fixed unnecessary allocations in Entity.OnUpdate() component iteration
  • Fixed allocation in ParticleSystem.Render() (removed .ToList())
  • Optimized EntityQuery.Random() to use ArrayPool<T>

ECS

  • Fixed entity component iteration thread safety issues
  • Fixed transform hierarchy cleanup on entity destruction
  • Fixed cached query invalidation edge cases

Rendering

  • Fixed sprite batching layer sorting inconsistencies
  • Fixed camera follow jitter with high smoothing values
  • Fixed frustum culling boundary precision issues

Input

  • Fixed text input handling for special keys (backspace, delete, enter)
  • Fixed gamepad axis deadzone calculations

Documentation

New Guides

Updated Guides


New Demo Scenes

Performance Benchmark Scene

Stress test sprite batching with 10,000+ sprites:

cd samples/FeatureDemos
dotnet run
# Select "Performance Benchmark" from menu

Features: - Add/remove sprites dynamically (UP/DOWN: ±100, LEFT/RIGHT: ±1000) - Move camera to see frustum culling (WASD) - Zoom camera (Q/E) - Toggle culling visualization (C) - Real-time batching statistics

Enhanced Query Demo

Interactive demonstration of all query features:

  • Spatial queries (WithinRadius, WithinBounds)
  • Component filtering with predicates
  • Multi-tag queries (WithAllTags, WithAnyTag)
  • Sorting and pagination
  • Random selection
  • Query cloning

Enhanced Particle Demo

5 pre-configured particle effects:

  • Fire
  • Explosion
  • Smoke
  • Sparkles
  • Trail

Toggle continuous/burst emission, adjust parameters in real-time.


Performance Metrics

Sprite Rendering

  • Baseline: 1,000 sprites @ 60 FPS
  • Stress Test: 10,000+ sprites @ 60 FPS with batching
  • Draw Calls: 1-5 (depending on texture variety)
  • Batch Efficiency: 10-50x reduction in draw calls

Memory Management

  • Entity Updates: Zero allocation (uses ArrayPool<T>)
  • Query System: Zero allocation for cached queries
  • Particle System: Zero allocation per frame (object pooling)
  • GC Collections: Significantly reduced Gen 2 collections

Breaking Changes

None!

Version 0.6.0-beta maintains full API compatibility with 0.5.0-beta. All existing code will continue to work without modifications.


Updated Dependencies

  • .NET 10 SDK - Required
  • SDL3-CS - Updated to latest version
  • Microsoft.Extensions.* - Updated to .NET 10 versions

Upgrade Guide

From 0.5.0-beta

Update your package references:

<ItemGroup>
  <PackageReference Include="Brine2D.Desktop" Version="0.6.0-beta" />
</ItemGroup>

Or via command line:

dotnet add package Brine2D.Desktop --version 0.6.0-beta

No code changes required! Your 0.5.0-beta code will work as-is.

Optional: Enable Performance Monitoring

Add to your game builder:

builder.Services.AddPerformanceMonitoring(options =>
{
    options.EnableOverlay = true;
    options.ShowFPS = true;
    options.ShowFrameTime = true;
    options.ShowMemory = true;
});

What's Next (v0.7.0)

  • GPU Renderer - Complete SDL3 GPU backend
  • Texture Atlases - Automatic sprite sheet packing
  • Post-Processing - Shaders and effects pipeline
  • Spatial Audio - 3D sound positioning
  • Multi-Threading - Parallel ECS system execution
  • Enhanced Documentation - Video tutorials and advanced guides

Contributors

Thank you to everyone who contributed to this release!


Full Changelog: v0.5.0-beta...v0.6.0-beta