Loading screen between world setup and the game scene

World generation (WorldScene.OnLoad: terrain, atlases, spawn) runs synchronously
and blocks the frame; previously only a blank fade covered it, with no feedback.
New WorldLoadingScene shows a "Generating world" label, lets it draw, then switches
to WorldScene WITHOUT a transition so its last drawn frame (the label) stays on
screen during the blocking generation. Both New World and Load Game route through
it. Localized loading.world ru/en. Build + --check-content clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Leonid Pershin
2026-06-14 23:02:19 +03:00
co-authored by Claude Opus 4.8
parent 282ec018f7
commit 6ec70cab91
5 changed files with 67 additions and 2 deletions
+1 -1
View File
@@ -73,7 +73,7 @@ public sealed class LoadGameScene : Scene
if (!Context.Scenes.IsTransitioning)
{
Context.Scenes.Switch(
new WorldScene(save.ToConfig(), save),
new WorldLoadingScene(save.ToConfig(), save),
Transitions.Fade(0.6f)
);
}
+1 -1
View File
@@ -154,7 +154,7 @@ public sealed class NewWorldScene : Scene
Seed = seed,
SmoothPasses = _smoothing,
};
Context.Scenes.Switch(new WorldScene(config), Transitions.Fade(0.6f));
Context.Scenes.Switch(new WorldLoadingScene(config), Transitions.Fade(0.6f));
}
private void Back()
+63
View File
@@ -0,0 +1,63 @@
using LittleSim.App;
using LittleSim.Content;
using LittleSim.UI;
using MrGameEng.Core;
using MrGameEng.UI;
using Myra.Graphics2D.UI;
namespace LittleSim.Scenes;
/// <summary>
/// Экран загрузки между окном создания/выбора мира и игровой сценой. Генерация мира
/// (<see cref="WorldScene.OnLoad"/>: рельеф, атласы, спавн) идёт синхронно и блокирует кадр; раньше под
/// ней был лишь сплошной фейд без индикатора. Эта сцена рисует надпись «Создание мира…», даёт ей
/// прорисоваться, затем переключается на <see cref="WorldScene"/> БЕЗ перехода — её последний кадр
/// (надпись) и остаётся на экране, пока идёт генерация, давая игроку понятную обратную связь.
/// </summary>
public sealed class WorldLoadingScene : Scene
{
private readonly WorldConfig _config;
private readonly WorldSave? _save;
private GameSettings _settings = new();
private Label _label = null!;
private int _frames;
/// <summary>Новый мир (<paramref name="save"/> = null) или загрузка сохранения.</summary>
public WorldLoadingScene(WorldConfig config, WorldSave? save = null)
{
_config = config;
_save = save;
}
protected override void OnLoad()
{
_settings = GameSettingsStore.Load();
var desktop = this.UseScaledUI(); // ставит MyraEnvironment.Game до создания виджетов
_label = new Label
{
TextColor = Ui.Accent,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
};
desktop.Root = Ui.Screen(_label);
UpdateSystems.Add(new CallbackSystem(Tick));
}
private void Tick()
{
var content = Context.Services.Get<GameContent>();
var word = content.Languages.Get("loading.world");
var dots = new string('.', (int)(Context.Clock.UnscaledTotalTime * 2) % 4);
_label.Text = word + dots;
// Дождаться, пока надпись точно прорисована (переход въезда завершён + пара кадров), затем
// мгновенно переключиться: блокирующий WorldScene.OnLoad оставит на экране кадр с надписью.
_frames++;
if (Context.Scenes.IsTransitioning || _frames < 2)
{
return;
}
Context.Scenes.Switch(new WorldScene(_config, _save));
}
}