Update Game, add IGame.

This commit is contained in:
2024-10-17 22:33:21 +02:00
parent 8f4f1a3c24
commit ae0a68c332
2 changed files with 134 additions and 84 deletions

View File

@@ -1,16 +1,29 @@
using Voile; using Voile;
using Voile.Resources; using Voile.Resources;
using Voile.Utils;
using Voile.Input; using Voile.Input;
using Voile.Systems.Particles; using Voile.Systems.Particles;
using System.Numerics; using System.Numerics;
using System.Diagnostics.CodeAnalysis; 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 string ResourceRoot => "Resources/";
public override void Initialize()
{
InitializeSystemsDefault();
_particleSystem = new ParticleSystem();
AddSystemToUpdate(_particleSystem);
}
public override void Shutdown()
{
ShutdownDefault();
}
protected override void LoadResources() protected override void LoadResources()
{ {
ResourceManager.AddResourceLoaderAssociation(new ParticleEmitterSettingsResourceLoader()); ResourceManager.AddResourceLoaderAssociation(new ParticleEmitterSettingsResourceLoader());
@@ -30,19 +43,14 @@ public class TestGame : BaseGame
protected override void Ready() protected override void Ready()
{ {
_particleSystem = new ParticleSystem();
Input.AddInputMapping("reload", new InputAction[] { new KeyInputAction(KeyboardKey.R) }); Input.AddInputMapping("reload", new InputAction[] { new KeyInputAction(KeyboardKey.R) });
_particleSimStopwatch = new Stopwatch();
_emitterId = _particleSystem.CreateEmitter(Renderer.WindowSize / 2, _fireEffect); _emitterId = _particleSystem.CreateEmitter(Renderer.WindowSize / 2, _fireEffect);
} }
protected override void Update(double deltaTime) protected override void Update(double deltaTime)
{ {
_particleSimStopwatch = Stopwatch.StartNew();
_particleSystem!.Update(deltaTime);
_particleSimStopwatch.Stop();
} }
protected override void Render(double deltaTime) protected override void Render(double deltaTime)
@@ -70,18 +78,16 @@ public class TestGame : BaseGame
} }
Renderer.ResetTransform(); 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.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); Renderer.DrawText(_font, $"Update: {UpdateTimeStep * 1000:F1} ms", Color.White);
} }
private void DrawEmitter(ParticleEmitter emitter) private void DrawEmitter(ParticleEmitter emitter)
{ {
Renderer.BeginBlended(Voile.Rendering.BlendMode.BlendAlpha); Renderer.BeginBlended(BlendMode.BlendAlpha);
var maxParticles = emitter.Settings.MaxParticles; var maxParticles = emitter.Settings.MaxParticles;
var particleSize = new Vector2(16.0f, 16.0f); var particleSize = new Vector2(16.0f, 16.0f);
@@ -99,11 +105,8 @@ public class TestGame : BaseGame
} }
[NotNull] private ParticleSystem _particleSystem; [NotNull] private ParticleSystem _particleSystem;
private Stopwatch _particleSimStopwatch;
private int _emitterId; private int _emitterId;
private ResourceRef<ParticleEmitterSettingsResource> _fireEffect; private ResourceRef<ParticleEmitterSettingsResource> _fireEffect;
private ResourceRef<Font> _font; private ResourceRef<Font> _font;
private ResourceRef<Texture2d> _icon; private ResourceRef<Texture2d> _icon;
private Logger _logger = new(nameof(TestGame));
} }

View File

@@ -1,43 +1,51 @@
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Voile.Input; using Voile.Input;
using Voile.Rendering; using Voile.Rendering;
using Voile.Resources; using Voile.Resources;
namespace Voile namespace Voile
{ {
public interface IGame
{
string Name { get; }
/// <summary>
/// Resource root path for this game.
/// </summary>
string ResourceRoot { get; }
void Start();
void Run();
void Shutdown();
}
/// <summary> /// <summary>
/// Entry point for the Voile game. /// Entry point for the Voile game.
/// </summary> /// </summary>
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; }
/// <summary> /// <summary>
/// The ResourceManager associated with this game. /// The ResourceManager associated with this game.
/// </summary> /// </summary>
protected ResourceManager ResourceManager { get; private set; } protected ResourceManager ResourceManager { get; private set; } = new();
/// <summary> /// <summary>
/// The InputHandler associated with this game. Uses <see cref="RaylibInputSystem"/> by default. /// The InputHandler associated with this game. Uses <see cref="RaylibInputSystem"/> by default.
/// </summary> /// </summary>
protected InputSystem Input { get; private set; } protected InputSystem? Input { get; set; }
/// <summary> /// <summary>
/// The Renderer associated with this game. Uses <see cref="RaylibRenderSystem"/> by default. /// The Renderer associated with this game. Uses <see cref="RaylibRenderSystem"/> by default.
/// </summary> /// </summary>
protected RenderSystem Renderer { get; private set; } protected RenderSystem? Renderer { get; set; }
/// <summary>
/// Resource root path for this game.
/// </summary>
public virtual string ResourceRoot => "Resources/";
/// <summary>
/// Path to the engine configuration file.
/// </summary>
public virtual string EngineConfigPath => "engine.config";
/// <summary> /// <summary>
/// Name of this game. Also used as a default window title. /// Name of this game. Also used as a default window title.
/// </summary> /// </summary>
public virtual string Name => ""; public virtual string Name => "Voile Game";
public virtual string ResourceRoot => "Resources/";
/// <summary> /// <summary>
/// Default game constructor. /// Default game constructor.
@@ -45,19 +53,16 @@ namespace Voile
public Game() public Game()
{ {
ResourceManager = new ResourceManager(); ResourceManager = new ResourceManager();
Input = new RaylibInputSystem(); Initialize();
Renderer = new RaylibRenderSystem();
} }
/// <summary> /// <summary>
/// Game constructor with custom systems. /// Game constructor with custom systems.
/// </summary> /// </summary>
/// <param name="resourceManager"></param>
/// <param name="inputSystem"></param> /// <param name="inputSystem"></param>
/// <param name="renderSystem"></param> /// <param name="renderSystem"></param>
public Game(ResourceManager resourceManager, InputSystem inputSystem, RenderSystem renderSystem) public Game(InputSystem inputSystem, RenderSystem renderSystem)
{ {
ResourceManager = resourceManager;
Input = inputSystem; Input = inputSystem;
Renderer = renderSystem; Renderer = renderSystem;
} }
@@ -83,83 +88,77 @@ namespace Voile
throw new NullReferenceException("No ResourceManager provided."); throw new NullReferenceException("No ResourceManager provided.");
} }
Initialize(); LoadResources();
Ready(); Ready();
Run(); Run();
Shutdown(); Shutdown();
} }
/// <summary> /// <summary>
/// Initializes subsystems using default types and settings. /// Initializes systems using default types and settings.
/// </summary> /// </summary>
public void InitializeDefault() public void InitializeSystemsDefault()
{ {
ResourceManager.ResourceRoot = ResourceRoot; ResourceManager.ResourceRoot = ResourceRoot;
Input = new RaylibInputSystem(); if (Renderer is null)
Renderer = new RaylibRenderSystem(); {
Renderer = new RaylibRenderSystem();
}
if (Input is null)
{
Input = new RaylibInputSystem();
}
Input.Start(); Input.Start();
InitializeRenderer(); InitializeRenderer();
} }
public void ShutdownDefault() public void ShutdownDefault()
{ {
Input.Dispose(); Input?.Dispose();
Renderer.Dispose(); Renderer?.Dispose();
ResourceManager.Dispose(); ResourceManager.Dispose();
} }
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
public abstract void Initialize(); /// <param name="system"></param>
public void AddSystem([DisallowNull] IStartableSystem system)
{
_startableSystems.Add(system);
}
/// <summary> /// <summary>
/// Called when it's safe to manipulate the resources or/and systems. /// Adds a system to the Update step.
/// You can safely create game objects, scenes, etc. in this method.
/// </summary> /// </summary>
protected abstract void Ready(); /// <param name="system"></param>
public void AddSystemToUpdate([DisallowNull] IUpdatableSystem system)
{
_updatableSystems.Add(system);
}
/// <summary>
/// Adds a system to the render step.
/// </summary>
/// <param name="system"></param>
public void AddSystemToRender([DisallowNull] IUpdatableSystem system)
{
_renderableSystems.Add(system);
}
/// <summary> /// <summary>
/// Called when everything has been readied to start the main loop. /// Called when everything has been readied to start the main loop.
/// </summary> /// </summary>
protected abstract void Run(); public void Run()
/// <summary>
/// Called when the application quits and it's safe to clean up.
/// </summary>
public abstract void Shutdown();
private void InitializeRenderer()
{ {
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();
/// <summary>
/// Called when it's time to load the game's resources, such as images or sounds.
/// </summary>
protected abstract void LoadResources();
protected override void Run()
{
Stopwatch stopwatch = Stopwatch.StartNew(); Stopwatch stopwatch = Stopwatch.StartNew();
double previousTime = stopwatch.Elapsed.TotalSeconds; double previousTime = stopwatch.Elapsed.TotalSeconds;
@@ -173,11 +172,22 @@ namespace Voile
while (_accumulator >= UpdateTimeStep) while (_accumulator >= UpdateTimeStep)
{ {
foreach (var system in _updatableSystems)
{
system.Update(UpdateTimeStep);
}
Update(UpdateTimeStep); Update(UpdateTimeStep);
_accumulator -= UpdateTimeStep; _accumulator -= UpdateTimeStep;
} }
Renderer.BeginFrame(); Renderer.BeginFrame();
foreach (var system in _renderableSystems)
{
system.Update(Renderer.FrameTime);
}
Render(Renderer.FrameTime); Render(Renderer.FrameTime);
Renderer.EndFrame(); Renderer.EndFrame();
@@ -185,6 +195,21 @@ namespace Voile
} }
} }
/// <summary>
/// Called when it's time to initialize the subsystems, or modify default game settings or system settings.
/// </summary>
public abstract void Initialize();
/// <summary>
/// Called when it's safe to manipulate the resources or/and systems.
/// You can safely create game objects, scenes, etc. in this method.
/// </summary>
protected abstract void Ready();
/// <summary>
/// Called when it's time to load the game's resources, such as images or sounds.
/// </summary>
protected abstract void LoadResources();
/// <summary> /// <summary>
/// Triggered on each fixed timestep. Update your game's state here. /// Triggered on each fixed timestep. Update your game's state here.
/// </summary> /// </summary>
@@ -196,6 +221,28 @@ namespace Voile
/// <param name="deltaTime"></param> /// <param name="deltaTime"></param>
protected abstract void Render(double deltaTime); protected abstract void Render(double deltaTime);
/// <summary>
/// Called when the application quits and it's safe to clean up.
/// </summary>
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<IStartableSystem> _startableSystems = new();
private List<IUpdatableSystem> _updatableSystems = new();
private List<IUpdatableSystem> _renderableSystems = new();
private double _accumulator; private double _accumulator;
} }
} }