aboutsummaryrefslogtreecommitdiff
path: root/src/ecs/ecs.zig
diff options
context:
space:
mode:
authorjjanzen <jjanzen@jjanzen.ca>2025-01-21 23:26:23 -0600
committerjjanzen <jjanzen@jjanzen.ca>2025-01-21 23:26:23 -0600
commit900c8756edc3bc547dfd2cd47921ecd453bf703b (patch)
tree057be3b086c66bab292da8b2ae798e92f8db54b2 /src/ecs/ecs.zig
parent385ca6511a8de0a4cc1dca774a3c743422c3d6be (diff)
doc comments and io refactor
Diffstat (limited to 'src/ecs/ecs.zig')
-rw-r--r--src/ecs/ecs.zig39
1 files changed, 27 insertions, 12 deletions
diff --git a/src/ecs/ecs.zig b/src/ecs/ecs.zig
index d1341bf..47c576b 100644
--- a/src/ecs/ecs.zig
+++ b/src/ecs/ecs.zig
@@ -1,12 +1,20 @@
+//! This module provides an implementation of an Entity Component System
const std = @import("std");
const component = @import("component.zig");
const ComponentType = component.ComponentType;
+/// EntityComponentSystem keeps track of components in a MultiArrayList of Components.
+/// Each Entity is simply an index into that MultiArrayList of Components.
+/// To save on memory and avoid resizing, ids are recycled upon Entities being deleted.
pub const EntityComponentSystem = struct {
+ /// An allocator for use by the EntityComponentSystem to manage memory
allocator: std.mem.Allocator,
+
+ /// The mapping of Components to Entities is in this MultiArrayList
components: std.MultiArrayList(component.Components),
+
+ /// Keeps track of ids available for reuse
available_ids: std.ArrayList(usize),
- next_id: usize,
fn nullEntity(self: *EntityComponentSystem, entity: usize) void {
inline for (std.enums.valuesFromFields(ComponentType, std.meta.fields(ComponentType))) |comp| {
@@ -19,7 +27,6 @@ pub const EntityComponentSystem = struct {
.allocator = allocator,
.components = .{},
.available_ids = std.ArrayList(usize).init(allocator),
- .next_id = 0,
};
}
@@ -28,28 +35,34 @@ pub const EntityComponentSystem = struct {
self.components.deinit(self.allocator);
}
+ /// Create a new entity (or recycle an old one) and return the id.
+ /// May error if the Allocator runs out of memory.
pub fn createEntity(self: *EntityComponentSystem) !usize {
const id = self.available_ids.popOrNull() orelse noroom: {
- const id = self.next_id;
+ const id = self.components.len;
try self.components.append(self.allocator, undefined);
- self.next_id += 1;
break :noroom id;
};
self.nullEntity(id);
return id;
}
+ /// Add an entity to a component.
+ /// Takes a ComponentType and an entity id along with any arguments needed to initialize the component.
pub fn componentAddEntity(
self: *EntityComponentSystem,
comp: component.ComponentType,
entity: usize,
args: anytype,
- ) !void {
+ ) void {
switch (comp) {
ComponentType.component_stub => self.components.items(.component_stub)[entity] = component.ComponentStub.init(args),
}
}
+ /// Delete an entity and make it ready for recycling by nulling all components.
+ /// Takes an entity id.
+ /// May error if the Allocator runs out of memory.
pub fn deleteEntity(self: *EntityComponentSystem, entity: usize) !void {
self.nullEntity(entity);
try self.available_ids.append(entity);
@@ -61,6 +74,8 @@ pub const EntityComponentSystem = struct {
comp[entity] = null;
}
+ /// Removes an entity from a component.
+ /// Takes a ComponentType and an entity id.
pub fn componentRemoveEntity(
self: *EntityComponentSystem,
comp: component.ComponentType,
@@ -80,7 +95,7 @@ test "add entities to components" {
for (0..100) |i| {
const entity = try ecs.createEntity();
try std.testing.expectEqual(i, entity);
- try ecs.componentAddEntity(ComponentType.component_stub, entity, .{});
+ ecs.componentAddEntity(ComponentType.component_stub, entity, .{});
try std.testing.expect(ecs.components.items(.component_stub)[entity] != null);
}
}
@@ -90,9 +105,9 @@ test "remove entities from components" {
defer ecs.deinit();
const entity = try ecs.createEntity();
- try ecs.componentAddEntity(ComponentType.component_stub, entity, .{});
+ ecs.componentAddEntity(ComponentType.component_stub, entity, .{});
const entity2 = try ecs.createEntity();
- try ecs.componentAddEntity(ComponentType.component_stub, entity2, .{});
+ ecs.componentAddEntity(ComponentType.component_stub, entity2, .{});
try std.testing.expect(ecs.components.items(.component_stub)[entity2] != null);
ecs.componentRemoveEntity(ComponentType.component_stub, entity2);
@@ -104,9 +119,9 @@ test "delete entities" {
defer ecs.deinit();
const entity = try ecs.createEntity();
- try ecs.componentAddEntity(ComponentType.component_stub, entity, .{});
+ ecs.componentAddEntity(ComponentType.component_stub, entity, .{});
const entity2 = try ecs.createEntity();
- try ecs.componentAddEntity(ComponentType.component_stub, entity2, .{});
+ ecs.componentAddEntity(ComponentType.component_stub, entity2, .{});
try std.testing.expect(ecs.components.items(.component_stub)[entity2] != null);
try ecs.deleteEntity(entity2);
@@ -119,9 +134,9 @@ test "recycle entities" {
defer ecs.deinit();
const entity = try ecs.createEntity();
- try ecs.componentAddEntity(ComponentType.component_stub, entity, .{});
+ ecs.componentAddEntity(ComponentType.component_stub, entity, .{});
const entity2 = try ecs.createEntity();
- try ecs.componentAddEntity(ComponentType.component_stub, entity2, .{});
+ ecs.componentAddEntity(ComponentType.component_stub, entity2, .{});
try ecs.deleteEntity(entity2);
try std.testing.expectEqual(1, ecs.available_ids.items.len);