Merge branch 'world-loading-scene' into main
Add a loading screen (WorldLoadingScene) between world setup/load and WorldScene so the blocking world generation shows a "Generating world" indicator instead of a blank fade. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -92,6 +92,7 @@
|
|||||||
"menu.settings": "Settings",
|
"menu.settings": "Settings",
|
||||||
"menu.credits": "Credits",
|
"menu.credits": "Credits",
|
||||||
"menu.quit": "Quit",
|
"menu.quit": "Quit",
|
||||||
|
"loading.world": "Generating world",
|
||||||
"newworld.title": "New World",
|
"newworld.title": "New World",
|
||||||
"newworld.name": "Name",
|
"newworld.name": "Name",
|
||||||
"newworld.defaultname": "New World",
|
"newworld.defaultname": "New World",
|
||||||
|
|||||||
@@ -92,6 +92,7 @@
|
|||||||
"menu.settings": "Настройки",
|
"menu.settings": "Настройки",
|
||||||
"menu.credits": "Авторы",
|
"menu.credits": "Авторы",
|
||||||
"menu.quit": "Выход",
|
"menu.quit": "Выход",
|
||||||
|
"loading.world": "Создание мира",
|
||||||
"newworld.title": "Новый мир",
|
"newworld.title": "Новый мир",
|
||||||
"newworld.name": "Название",
|
"newworld.name": "Название",
|
||||||
"newworld.defaultname": "Новый мир",
|
"newworld.defaultname": "Новый мир",
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public sealed class LoadGameScene : Scene
|
|||||||
if (!Context.Scenes.IsTransitioning)
|
if (!Context.Scenes.IsTransitioning)
|
||||||
{
|
{
|
||||||
Context.Scenes.Switch(
|
Context.Scenes.Switch(
|
||||||
new WorldScene(save.ToConfig(), save),
|
new WorldLoadingScene(save.ToConfig(), save),
|
||||||
Transitions.Fade(0.6f)
|
Transitions.Fade(0.6f)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ public sealed class NewWorldScene : Scene
|
|||||||
Seed = seed,
|
Seed = seed,
|
||||||
SmoothPasses = _smoothing,
|
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()
|
private void Back()
|
||||||
|
|||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user