Make most subsystems available as protected properties in base Game class, implement IDisposable on systems.

This commit is contained in:
2024-08-22 21:47:57 +02:00
parent c61a12d170
commit 03e7a4a90c
11 changed files with 136 additions and 65 deletions

View File

@@ -4,7 +4,7 @@ namespace Voile.Audio
{
public abstract void Initialize();
public abstract void Update();
public abstract void Shutdown();
protected abstract void Shutdown();
// BUS
public abstract void CreateBus(string busName);
public abstract void SetBusVolume(string busName, float volume);
@@ -26,6 +26,7 @@ namespace Voile.Audio
public void Dispose()
{
Shutdown();
GC.SuppressFinalize(this);
}
private LehmerRandom _random = new LehmerRandom();

View File

@@ -27,7 +27,7 @@ namespace Voile.Audio
return;
}
public override void Shutdown()
protected override void Shutdown()
{
return;
}

View File

@@ -71,6 +71,11 @@ namespace Voile.Audio
channelGroup.addDSP(0, dsp);
}
protected override void Shutdown()
{
}
private DSP CreateReverbDsp(AudioEffectReverb effectReverb)
{
DSP dsp;
@@ -122,11 +127,6 @@ namespace Voile.Audio
return _channelGroups[busName];
}
public override void Shutdown()
{
}
private FMOD.System _system;
// TODO: use a different key for the dictionary, paths are not good :( (waste of memory lol)

View File

@@ -1,3 +1,4 @@
using Voile.Rendering;
using Voile.Resources;
namespace Voile
@@ -8,12 +9,36 @@ namespace Voile
/// The ResourceManager associated with this game.
/// </summary>
protected ResourceManager ResourceManager { get; private set; }
public abstract string ResourceRoot { get; }
/// <summary>
/// The InputHandler associated with this game. Uses <see cref="RaylibInputHandler"/> by default.
/// </summary>
protected InputHandler Input { get; private set; }
/// <summary>
/// The Renderer associated with this game. Uses <see cref="RaylibRenderer"/> by default.
/// </summary>
protected Renderer Renderer { get; private 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>
/// Name of this game. Also used as a default window title.
/// </summary>
public virtual string Name => "";
public Game()
{
ResourceManager = new ResourceManager();
Input = new RaylibInputHandler();
Renderer = new RaylibRenderer();
}
/// <summary>
@@ -22,8 +47,6 @@ namespace Voile
/// </summary>
public void Start()
{
Configure();
Initialize();
LoadResources();
Ready();
@@ -32,15 +55,36 @@ namespace Voile
}
/// <summary>
/// Called when it's time to initialize the subsystems.
/// Initializes subsystems using default types and settings.
/// </summary>
public void InitializeDefault()
{
ResourceManager.ResourceRoot = ResourceRoot;
Input = new RaylibInputHandler();
Renderer = new RaylibRenderer();
InitializeRenderer();
}
public void ShutdownDefault()
{
Input.Dispose();
Renderer.Dispose();
ResourceManager.Dispose();
}
/// <summary>
/// Called when it's time to initialize the subsystems, or modify default game settings or systems.
/// </summary>
public abstract void Initialize();
/// <summary>
/// Called when it's time to load the application's resources, such as images or sounds.
/// Called when it's time to load the game's resources, such as images or sounds.
/// </summary>
protected abstract void LoadResources();
/// <summary>
/// Called when it's safe to manipulate with the resources or/and systems.
/// You can safely create game objects, scenes, etc. in this method.
/// </summary>
protected abstract void Ready();
/// <summary>
@@ -52,9 +96,14 @@ namespace Voile
/// </summary>
public abstract void Shutdown();
private void Configure()
private void InitializeRenderer()
{
ResourceManager.ResourceRoot = ResourceRoot;
var windowSettings = WindowSettings.Default;
if (!string.IsNullOrWhiteSpace(Name))
windowSettings.Title = Name;
Renderer.CreateAndInitialize(windowSettings, RendererSettings.Default);
}
}
}

View File

@@ -4,14 +4,18 @@ using Voile.Utils;
namespace Voile
{
public abstract class InputHandler
public abstract class InputHandler : IDisposable
{
public static IReadOnlyDictionary<string, List<InputAction>> InputMappings => inputMappings;
public InputHandler()
{
inputMappings = new Dictionary<string, IEnumerable<InputAction>>();
inputMappings = new Dictionary<string, List<InputAction>>();
CreateDefaultMappings();
}
public Action OnInput;
public void Dispose() => GC.SuppressFinalize(this);
public bool Handled { get => _handled; set => _handled = value; }
public abstract bool IsKeyboardKeyDown(KeyboardKey key);
public abstract bool KeyboardKeyJustPressed(KeyboardKey key);
@@ -36,7 +40,7 @@ namespace Voile
public void AddInputMapping(string actionName, IEnumerable<InputAction> inputActions)
{
inputMappings.Add(actionName, inputActions);
inputMappings.Add(actionName, inputActions.ToList());
}
private void CreateDefaultMappings()
@@ -75,9 +79,9 @@ namespace Voile
return true;
}
private bool _handled;
protected Dictionary<string, IEnumerable<InputAction>> inputMappings;
protected static Dictionary<string, List<InputAction>> inputMappings = new();
private bool _handled;
private Logger _logger = new(nameof(InputHandler));
}

View File

@@ -100,7 +100,6 @@ namespace Voile
public override bool IsKeyboardKeyDown(KeyboardKey key)
{
Raylib_cs.KeyboardKey rayKey = (Raylib_cs.KeyboardKey)key;
OnInput?.Invoke();
return Raylib.IsKeyDown(rayKey);
}

View File

@@ -82,7 +82,7 @@ namespace Voile.Rendering
return Raylib.WindowShouldClose();
}
public override void Shutdown()
protected override void Shutdown()
{
Raylib.CloseWindow();
}

View File

@@ -5,7 +5,7 @@ namespace Voile.Rendering
/// <summary>
/// An abstract class representing the graphics renderer.
/// </summary>
public abstract class Renderer
public abstract class Renderer : IDisposable
{
// INIT
/// <summary>
@@ -46,6 +46,13 @@ namespace Voile.Rendering
/// </summary>
public abstract Vector2 MonitorSize { get; }
/// <inheritdoc/>
public void Dispose()
{
Shutdown();
GC.SuppressFinalize(this);
}
/// <summary>
/// Creates a window.
/// </summary>
@@ -59,7 +66,7 @@ namespace Voile.Rendering
protected abstract int GetMonitorHeight(int monitorId);
protected abstract int GetCurrentMonitor();
protected abstract bool WindowShouldClose();
public abstract void Shutdown();
protected abstract void Shutdown();
// DRAWING
/// <summary>
@@ -171,7 +178,7 @@ namespace Voile.Rendering
public struct WindowSettings
{
public string Title;
public Vector2 Size = new Vector2(640, 480);
public Vector2 Size = new Vector2(1280, 720);
public bool Resizable { get; set; }
public WindowSettings(string title, Vector2 size)
@@ -179,5 +186,7 @@ namespace Voile.Rendering
Title = title;
Size = size;
}
public static WindowSettings Default => new("Voile Game", new Vector2(1280, 720));
}
}

View File

@@ -130,7 +130,7 @@ namespace Voile.Rendering
/// <inheritdoc />
public override void Shutdown()
protected override void Shutdown()
{
_window!.DoEvents();
_window.Reset();

View File

@@ -4,7 +4,7 @@ using Voile.Utils;
namespace Voile.Resources
{
public class ResourceManager
public class ResourceManager : IDisposable
{
public string ResourceRoot { get; set; } = "Resources/";
@@ -49,6 +49,24 @@ namespace Voile.Resources
return true;
}
public bool TryUnload(string resourceId)
{
_logger.Info($"Unloading resource with id \"{resourceId}\"...");
if (!_loadedResources.ContainsKey(resourceId))
{
_logger.Error($"Cannot unload resource with id \"{resourceId}\": resource doesn't exist!");
return false;
}
var resource = _loadedResources[resourceId];
_loadedResources.Remove(resourceId);
resource.Dispose();
return true;
}
public bool TrySave<T>(string path, in T resource) where T : Resource
{
if (!TryGetSaver(out IResourceSaver<T>? saver))
@@ -151,6 +169,17 @@ namespace Voile.Resources
return true;
}
public void Dispose()
{
foreach (var resource in _loadedResources)
{
TryUnload(resource.Key);
}
GC.SuppressFinalize(this);
}
private Logger _logger = new(nameof(ResourceManager));
private readonly Dictionary<Type, object> _resourceLoaderAssociations = new()