diff --git a/src/ReactorMaintenance.Win2D/MainWindow.xaml b/src/ReactorMaintenance.Win2D/MainWindow.xaml
index ca2a8a4..48750f4 100644
--- a/src/ReactorMaintenance.Win2D/MainWindow.xaml
+++ b/src/ReactorMaintenance.Win2D/MainWindow.xaml
@@ -15,7 +15,8 @@
-
+
+
diff --git a/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs b/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs
index 86704d0..a606c83 100644
--- a/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs
+++ b/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs
@@ -81,10 +81,13 @@ public sealed partial class MainWindow
m_Level = BuildStarterLevel();
m_EditorTools = BuildEditorTools();
+ m_SimulationTimer.Interval = TimeSpan.FromSeconds(1.0 / c_SimulationStepsPerSecond);
+ m_SimulationTimer.Tick += SimulationTimer_Tick;
LayerPicker.ItemsSource = Enum.GetValues();
LayerPicker.SelectedItem = EEditorLayer.Surface;
RefreshToolPicker();
RefreshInspector();
+ UpdatePlayPauseButton();
}
private void LevelCanvas_CreateResources(CanvasControl sender, CanvasCreateResourcesEventArgs args)
@@ -147,6 +150,7 @@ public sealed partial class MainWindow
private void New_Click(object sender, RoutedEventArgs e)
{
+ StopSimulationTimer();
m_Level = BuildStarterLevel();
m_CurrentFile = null;
m_SelectedCell = null;
@@ -166,6 +170,7 @@ public sealed partial class MainWindow
if (file is null)
return;
+ StopSimulationTimer();
var json = await FileIO.ReadTextAsync(file);
var loaded = LevelSerializer.Deserialize(json);
m_Level = loaded with { Forecasts = m_Simulation.Forecast(loaded) };
@@ -213,6 +218,43 @@ public sealed partial class MainWindow
}
private void EndTurn_Click(object sender, RoutedEventArgs e)
+ {
+ RunSimulationStep();
+ }
+
+ private void PlayPause_Click(object sender, RoutedEventArgs e)
+ {
+ if (m_SimulationTimer.IsEnabled)
+ StopSimulationTimer();
+ else
+ StartSimulationTimer();
+ }
+
+ private void SimulationTimer_Tick(object? sender, object e)
+ {
+ RunSimulationStep();
+ }
+
+ private void StartSimulationTimer()
+ {
+ m_SimulationTimer.Start();
+ UpdatePlayPauseButton();
+ }
+
+ private void StopSimulationTimer()
+ {
+ m_SimulationTimer.Stop();
+ UpdatePlayPauseButton();
+ }
+
+ private void UpdatePlayPauseButton()
+ {
+ var isPlaying = m_SimulationTimer.IsEnabled;
+ PlayPauseButton.Icon = new SymbolIcon(isPlaying ? Symbol.Pause : Symbol.Play);
+ PlayPauseButton.Label = isPlaying ? "Pause" : "Play";
+ }
+
+ private void RunSimulationStep()
{
m_Level = m_Simulation.EndTurn(m_Level);
RefreshInspector();
@@ -1313,6 +1355,7 @@ public sealed partial class MainWindow
private const double c_MaxZoom = 4;
private const double c_ZoomStep = 1.15;
private const double c_ClickPixelThreshold = 10;
+ private const int c_SimulationStepsPerSecond = 2;
private const int c_TilemapTileSize = 512;
private const int c_TopLeftCorner = 1;
private const int c_TopRightCorner = 2;
@@ -1326,6 +1369,7 @@ public sealed partial class MainWindow
private readonly EditorImageRegistry m_Images = new();
private readonly SimulationEngine m_Simulation = new();
+ private readonly DispatcherTimer m_SimulationTimer = new();
private EEditorLayer m_ActiveLayer = EEditorLayer.Surface;
private StorageFile? m_CurrentFile;
private GridPosition? m_CursorDragStartCell;