Table of Contents

Stride UI - Draggable Window

A windowing system built on Stride's UI: windows with title bars and close buttons that can be dragged around, and that come to the front when clicked. Z-order is the part that makes it feel real, and it needs a container tracking every window rather than logic on each one. The windows spawn falling spheres and keep a live count, with objects that drop out of the world cleaned up and subtracted again.

The Program.cs file shows how to:

  • Building a draggable window from Canvas and pointer events
  • Bringing a window to the front by managing z-order centrally
  • Splitting responsibility: container, window, manager, generator
  • Spawning scene objects from a UI button
  • Keeping a UI counter in step with the scene
  • Removing entities that fall out of the world
  • Using helpers: SceneSetup3D, UseSkybox, CreatePrimitive, AddGrabber

Stride UI - Draggable Window

View on GitHub.

using E04_StrideUI_DragAndDrop;
using Stride.CommunityToolkit.Bepu;
using Stride.CommunityToolkit.Engine;
using Stride.CommunityToolkit.Rendering.Overlay;
using Stride.CommunityToolkit.Rendering.ProceduralModels;
using Stride.CommunityToolkit.Skyboxes;
using Stride.Core.Mathematics;
using Stride.Engine;
using Stride.Games;
using Stride.Graphics;

const int ShapeCount = 100;
const int RemovalThresholdY = -30;

UIManager? uiManager = null;
PrimitiveGenerator? shapeGenerator = null;

using var game = new Game();

game.Run(new SceneSetup3D { Profiler = true }.UseBepu().UseSkybox(), start: Start, update: Update);

void Start(Scene scene)
{
    game.AddGrabber();
    game.AddEntityInfoRenderer(new() { EnableBackground = true });

    shapeGenerator = new PrimitiveGenerator(game, scene);
    uiManager = new UIManager(game.Content.Load<SpriteFont>("/Stride.Engine/StrideDefaultFont"), GenerateRandomSpheres);
    uiManager.Entity.Scene = scene;

    var capsule = game.CreatePrimitive(Primitive3D.Capsule());
    capsule.Transform.Position = new Vector3(0, 8, 0);
    capsule.Scene = scene;
}

void Update(Scene scene, GameTime time)
{
    // Backwards by index: taking an entity out of the scene while a foreach walks the same list
    // would skip the entity after it
    for (var i = scene.Entities.Count - 1; i >= 0; i--)
    {
        var entity = scene.Entities[i];

        if (entity.Transform.Position.Y < RemovalThresholdY)
        {
            entity.Scene = null;

            shapeGenerator?.Subtract(1);
            uiManager?.UpdateTextBlock($"Total Shapes: {shapeGenerator?.TotalShapes ?? 0}");
        }
    }
}

void GenerateRandomSpheres()
{
    var totalShapes = shapeGenerator?.Generate(ShapeCount, Primitive3D.Sphere(0.3f));

    uiManager?.UpdateTextBlock($"Total Shapes: {totalShapes ?? 0}");
}

Files

  • UIManager - creates and manages the windows and updates their text
  • DragAndDropContainer - the root canvas that tracks the draggable elements and their stacking order
  • DragAndDropCanvas - one window: title bar, divider, close button and dragging
  • PrimitiveGenerator - creates the spheres spawned from the UI and keeps their count, which the update loop in Program.cs lowers as it removes those that fall out of the world