fixed scene management; but now I need to improve component management (see todo in Program.cs

This commit is contained in:
2025-12-21 12:02:45 +01:00
parent ad5d46ff0e
commit 4e6fd1f52f
12 changed files with 96 additions and 37 deletions

View File

@@ -1,6 +1,6 @@
namespace EngineSharp.Core.ECS;
public interface IComponent
public abstract class Component
{
}

View File

@@ -1,6 +1,6 @@
namespace EngineSharp.Core.ECS;
public abstract class DataComponent : IComponent
public abstract class DataComponent : Component
{
}

View File

@@ -22,12 +22,12 @@ public struct Entity
/// <summary>
/// If the component already exists on the entity, it will not be added.
/// </summary>
public void AddComponent(IComponent component)
public void AddComponent(Component component)
{
_scene.AddComponent(this, component);
}
public IComponent? GetComponent(IComponent component)
public Component? GetComponent(Component component)
{
return _scene.GetComponent(this, component);
}

View File

@@ -1,6 +1,6 @@
namespace EngineSharp.Core.ECS;
public abstract class LogicComponent : IComponent // Kinda like Unity's MonoBehaviour
public abstract class LogicComponent : Component // Kinda like Unity's MonoBehaviour
{
public abstract void Initialise();
public abstract void OnUpdate(double deltaTime);

View File

@@ -3,7 +3,7 @@ using Silk.NET.OpenGL;
namespace EngineSharp.Core.ECS;
public abstract class RenderComponent : IComponent
public abstract class RenderComponent : Component
{
internal abstract void Render(GL gl, Matrix4X4<float> projectionMatrix, Matrix4X4<float> viewMatrix, Matrix4X4<float> modelMatrix);
}

View File

@@ -54,7 +54,7 @@ public class Scene
/// If the component already exists on the entity, it will not be added
/// </summary>
internal void AddComponent<T>(Entity entity, T component)
where T : class, IComponent
where T : Component
{
switch (component)
{
@@ -71,7 +71,7 @@ public class Scene
}
internal T? GetComponent<T>(Entity entity, T component)
where T : class, IComponent
where T : Component
{
return component switch
{
@@ -83,7 +83,7 @@ public class Scene
}
private static TComponent? GetComponent<TComponent, TArchetype>(long id, Dictionary<long, List<TArchetype>> componentStore)
where TComponent : class, IComponent
where TComponent : Component
{
// ReSharper disable once ConvertIfStatementToReturnStatement
if (componentStore.TryGetValue(id, out var components))
@@ -98,7 +98,7 @@ public class Scene
/// If the component already exists on the entity, it will not be added
/// </summary>
private static void AddComponent<TComponent, TArchetype>(long id, TComponent component, Dictionary<long, List<TArchetype>> componentStore)
where TArchetype : class, IComponent
where TArchetype : Component
where TComponent : TArchetype
{
if (componentStore.TryGetValue(id, out var components) && !components.OfType<TComponent>().Any())

View File

@@ -1,6 +1,4 @@
using System;
using EngineSharp.Core.ECS;
using EngineSharp.Core.Rendering;
using EngineSharp.Core.Rendering;
using Silk.NET.Windowing;
namespace EngineSharp.Core;
@@ -9,10 +7,7 @@ public interface IEngine
{
void Start();
void Stop();
Scene CreateScene();
void SetCurrentScene(Scene scene);
Shader GetShader(string vertexShaderPath);
}

View File

@@ -12,7 +12,7 @@ namespace EngineSharp.Core;
internal class OpenGLEngine : Engine
{
private readonly IWindow _window;
private readonly List<Scene> _scenes;
private readonly Dictionary<string, Scene> _scenes;
private GL _gl = null!; // because between constructing the engine and OnLoad being called nothing should call these fields. Therefore, we do "!" to get rid of warnings
private Input _input = null!;
private PerspectiveCamera _camera = null!;
@@ -47,16 +47,6 @@ internal class OpenGLEngine : Engine
_window.Close();
}
// TODO: pass in name as parameter
// Name must be unique and is used to switch scenes while the application is running.
// We need exactly one default scene which is the initial scene (call SetCurrentScene during the Load() method
public override Scene CreateScene()
{
var scene = new Scene();
_scenes.Add(scene);
return scene;
}
private void InitialiseShaders(IEnumerable<string> vertexShaderFiles)
{
foreach (var vertexShaderFile in vertexShaderFiles)
@@ -69,14 +59,37 @@ internal class OpenGLEngine : Engine
}
}
public override void SetCurrentScene(Scene scene)
internal override Scene CreateScene(string name)
{
_currentScene = scene;
_currentScene.InitialiseComponents();
var scene = new Scene();
if (!_scenes.TryAdd(name, scene))
{
throw new ArgumentException($"Scene '{name}' already exists.");
}
return scene;
}
internal override void SetCurrentScene(string sceneName)
{
if (_scenes.TryGetValue(sceneName, out var scene))
{
_currentScene = scene;
_currentScene.InitialiseComponents();
}
else
{
throw new ArgumentException($"Scene '{sceneName}' does not exist.");
}
}
private void OnLoad()
{
if (string.IsNullOrEmpty(_defaultSceneName))
{
throw new InvalidOperationException("No default scene defined.");
}
_gl = _window.CreateOpenGL();
_input = new Input(_window.CreateInput());
@@ -86,7 +99,7 @@ internal class OpenGLEngine : Engine
_camera = new PerspectiveCamera(Vector3D<float>.Zero, _window.FramebufferSize);
InitialiseShaders(Directory.GetFiles("./assets/shaders", "*.vert"));
// TODO: SetCurrentScene -> with the default scene
SetCurrentScene(_defaultSceneName);
}
private void OnUpdate(double deltaTime)

View File

@@ -13,14 +13,28 @@ internal abstract class Engine : IEngine
}
protected readonly Dictionary<string, Shader> _shaders = [];
protected string? _defaultSceneName;
public static Engine Instance => SingletonInstance ?? throw new InvalidOperationException("No engine has been created yet. Cannot return an instance.");
public abstract void Start();
public abstract void Stop();
public abstract Scene CreateScene();
public abstract void SetCurrentScene(Scene scene);
internal abstract Scene CreateScene(string name);
internal abstract void SetCurrentScene(string sceneName);
internal Scene CreateScene(string sceneName, bool isDefaultScene)
{
if (isDefaultScene && !string.IsNullOrEmpty(_defaultSceneName))
{
throw new InvalidOperationException(
$"A default scene already exists, cannot create a new one. Name of the current default scene: '{_defaultSceneName}'.");
}
_defaultSceneName = sceneName;
return CreateScene(sceneName);
}
public Shader GetShader(string vertexShaderPath)
{
Instance._shaders.TryGetValue(vertexShaderPath, out var shader);

View File

@@ -0,0 +1,35 @@
using EngineSharp.Core.ECS;
using EngineSharp.Core.Rendering;
namespace EngineSharp.Core;
public static class SceneManager
{
private static bool DefaultSceneCreated = false;
/// <summary>
/// Creates the scene that will be loaded once the game is started. <br/>
/// Can only be called once.
/// </summary>
/// <param name="sceneName"></param>
public static Scene CreateDefaultScene(string sceneName)
{
if (DefaultSceneCreated)
{
throw new InvalidOperationException("Default scene has already been created.");
}
var scene = Engine.Instance.CreateScene(sceneName, true);
return scene;
}
public static Scene CreateScene(string sceneName)
{
return Engine.Instance.CreateScene(sceneName);
}
public static void SetCurrentScene(string sceneName)
{
Engine.Instance.SetCurrentScene(sceneName);
}
}

View File

@@ -1,4 +1,5 @@
using Engine_silk.NET;
using EngineSharp.Core;
using EngineSharp.Core.Rendering;
namespace EngineSharp;
@@ -19,6 +20,7 @@ public class Planet : Core.ECS.LogicComponent
Resolution = 10,
Material = material,
};
PlanetMesh = new MeshRenderer
{
Mesh = sphereGenerator.CreateSphere(),

View File

@@ -17,12 +17,12 @@ internal static class Program
};
var engine = EngineFactory.Create(GraphicsAPI.OpenGL, options);
var mainScene = engine.CreateScene();
var mainScene = SceneManager.CreateDefaultScene("default");
var planet = mainScene.CreateEntity("planet");
// TODO: Find a way to call "AddComponent" from a component. Otherwise the MeshRenderer I created inside the Planet-Component doesn't get registered and can't therefore be rendered
planet.AddComponent(new Planet());
engine.SetCurrentScene(mainScene);
engine.Start();
}
}