From ae0a68c3325895e2d388db99a7a141529bbc3128 Mon Sep 17 00:00:00 2001 From: dnesov Date: Thu, 17 Oct 2024 22:33:21 +0200 Subject: [PATCH] Update Game, add IGame. --- TestGame/TestGame.cs | 35 +++++---- Voile/Source/Game.cs | 183 +++++++++++++++++++++++++++---------------- 2 files changed, 134 insertions(+), 84 deletions(-) diff --git a/TestGame/TestGame.cs b/TestGame/TestGame.cs index 52807c1..ba50694 100644 --- a/TestGame/TestGame.cs +++ b/TestGame/TestGame.cs @@ -1,16 +1,29 @@ using Voile; using Voile.Resources; -using Voile.Utils; using Voile.Input; using Voile.Systems.Particles; using System.Numerics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics; +using Voile.Rendering; -public class TestGame : BaseGame +public class TestGame : Game { + public override string Name => "Jump Adventures 2"; public override string ResourceRoot => "Resources/"; + public override void Initialize() + { + InitializeSystemsDefault(); + + _particleSystem = new ParticleSystem(); + AddSystemToUpdate(_particleSystem); + } + + public override void Shutdown() + { + ShutdownDefault(); + } + protected override void LoadResources() { ResourceManager.AddResourceLoaderAssociation(new ParticleEmitterSettingsResourceLoader()); @@ -30,19 +43,14 @@ public class TestGame : BaseGame protected override void Ready() { - _particleSystem = new ParticleSystem(); Input.AddInputMapping("reload", new InputAction[] { new KeyInputAction(KeyboardKey.R) }); - _particleSimStopwatch = new Stopwatch(); - _emitterId = _particleSystem.CreateEmitter(Renderer.WindowSize / 2, _fireEffect); } protected override void Update(double deltaTime) { - _particleSimStopwatch = Stopwatch.StartNew(); - _particleSystem!.Update(deltaTime); - _particleSimStopwatch.Stop(); + } protected override void Render(double deltaTime) @@ -70,18 +78,16 @@ public class TestGame : BaseGame } Renderer.ResetTransform(); - Renderer.DrawText(_font, $"Particle Sim: {_particleSimStopwatch.Elapsed.TotalMilliseconds} ms", Color.White); - Renderer.SetTransform(new Vector2(0.0f, 16.0f), Vector2.Zero); Renderer.DrawText(_font, $"Render: {RenderFrameTime.TotalMilliseconds:F1} ms", Color.White); - Renderer.SetTransform(new Vector2(0.0f, 32.0f), Vector2.Zero); + Renderer.SetTransform(new Vector2(0.0f, 16.0f), Vector2.Zero); Renderer.DrawText(_font, $"Update: {UpdateTimeStep * 1000:F1} ms", Color.White); } private void DrawEmitter(ParticleEmitter emitter) { - Renderer.BeginBlended(Voile.Rendering.BlendMode.BlendAlpha); + Renderer.BeginBlended(BlendMode.BlendAlpha); var maxParticles = emitter.Settings.MaxParticles; var particleSize = new Vector2(16.0f, 16.0f); @@ -99,11 +105,8 @@ public class TestGame : BaseGame } [NotNull] private ParticleSystem _particleSystem; - - private Stopwatch _particleSimStopwatch; private int _emitterId; private ResourceRef _fireEffect; private ResourceRef _font; private ResourceRef _icon; - private Logger _logger = new(nameof(TestGame)); } \ No newline at end of file diff --git a/Voile/Source/Game.cs b/Voile/Source/Game.cs index 52972df..00949b3 100644 --- a/Voile/Source/Game.cs +++ b/Voile/Source/Game.cs @@ -1,43 +1,51 @@ using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using Voile.Input; using Voile.Rendering; using Voile.Resources; namespace Voile { + public interface IGame + { + string Name { get; } + /// + /// Resource root path for this game. + /// + string ResourceRoot { get; } + void Start(); + void Run(); + void Shutdown(); + } + /// /// Entry point for the Voile game. /// - public abstract class Game + public abstract class Game : IGame { + public double UpdateTimeStep { get; set; } = 1.0 / 60.0; + public TimeSpan UpdateFrameTime { get; private set; } + public TimeSpan RenderFrameTime { get; private set; } + /// /// The ResourceManager associated with this game. /// - protected ResourceManager ResourceManager { get; private set; } + protected ResourceManager ResourceManager { get; private set; } = new(); /// /// The InputHandler associated with this game. Uses by default. /// - protected InputSystem Input { get; private set; } + protected InputSystem? Input { get; set; } /// /// The Renderer associated with this game. Uses by default. /// - protected RenderSystem Renderer { get; private set; } - - /// - /// Resource root path for this game. - /// - public virtual string ResourceRoot => "Resources/"; - - /// - /// Path to the engine configuration file. - /// - public virtual string EngineConfigPath => "engine.config"; + protected RenderSystem? Renderer { get; set; } /// /// Name of this game. Also used as a default window title. /// - public virtual string Name => ""; + public virtual string Name => "Voile Game"; + public virtual string ResourceRoot => "Resources/"; /// /// Default game constructor. @@ -45,19 +53,16 @@ namespace Voile public Game() { ResourceManager = new ResourceManager(); - Input = new RaylibInputSystem(); - Renderer = new RaylibRenderSystem(); + Initialize(); } /// /// Game constructor with custom systems. /// - /// /// /// - public Game(ResourceManager resourceManager, InputSystem inputSystem, RenderSystem renderSystem) + public Game(InputSystem inputSystem, RenderSystem renderSystem) { - ResourceManager = resourceManager; Input = inputSystem; Renderer = renderSystem; } @@ -83,83 +88,77 @@ namespace Voile throw new NullReferenceException("No ResourceManager provided."); } - Initialize(); + LoadResources(); Ready(); Run(); Shutdown(); } /// - /// Initializes subsystems using default types and settings. + /// Initializes systems using default types and settings. /// - public void InitializeDefault() + public void InitializeSystemsDefault() { ResourceManager.ResourceRoot = ResourceRoot; - Input = new RaylibInputSystem(); - Renderer = new RaylibRenderSystem(); + if (Renderer is null) + { + Renderer = new RaylibRenderSystem(); + } + + if (Input is null) + { + Input = new RaylibInputSystem(); + } Input.Start(); - InitializeRenderer(); } public void ShutdownDefault() { - Input.Dispose(); - Renderer.Dispose(); + Input?.Dispose(); + Renderer?.Dispose(); ResourceManager.Dispose(); } /// - /// Called when it's time to initialize the subsystems, or modify default game settings or system settings. + /// Adds a system that will start together with the game. /// - public abstract void Initialize(); + /// + public void AddSystem([DisallowNull] IStartableSystem system) + { + _startableSystems.Add(system); + } + /// - /// Called when it's safe to manipulate the resources or/and systems. - /// You can safely create game objects, scenes, etc. in this method. + /// Adds a system to the Update step. /// - protected abstract void Ready(); + /// + public void AddSystemToUpdate([DisallowNull] IUpdatableSystem system) + { + _updatableSystems.Add(system); + } + + /// + /// Adds a system to the render step. + /// + /// + public void AddSystemToRender([DisallowNull] IUpdatableSystem system) + { + _renderableSystems.Add(system); + } + /// /// Called when everything has been readied to start the main loop. /// - protected abstract void Run(); - /// - /// Called when the application quits and it's safe to clean up. - /// - public abstract void Shutdown(); - - private void InitializeRenderer() + public void Run() { - var windowSettings = WindowSettings.Default; + if (Renderer is null) + { + throw new NullReferenceException("No renderer provided."); + } - if (!string.IsNullOrWhiteSpace(Name)) - windowSettings.Title = Name; - - Renderer.Start(RendererSettings.Default); - } - } - - public abstract class BaseGame : Game - { - public double UpdateTimeStep { get; set; } = 1.0 / 60.0; - public TimeSpan UpdateFrameTime { get; private set; } - public TimeSpan RenderFrameTime { get; private set; } - public override void Initialize() - { - LoadResources(); - InitializeDefault(); - } - - public override void Shutdown() => ShutdownDefault(); - - /// - /// Called when it's time to load the game's resources, such as images or sounds. - /// - protected abstract void LoadResources(); - - protected override void Run() - { Stopwatch stopwatch = Stopwatch.StartNew(); double previousTime = stopwatch.Elapsed.TotalSeconds; @@ -173,11 +172,22 @@ namespace Voile while (_accumulator >= UpdateTimeStep) { + foreach (var system in _updatableSystems) + { + system.Update(UpdateTimeStep); + } + Update(UpdateTimeStep); _accumulator -= UpdateTimeStep; } Renderer.BeginFrame(); + + foreach (var system in _renderableSystems) + { + system.Update(Renderer.FrameTime); + } + Render(Renderer.FrameTime); Renderer.EndFrame(); @@ -185,6 +195,21 @@ namespace Voile } } + /// + /// Called when it's time to initialize the subsystems, or modify default game settings or system settings. + /// + public abstract void Initialize(); + /// + /// Called when it's safe to manipulate the resources or/and systems. + /// You can safely create game objects, scenes, etc. in this method. + /// + protected abstract void Ready(); + + /// + /// Called when it's time to load the game's resources, such as images or sounds. + /// + protected abstract void LoadResources(); + /// /// Triggered on each fixed timestep. Update your game's state here. /// @@ -196,6 +221,28 @@ namespace Voile /// protected abstract void Render(double deltaTime); + /// + /// Called when the application quits and it's safe to clean up. + /// + public abstract void Shutdown(); + + private void InitializeRenderer() + { + var windowSettings = WindowSettings.Default; + + if (!string.IsNullOrWhiteSpace(Name)) + windowSettings.Title = Name; + + var renderSettings = RendererSettings.Default; + renderSettings.WindowSettings = windowSettings; + + Renderer?.Start(renderSettings); + } + + private List _startableSystems = new(); + private List _updatableSystems = new(); + private List _renderableSystems = new(); + private double _accumulator; } } \ No newline at end of file