Ecs changes

- BitArray has always at least sizeof(uint) bits
- Renamed Entity to EcsEntity
- Added value parameter to EcsWorld.AssignComponent
- Matched EcsWorld generic parameters
- Added Scene
- Added Entity
This commit is contained in:
Simon Lübeß
2022-02-28 23:34:52 +01:00
parent ba5ccd7107
commit 9197a209d6
16 changed files with 270 additions and 100 deletions
@@ -26,7 +26,7 @@ namespace GlitchyEditor.EditWindows
if(_editor.SelectedEntities.Count == 1) if(_editor.SelectedEntities.Count == 1)
{ {
Entity entity = _editor.SelectedEntities.Front; EcsEntity entity = _editor.SelectedEntities.Front;
ShowComponents(entity); ShowComponents(entity);
} }
@@ -34,7 +34,7 @@ namespace GlitchyEditor.EditWindows
ImGui.End(); ImGui.End();
} }
private void ShowComponents(Entity entity) private void ShowComponents(EcsEntity entity)
{ {
NameComponentEditor.Show(_editor.World, entity); NameComponentEditor.Show(_editor.World, entity);
TransformComponentEditor.Show(_editor.World, entity); TransformComponentEditor.Show(_editor.World, entity);
@@ -43,7 +43,7 @@ namespace GlitchyEditor.EditWindows
static class NameComponentEditor static class NameComponentEditor
{ {
public static void Show(EcsWorld world, Entity entity) public static void Show(EcsWorld world, EcsEntity entity)
{ {
char8[128] nameBuffer = default; char8[128] nameBuffer = default;
@@ -78,7 +78,7 @@ namespace GlitchyEditor.EditWindows
static class TransformComponentEditor static class TransformComponentEditor
{ {
public static void Show(EcsWorld world, Entity entity) public static void Show(EcsWorld world, EcsEntity entity)
{ {
TransformComponent* component = world.GetComponent<TransformComponent>(entity); TransformComponent* component = world.GetComponent<TransformComponent>(entity);
@@ -111,7 +111,7 @@ namespace GlitchyEditor.EditWindows
} }
} }
private void ImGuiPrintEntityTree(TreeNode<Entity> tree) private void ImGuiPrintEntityTree(TreeNode<EcsEntity> tree)
{ {
String name = null; String name = null;
@@ -140,7 +140,7 @@ namespace GlitchyEditor.EditWindows
if(ImGui.BeginDragDropSource()) if(ImGui.BeginDragDropSource())
{ {
ImGui.SetDragDropPayload("DND_Entity", &tree.Value, sizeof(Entity)); ImGui.SetDragDropPayload("DND_Entity", &tree.Value, sizeof(EcsEntity));
ImGui.Text(name); ImGui.Text(name);
@@ -153,13 +153,13 @@ namespace GlitchyEditor.EditWindows
if(payload != null) if(payload != null)
{ {
Log.ClientLogger.AssertDebug(payload.DataSize == sizeof(Entity)); Log.ClientLogger.AssertDebug(payload.DataSize == sizeof(EcsEntity));
Entity movedEntity = *(Entity*)payload.Data; EcsEntity movedEntity = *(EcsEntity*)payload.Data;
bool dropLegal = true; bool dropLegal = true;
Entity walker = tree.Value; EcsEntity walker = tree.Value;
// make sure the dropped entity is not a parent of the entity we dropped it on. // make sure the dropped entity is not a parent of the entity we dropped it on.
while(true) while(true)
@@ -230,9 +230,9 @@ namespace GlitchyEditor.EditWindows
{ {
// Show entity hierarchy as tree // Show entity hierarchy as tree
TreeNode<Entity> root = scope .(.InvalidEntity); TreeNode<EcsEntity> root = scope .(.InvalidEntity);
TreeNode<Entity> AddEntity(Entity entity) TreeNode<EcsEntity> AddEntity(EcsEntity entity)
{ {
var parent = _editor.World.GetComponent<ParentComponent>(entity); var parent = _editor.World.GetComponent<ParentComponent>(entity);
@@ -264,9 +264,9 @@ namespace GlitchyEditor.EditWindows
if(payload != null) if(payload != null)
{ {
Log.ClientLogger.AssertDebug(payload.DataSize == sizeof(Entity)); Log.ClientLogger.AssertDebug(payload.DataSize == sizeof(EcsEntity));
Entity movedEntity = *(Entity*)payload.Data; EcsEntity movedEntity = *(EcsEntity*)payload.Data;
_editor.World.RemoveComponent<ParentComponent>(movedEntity); _editor.World.RemoveComponent<ParentComponent>(movedEntity);
+18 -16
View File
@@ -9,26 +9,28 @@ namespace GlitchyEditor
{ {
class Editor class Editor
{ {
private EcsWorld _world; private EcsWorld _ecsWorld;
private Scene _scene;
private EntityHierarchyWindow _entityHierarchyWindow = new .(this) ~ delete _; private EntityHierarchyWindow _entityHierarchyWindow = new .(this) ~ delete _;
private ComponentEditWindow _componentEditWindow = new .(this) ~ delete _; private ComponentEditWindow _componentEditWindow = new .(this) ~ delete _;
private SceneViewportWindow _sceneViewportWindow = new .(this) ~ delete _; private SceneViewportWindow _sceneViewportWindow = new .(this) ~ delete _;
private List<Entity> _selectedEntities = new .() ~ delete _; private List<EcsEntity> _selectedEntities = new .() ~ delete _;
public EcsWorld World => _world; public EcsWorld World => _ecsWorld;
public List<Entity> SelectedEntities => _selectedEntities; public List<EcsEntity> SelectedEntities => _selectedEntities;
public EntityHierarchyWindow EntityHierarchyWindow => _entityHierarchyWindow; public EntityHierarchyWindow EntityHierarchyWindow => _entityHierarchyWindow;
public ComponentEditWindow ComponentEditWindow => _componentEditWindow; public ComponentEditWindow ComponentEditWindow => _componentEditWindow;
public SceneViewportWindow SceneViewportWindow => _sceneViewportWindow; public SceneViewportWindow SceneViewportWindow => _sceneViewportWindow;
/// Creates a new editor for the given world /// Creates a new editor for the given world
public this(EcsWorld world) public this(Scene scene)
{ {
_world = world; _scene = scene;
_ecsWorld = _scene.[Friend]_ecsWorld;
} }
public void Update() public void Update()
@@ -39,14 +41,14 @@ namespace GlitchyEditor
} }
/// Creates a new entity with a transform component. /// Creates a new entity with a transform component.
internal Entity CreateEntityWithTransform() internal EcsEntity CreateEntityWithTransform()
{ {
var entity = _world.NewEntity(); var entity = _ecsWorld.NewEntity();
var transformComponent = ref *_world.AssignComponent<TransformComponent>(entity); var transformComponent = ref *_ecsWorld.AssignComponent<TransformComponent>(entity);
transformComponent = TransformComponent(); transformComponent = TransformComponent();
var nameComponent = ref *_world.AssignComponent<DebugNameComponent>(entity); var nameComponent = ref *_ecsWorld.AssignComponent<DebugNameComponent>(entity);
nameComponent.SetName("Entity"); nameComponent.SetName("Entity");
return entity; return entity;
@@ -56,11 +58,11 @@ namespace GlitchyEditor
/// Returns whether or not all selected entities have the same parent. /// Returns whether or not all selected entities have the same parent.
internal bool AllSelectionsOnSameLevel() internal bool AllSelectionsOnSameLevel()
{ {
Entity? parent = .InvalidEntity; EcsEntity? parent = .InvalidEntity;
for(var selectedEntity in _selectedEntities) for(var selectedEntity in _selectedEntities)
{ {
var parentComponent = _world.GetComponent<ParentComponent>(selectedEntity); var parentComponent = _ecsWorld.GetComponent<ParentComponent>(selectedEntity);
if(parent == .InvalidEntity) if(parent == .InvalidEntity)
{ {
@@ -76,9 +78,9 @@ namespace GlitchyEditor
} }
/// Finds all children of the given entity and stores their IDs in the given list. /// Finds all children of the given entity and stores their IDs in the given list.
internal void FindChildren(Entity entity, List<Entity> entities) internal void FindChildren(EcsEntity entity, List<EcsEntity> entities)
{ {
for(var (child, childParent) in _world.Enumerate<ParentComponent>()) for(var (child, childParent) in _ecsWorld.Enumerate<ParentComponent>())
{ {
if(childParent.Entity == entity) if(childParent.Entity == entity)
{ {
@@ -93,7 +95,7 @@ namespace GlitchyEditor
/// Deletes all selected entities and their children. /// Deletes all selected entities and their children.
internal void DeleteSelectedEntities() internal void DeleteSelectedEntities()
{ {
List<Entity> entities = scope .(); List<EcsEntity> entities = scope .();
for(var entity in _selectedEntities) for(var entity in _selectedEntities)
{ {
@@ -104,7 +106,7 @@ namespace GlitchyEditor
for(var entity in entities) for(var entity in entities)
{ {
_world.RemoveEntity(entity); _ecsWorld.RemoveEntity(entity);
} }
_selectedEntities.Clear(); _selectedEntities.Clear();
+17 -10
View File
@@ -20,7 +20,7 @@ namespace GlitchyEditor
BlendState _alphaBlendState ~ _?.ReleaseRef(); BlendState _alphaBlendState ~ _?.ReleaseRef();
BlendState _opaqueBlendState ~ _?.ReleaseRef(); BlendState _opaqueBlendState ~ _?.ReleaseRef();
EcsWorld _world = new EcsWorld() ~ delete _; Scene _scene = new Scene() ~ delete _;
Editor _editor ~ delete _; Editor _editor ~ delete _;
@@ -33,7 +33,7 @@ namespace GlitchyEditor
Application.Get().Window.IsVSync = false; Application.Get().Window.IsVSync = false;
InitGraphics(); InitGraphics();
InitEcs(); //InitEcs();
InitEditor(); InitEditor();
} }
@@ -56,7 +56,7 @@ namespace GlitchyEditor
_viewportTarget.SamplerState = SamplerStateManager.LinearClamp; _viewportTarget.SamplerState = SamplerStateManager.LinearClamp;
} }
private void InitEcs() /*private void InitEcs()
{ {
_world.Register<DebugNameComponent>(); _world.Register<DebugNameComponent>();
_world.Register<TransformComponent>(); _world.Register<TransformComponent>();
@@ -66,18 +66,18 @@ namespace GlitchyEditor
_world.Register<SkinnedMeshRendererComponent>(); _world.Register<SkinnedMeshRendererComponent>();
_world.Register<CameraComponent>(); _world.Register<CameraComponent>();
_world.Register<AnimationComponent>(); _world.Register<AnimationComponent>();
} }*/
private void InitEditor() private void InitEditor()
{ {
_editor = new Editor(_world); _editor = new Editor(_scene);
_editor.SceneViewportWindow.ViewportSizeChangedEvent.Add(new (s, e) => ViewportSizeChanged(s, e)); _editor.SceneViewportWindow.ViewportSizeChangedEvent.Add(new (s, e) => ViewportSizeChanged(s, e));
_cameraController = new .(_context.SwapChain.AspectRatio); _cameraController = new .(_context.SwapChain.AspectRatio);
_cameraController.CameraPosition = .(0, 0, -5); _cameraController.CameraPosition = .(0, 0, -5);
_cameraController.TranslationSpeed = 10; _cameraController.TranslationSpeed = 10;
_editor.[Friend]CreateEntityWithTransform(); //_editor.[Friend]CreateEntityWithTransform();
_editor.SceneViewportWindow._camera = _cameraController.Camera; _editor.SceneViewportWindow._camera = _cameraController.Camera;
} }
@@ -87,7 +87,7 @@ namespace GlitchyEditor
if(_editor.SceneViewportWindow.HasFocus && Input.IsMouseButtonPressed(.RightButton)) if(_editor.SceneViewportWindow.HasFocus && Input.IsMouseButtonPressed(.RightButton))
_cameraController.Update(gameTime); _cameraController.Update(gameTime);
TransformSystem.Update(_world); //TransformSystem.Update(_world);
RenderCommand.Clear(_viewportTarget, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0); RenderCommand.Clear(_viewportTarget, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
@@ -98,11 +98,18 @@ namespace GlitchyEditor
RenderCommand.SetBlendState(_opaqueBlendState); RenderCommand.SetBlendState(_opaqueBlendState);
Renderer.BeginScene(_cameraController.Camera); //Renderer.BeginScene(_cameraController.Camera);
DebugRenderer.Render(_world); //DebugRenderer.Render(_scene.[Friend]_ecsWorld);
//Renderer.EndScene();
Renderer2D.BeginScene(_cameraController.Camera);
_scene.Update(gameTime);
Renderer2D.EndScene();
Renderer.EndScene();
RenderCommand.Clear(null, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0); RenderCommand.Clear(null, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0);
+3 -3
View File
@@ -33,9 +33,9 @@ namespace GlitchyEngine.Content
CGLTF.Free(data); CGLTF.Free(data);
} }
private static void NodesToEntities(CGLTF.Data* data, CGLTF.Node* node, Entity? parentEntity, EcsWorld world, Effect validationEffect, Material material, List<AnimationClip> clips) private static void NodesToEntities(CGLTF.Data* data, CGLTF.Node* node, EcsEntity? parentEntity, EcsWorld world, Effect validationEffect, Material material, List<AnimationClip> clips)
{ {
Entity entity = world.NewEntity(); EcsEntity entity = world.NewEntity();
#if DEBUG #if DEBUG
var nameComponent = world.AssignComponent<DebugNameComponent>(entity); var nameComponent = world.AssignComponent<DebugNameComponent>(entity);
@@ -122,7 +122,7 @@ namespace GlitchyEngine.Content
{ {
for(var primitive in node.Mesh.Primitives) for(var primitive in node.Mesh.Primitives)
{ {
Entity meshEntity = world.NewEntity(); EcsEntity meshEntity = world.NewEntity();
var meshParent = world.AssignComponent<ParentComponent>(meshEntity); var meshParent = world.AssignComponent<ParentComponent>(meshEntity);
meshParent.Entity = entity; meshParent.Entity = entity;
+5
View File
@@ -18,6 +18,11 @@ namespace GlitchyEngine.Math
public this(int initialCapacity = sizeof(uint)) public this(int initialCapacity = sizeof(uint))
{ {
var initialCapacity;
if (initialCapacity < sizeof(uint))
initialCapacity = sizeof(uint);
EnsureCapacity(initialCapacity); EnsureCapacity(initialCapacity);
} }
+1 -1
View File
@@ -79,7 +79,7 @@ namespace GlitchyEngine.Renderer
LineGeometry.SetVertexLayout(layout..ReleaseRefNoDelete()); LineGeometry.SetVertexLayout(layout..ReleaseRefNoDelete());
} }
public static void BeginScene(EcsWorld world, Entity cameraEntity) public static void BeginScene(EcsWorld world, EcsEntity cameraEntity)
{ {
Debug.Profiler.ProfileRendererFunction!(); Debug.Profiler.ProfileRendererFunction!();
+34
View File
@@ -0,0 +1,34 @@
using GlitchyEngine.Math;
namespace GlitchyEngine.World
{
struct SimpleTransformComponent
{
public Matrix Transform = Matrix.Identity;
public this()
{
}
public this(Matrix transform)
{
Transform = transform;
}
}
struct SpriterRendererComponent
{
public ColorRGBA Color = .White;
public this()
{
}
public this(ColorRGBA color)
{
Color = color;
}
}
}
+30
View File
@@ -0,0 +1,30 @@
using System;
using internal GlitchyEngine.World;
namespace GlitchyEngine.World
{
public struct EcsEntity : uint64
{
// Binary Format:
// Bits: [0 - 31] [32 - 64]
// Data: Version Index
[Inline]
internal uint32 Version => (uint32)this;
[Inline]
internal uint32 Index => (uint32)(this >> 32);
[Inline]
static internal EcsEntity CreateEntityID(uint32 index, uint32 version)
{
return ((uint64)index << 32) | version;
}
[Inline]
internal bool IsValid => Index != InvalidEntity.Index;
public const EcsEntity InvalidEntity = CreateEntityID(uint32.MaxValue, 0);
}
}
+38 -20
View File
@@ -10,7 +10,7 @@ namespace GlitchyEngine.World
{ {
const int MaxEntities = 1024; const int MaxEntities = 1024;
internal typealias BitmaskEntry = (Entity ID, BitArray ComponentMask); internal typealias BitmaskEntry = (EcsEntity ID, BitArray ComponentMask);
internal List<BitmaskEntry> _entities = new .(); internal List<BitmaskEntry> _entities = new .();
List<uint32> _freeIndices = new List<uint32>() ~ delete _; List<uint32> _freeIndices = new List<uint32>() ~ delete _;
@@ -44,7 +44,7 @@ namespace GlitchyEngine.World
/** /**
* Registers a new Component. * Registers a new Component.
*/ */
public void Register<T>() where T: struct public void Register<T>() where T: struct, new
{ {
uint32 id = (uint32)_componentPools.Count; uint32 id = (uint32)_componentPools.Count;
ComponentPool<T> componentPool = new ComponentPool<T>(MaxEntities); ComponentPool<T> componentPool = new ComponentPool<T>(MaxEntities);
@@ -55,7 +55,7 @@ namespace GlitchyEngine.World
/** /**
* Registers a new Component. * Registers a new Component.
*/ */
public void Register<T>() where T: struct, IDisposableComponent public void Register<T>() where T: struct, new, IDisposableComponent
{ {
uint32 id = (uint32)_componentPools.Count; uint32 id = (uint32)_componentPools.Count;
ComponentPool<T> componentPool = new ComponentPool<T>(MaxEntities); ComponentPool<T> componentPool = new ComponentPool<T>(MaxEntities);
@@ -88,23 +88,23 @@ namespace GlitchyEngine.World
/** /**
* Creates a new Entity and returns its ID. * Creates a new Entity and returns its ID.
*/ */
public Entity NewEntity() public EcsEntity NewEntity()
{ {
Entity entity; EcsEntity entity;
// Reuse freed entity slot // Reuse freed entity slot
if(_freeIndices.Count > 0) if(_freeIndices.Count > 0)
{ {
uint32 index = _freeIndices.PopBack(); uint32 index = _freeIndices.PopBack();
entity = Entity.CreateEntityID(index, _entities[index].ID.Version); entity = EcsEntity.CreateEntityID(index, _entities[index].ID.Version);
_entities[index].ID = entity; _entities[index].ID = entity;
} }
// Create new entity slot // Create new entity slot
else else
{ {
entity = Entity.CreateEntityID((.)_entities.Count, 0); entity = EcsEntity.CreateEntityID((.)_entities.Count, 0);
_entities.Add((entity, new BitArray(_componentPools.Count))); _entities.Add((entity, new BitArray(_componentPools.Count)));
} }
@@ -114,7 +114,7 @@ namespace GlitchyEngine.World
/** /**
* Removes the specified Entity from the World. * Removes the specified Entity from the World.
*/ */
public void RemoveEntity(Entity entity) public void RemoveEntity(EcsEntity entity)
{ {
var listEntity = ref _entities[entity.Index]; var listEntity = ref _entities[entity.Index];
if(entity != listEntity.ID) if(entity != listEntity.ID)
@@ -123,7 +123,7 @@ namespace GlitchyEngine.World
DisposeComponents(listEntity); DisposeComponents(listEntity);
// Invalidate entry and increment version // Invalidate entry and increment version
listEntity.ID = Entity.CreateEntityID(Entity.InvalidEntity.Index, entity.Version + 1); listEntity.ID = EcsEntity.CreateEntityID(EcsEntity.InvalidEntity.Index, entity.Version + 1);
_entities[entity.Index].ComponentMask.Clear(); _entities[entity.Index].ComponentMask.Clear();
_freeIndices.Add(entity.Index); _freeIndices.Add(entity.Index);
@@ -152,7 +152,7 @@ namespace GlitchyEngine.World
/** /**
* Assigns a component of type T to the specified entity and returns it. * Assigns a component of type T to the specified entity and returns it.
*/ */
public T* AssignComponent<T>(Entity entity) where T : struct, new public T* AssignComponent<T>(EcsEntity entity, T value = T()) where T : struct, new
{ {
if(entity.Index > _entities.Count) if(entity.Index > _entities.Count)
return null; return null;
@@ -165,8 +165,12 @@ namespace GlitchyEngine.World
ComponentPoolEntry entry; ComponentPoolEntry entry;
if(!_componentPools.TryGetValue(typeof(T), out entry)) if(!_componentPools.TryGetValue(typeof(T), out entry))
{ {
Log.EngineLogger.AssertDebug(false, scope $"Tried to assign unregistered component type {typeof(T)}"); Register<T>();
return null;
entry = _componentPools[typeof(T)];
//Log.EngineLogger.AssertDebug(false, scope $"Tried to assign unregistered component type {typeof(T)}");
//return null;
} }
// TODO: is it a problem to assign a component again? // TODO: is it a problem to assign a component again?
@@ -177,7 +181,7 @@ namespace GlitchyEngine.World
T* component = (T*)entry.Pool.Get(entity.Index); T* component = (T*)entry.Pool.Get(entity.Index);
*component = T(); *component = value;
return component; return component;
} }
@@ -185,7 +189,7 @@ namespace GlitchyEngine.World
/** /**
* Removes a component of type T from the specified entity. * Removes a component of type T from the specified entity.
*/ */
public void RemoveComponent<T>(Entity entity) where T : struct public void RemoveComponent<T>(EcsEntity entity) where T : struct, new
{ {
if(entity.Index > _entities.Count) if(entity.Index > _entities.Count)
return; return;
@@ -205,7 +209,7 @@ namespace GlitchyEngine.World
listEntity.ComponentMask[entry.Id] = false; listEntity.ComponentMask[entry.Id] = false;
} }
public void RemoveComponent<T>(Entity entity) where T : struct, IDisposableComponent public void RemoveComponent<T>(EcsEntity entity) where T : struct, new, IDisposableComponent
{ {
if(entity.Index > _entities.Count) if(entity.Index > _entities.Count)
return; return;
@@ -228,7 +232,21 @@ namespace GlitchyEngine.World
DisposeComponent<T>(entry.Pool.Get(entity.Index)); DisposeComponent<T>(entry.Pool.Get(entity.Index));
} }
public T* GetComponent<T>(Entity entity) where T : struct /// Returns whether or not the given entity has the specified component.
public bool HasComponent<T>(EcsEntity entity) where T : struct, new
{
var listEntity = ref _entities[entity.Index];
if(entity != listEntity.ID)
return false;
ComponentPoolEntry entry;
if(!_componentPools.TryGetValue(typeof(T), out entry))
return false;
return listEntity.ComponentMask[entry.Id];
}
public T* GetComponent<T>(EcsEntity entity) where T : struct, new
{ {
var listEntity = ref _entities[entity.Index]; var listEntity = ref _entities[entity.Index];
if(entity != listEntity.ID) if(entity != listEntity.ID)
@@ -279,7 +297,7 @@ namespace GlitchyEngine.World
world.Register<TransformComponent>(); world.Register<TransformComponent>();
Entity entity = world.NewEntity(); EcsEntity entity = world.NewEntity();
TransformComponent* myComp = world.AssignComponent<TransformComponent>(entity); TransformComponent* myComp = world.AssignComponent<TransformComponent>(entity);
myComp.LocalTransform = Matrix.Identity; myComp.LocalTransform = Matrix.Identity;
@@ -289,7 +307,7 @@ namespace GlitchyEngine.World
world.RemoveComponent<TransformComponent>(entity); world.RemoveComponent<TransformComponent>(entity);
Entity entity2 = world.NewEntity(); EcsEntity entity2 = world.NewEntity();
world.AssignComponent<TransformComponent>(entity2); world.AssignComponent<TransformComponent>(entity2);
world.RemoveEntity(entity); world.RemoveEntity(entity);
@@ -330,7 +348,7 @@ namespace GlitchyEngine.World
// Test dispose on component removal // Test dispose on component removal
{ {
// Create entity with disposable component. // Create entity with disposable component.
Entity entity = world.NewEntity(); EcsEntity entity = world.NewEntity();
var component = world.AssignComponent<TestDisposingComponent>(entity); var component = world.AssignComponent<TestDisposingComponent>(entity);
component.IsDisposed = false; component.IsDisposed = false;
@@ -342,7 +360,7 @@ namespace GlitchyEngine.World
// Test dispose on entity removal // Test dispose on entity removal
{ {
// Create entity with disposable component. // Create entity with disposable component.
Entity entity = world.NewEntity(); EcsEntity entity = world.NewEntity();
var component = world.AssignComponent<TestDisposingComponent>(entity); var component = world.AssignComponent<TestDisposingComponent>(entity);
component.IsDisposed = false; component.IsDisposed = false;
+40 -14
View File
@@ -4,27 +4,53 @@ using internal GlitchyEngine.World;
namespace GlitchyEngine.World namespace GlitchyEngine.World
{ {
public struct Entity : uint64 public struct Entity
{ {
// Binary Format: private EcsEntity _entity = .InvalidEntity;
// Bits: [0 - 31] [32 - 64]
// Data: Version Index
[Inline] private Scene _scene = null;
internal uint32 Version => (uint32)this;
[Inline] public EcsEntity Handle => _entity;
internal uint32 Index => (uint32)(this >> 32);
[Inline] public Scene Scene => _scene;
static internal Entity CreateEntityID(uint32 index, uint32 version)
public this()
{ {
return ((uint64)index << 32) | version;
} }
[Inline] public this(EcsEntity entity, Scene scene)
internal bool IsValid => Index != InvalidEntity.Index; {
_entity = entity;
_scene = scene;
}
public bool IsValid => _entity.IsValid;
public T* AddComponent<T>(T value = T()) where T: struct, new
{
Log.EngineLogger.AssertDebug(!HasComponent<T>(), scope $"Entity already has component.");
return _scene._ecsWorld.AssignComponent<T>(_entity, value);
}
public T* GetComponent<T>() where T: struct, new
{
Log.EngineLogger.AssertDebug(HasComponent<T>(), "Entity doesn't have component!");
return _scene._ecsWorld.GetComponent<T>(_entity);
}
public bool HasComponent<T>() where T: struct, new
{
return _scene._ecsWorld.HasComponent<T>(_entity);
}
public void RemoveComponent<T>() where T: struct, new
{
Log.EngineLogger.AssertDebug(HasComponent<T>(), "Entity doesn't have component!");
_scene._ecsWorld.RemoveComponent<T>(_entity);
}
public const Entity InvalidEntity = ((uint64)uint32.MaxValue << 32) | 0;//TODO: Report bug: CreateEntityID(uint32.MaxValue, 0);
} }
} }
+1 -1
View File
@@ -5,6 +5,6 @@ namespace GlitchyEngine.World
*/ */
public struct ParentComponent public struct ParentComponent
{ {
public Entity Entity; public EcsEntity Entity;
} }
} }
+48
View File
@@ -0,0 +1,48 @@
using GlitchyEngine.Math;
using GlitchyEngine.Renderer;
using System;
namespace GlitchyEngine.World
{
class Scene
{
internal EcsWorld _ecsWorld = new .() ~ delete _;
public this()
{
Entity entity = CreateEntity();
entity.AddComponent<SpriterRendererComponent>(.(ColorRGBA(0.2f, 0.9f, 0.15f)));
}
public ~this()
{
}
public void Update(GameTime gameTime)
{
//TransformSystem.Update(_ecsWorld);
for (var (entity, transform, sprite) in _ecsWorld.Enumerate<SimpleTransformComponent, SpriterRendererComponent>())
{
Renderer2D.DrawQuad(transform.Transform, sprite.Color);
}
}
public Entity CreateEntity(String name = "")
{
Entity entity = Entity(_ecsWorld.NewEntity(), this);
entity.AddComponent<SimpleTransformComponent>(.(.Identity));
let nameComponent = entity.AddComponent<DebugNameComponent>();
nameComponent.SetName(name.IsEmpty ? "Entity" : name);
return entity;
}
public void DestroyEntity(Entity entity)
{
_ecsWorld.RemoveEntity(entity.Handle);
}
}
}
+1 -1
View File
@@ -16,7 +16,7 @@ namespace GlitchyEngine.World
} }
} }
private static void UpdateEntity(Entity entity, TransformComponent* transform, EcsWorld world) private static void UpdateEntity(EcsEntity entity, TransformComponent* transform, EcsWorld world)
{ {
// Todo: test scaling with deep hierarchies! // Todo: test scaling with deep hierarchies!
+15 -15
View File
@@ -6,7 +6,7 @@ using internal GlitchyEngine.World;
namespace GlitchyEngine.World namespace GlitchyEngine.World
{ {
public struct WorldEnumerator : IEnumerator<Entity>, IDisposable public struct WorldEnumerator : IEnumerator<EcsEntity>, IDisposable
{ {
internal EcsWorld _world; internal EcsWorld _world;
internal BitArray _bitMask; internal BitArray _bitMask;
@@ -37,14 +37,14 @@ namespace GlitchyEngine.World
} }
} }
public Result<Entity> GetNext() mut public Result<EcsEntity> GetNext() mut
{ {
while(_currentEntry < _endEntry) while(_currentEntry < _endEntry)
{ {
EcsWorld.BitmaskEntry* entry = _currentEntry++; EcsWorld.BitmaskEntry* entry = _currentEntry++;
// Skip deleted entities // Skip deleted entities
if(entry.ID.Index == Entity.InvalidEntity.Index) if(entry.ID.Index == EcsEntity.InvalidEntity.Index)
continue; continue;
// Check whether or not mask matches // Check whether or not mask matches
@@ -61,7 +61,7 @@ namespace GlitchyEngine.World
} }
} }
public struct WorldEnumerator<TComponent> : WorldEnumerator, IEnumerator<(Entity Entity, TComponent* Component)> where TComponent : struct public struct WorldEnumerator<TComponent> : WorldEnumerator, IEnumerator<(EcsEntity Entity, TComponent* Component)> where TComponent : struct
{ {
internal EcsWorld.ComponentPoolEntry* _componentPool; internal EcsWorld.ComponentPoolEntry* _componentPool;
@@ -70,9 +70,9 @@ namespace GlitchyEngine.World
_componentPool = &world.GetComponentPool<TComponent>(); _componentPool = &world.GetComponentPool<TComponent>();
} }
public new Result<(Entity Entity, TComponent* Component)> GetNext() mut public new Result<(EcsEntity Entity, TComponent* Component)> GetNext() mut
{ {
Result<Entity> entity = base.GetNext(); Result<EcsEntity> entity = base.GetNext();
if(entity case .Err) if(entity case .Err)
return .Err; return .Err;
@@ -84,7 +84,7 @@ namespace GlitchyEngine.World
} }
public struct WorldEnumerator<TComponent0, TComponent1> : WorldEnumerator, public struct WorldEnumerator<TComponent0, TComponent1> : WorldEnumerator,
IEnumerator<(Entity Entity, TComponent0* Component0, TComponent1* Component1)> IEnumerator<(EcsEntity Entity, TComponent0* Component0, TComponent1* Component1)>
where TComponent0 : struct where TComponent1 : struct where TComponent0 : struct where TComponent1 : struct
{ {
internal EcsWorld.ComponentPoolEntry* _componentPool0; internal EcsWorld.ComponentPoolEntry* _componentPool0;
@@ -96,9 +96,9 @@ namespace GlitchyEngine.World
_componentPool1 = &world.GetComponentPool<TComponent1>(); _componentPool1 = &world.GetComponentPool<TComponent1>();
} }
public new Result<(Entity Entity, TComponent0* Component0, TComponent1* Component1)> GetNext() mut public new Result<(EcsEntity Entity, TComponent0* Component0, TComponent1* Component1)> GetNext() mut
{ {
Result<Entity> entity = base.GetNext(); Result<EcsEntity> entity = base.GetNext();
if(entity case .Err) if(entity case .Err)
return .Err; return .Err;
@@ -111,7 +111,7 @@ namespace GlitchyEngine.World
} }
public struct WorldEnumerator<TComponent0, TComponent1, TComponent2> : WorldEnumerator, public struct WorldEnumerator<TComponent0, TComponent1, TComponent2> : WorldEnumerator,
IEnumerator<(Entity Entity, TComponent0* Component0, TComponent1* Component1, TComponent2* Component2)> IEnumerator<(EcsEntity Entity, TComponent0* Component0, TComponent1* Component1, TComponent2* Component2)>
where TComponent0 : struct where TComponent1 : struct where TComponent2 : struct where TComponent0 : struct where TComponent1 : struct where TComponent2 : struct
{ {
internal EcsWorld.ComponentPoolEntry* _componentPool0; internal EcsWorld.ComponentPoolEntry* _componentPool0;
@@ -125,9 +125,9 @@ namespace GlitchyEngine.World
_componentPool2 = &world.GetComponentPool<TComponent2>(); _componentPool2 = &world.GetComponentPool<TComponent2>();
} }
public new Result<(Entity Entity, TComponent0* Component0, TComponent1* Component1, TComponent2* Component2)> GetNext() mut public new Result<(EcsEntity Entity, TComponent0* Component0, TComponent1* Component1, TComponent2* Component2)> GetNext() mut
{ {
Result<Entity> entity = base.GetNext(); Result<EcsEntity> entity = base.GetNext();
if(entity case .Err) if(entity case .Err)
return .Err; return .Err;
@@ -141,7 +141,7 @@ namespace GlitchyEngine.World
} }
public struct WorldEnumerator<TComponent0, TComponent1, TComponent2, TComponent3> : WorldEnumerator, public struct WorldEnumerator<TComponent0, TComponent1, TComponent2, TComponent3> : WorldEnumerator,
IEnumerator<(Entity Entity, TComponent0* Component0, TComponent1* Component1, TComponent2* Component2, TComponent3* Component3)> IEnumerator<(EcsEntity Entity, TComponent0* Component0, TComponent1* Component1, TComponent2* Component2, TComponent3* Component3)>
where TComponent0 : struct where TComponent1 : struct where TComponent2 : struct where TComponent3 : struct where TComponent0 : struct where TComponent1 : struct where TComponent2 : struct where TComponent3 : struct
{ {
internal EcsWorld.ComponentPoolEntry* _componentPool0; internal EcsWorld.ComponentPoolEntry* _componentPool0;
@@ -157,9 +157,9 @@ namespace GlitchyEngine.World
_componentPool3 = &world.GetComponentPool<TComponent3>(); _componentPool3 = &world.GetComponentPool<TComponent3>();
} }
public new Result<(Entity Entity, TComponent0* Component0, TComponent1* Component1, TComponent2* Component2, TComponent3* Component3)> GetNext() mut public new Result<(EcsEntity Entity, TComponent0* Component0, TComponent1* Component1, TComponent2* Component2, TComponent3* Component3)> GetNext() mut
{ {
Result<Entity> entity = base.GetNext(); Result<EcsEntity> entity = base.GetNext();
if(entity case .Err) if(entity case .Err)
return .Err; return .Err;
+2 -2
View File
@@ -249,8 +249,8 @@ namespace Sandbox
} }
} }
Entity evenCrazierParent; EcsEntity evenCrazierParent;
Entity crazyParent; EcsEntity crazyParent;
Material testMaterial1 ~ _?.ReleaseRef(); Material testMaterial1 ~ _?.ReleaseRef();
Material testMaterial2 ~ _?.ReleaseRef(); Material testMaterial2 ~ _?.ReleaseRef();