Add MrGameEng.UI module integrating Myra

scene.UseUI() creates a per-scene Myra Desktop and registers
UiRenderSystem last in the draw phase (UI on top, window pixels).
GameHost now exposes itself as a Game service (Myra needs the instance;
useful for games too). Myra was picked over Gum/ImGui for the
FontStashSharp ecosystem fit, pipeline-free assets and maturity; its
internal SpriteBatch use is a documented exception to the engine rule.

Sample: on-screen HUD replaces window-title-only stats — live FPS label,
music volume slider and scene-switch buttons on both scenes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Leonid Pershin
2026-06-11 04:51:12 +03:00
co-authored by Claude Fable 5
parent a3e6d3bb0a
commit af319d1276
12 changed files with 159 additions and 8 deletions
+24 -1
View File
@@ -5,6 +5,8 @@ using MrGameEng.Audio;
using MrGameEng.Core;
using MrGameEng.Graphics;
using MrGameEng.Input;
using MrGameEng.UI;
using Myra.Graphics2D.UI;
namespace MrGameEng.Sample.Scenes;
@@ -90,11 +92,32 @@ public sealed class MainScene : Scene
var hud = new Sprite(shapeRegions[3], SampleLayers.Ui);
Store.CreateEntity(new Transform2D(new Vector2(16f, 16f)), hud);
// UI (Myra): HUD со статистикой, слайдер громкости, кнопка перехода. После UseRenderer2D!
var desktop = this.UseUI();
var statsLabel = new Label();
var volumeSlider = new HorizontalSlider { Minimum = 0f, Maximum = 1f, Value = audio.Music.Volume, Width = 180 };
volumeSlider.ValueChanged += (_, _) => audio.Music.Volume = volumeSlider.Value;
var switchButton = new Button { Content = new Label { Text = "Stress scene (Tab)" } };
switchButton.Click += (_, _) =>
{
if (!Context.Scenes.IsTransitioning)
{
Context.Scenes.Switch(new StressScene(), Transition.Fade(0.8f));
}
};
var panel = new VerticalStackPanel { Left = 12, Top = 12, Spacing = 6 };
panel.Widgets.Add(statsLabel);
panel.Widgets.Add(new Label { Text = "Music volume (M — pause)" });
panel.Widgets.Add(volumeSlider);
panel.Widgets.Add(switchButton);
desktop.Root = panel;
UpdateSystems.Add(new PlayerControlSystem(player, actions, audio, beep));
UpdateSystems.Add(new BounceSystem(WorldBounds));
UpdateSystems.Add(new CameraControlSystem(camera, player, input));
UpdateSystems.Add(new SceneHotkeysSystem(Context, actions, () => new StressScene(), Transition.Fade(0.8f)));
UpdateSystems.Add(new TitleStatsSystem(Context, renderer, "Main"));
UpdateSystems.Add(new StatsSystem(Context, renderer, "Main", statsLabel));
var music = audio.Music;
if (!music.IsPlaying)