diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ecs/component.zig | 27 | ||||
-rw-r--r-- | src/ecs/ecs.zig | 143 |
2 files changed, 105 insertions, 65 deletions
diff --git a/src/ecs/component.zig b/src/ecs/component.zig index 4a10172..37956d0 100644 --- a/src/ecs/component.zig +++ b/src/ecs/component.zig @@ -11,29 +11,10 @@ pub const ComponentStub = struct { } }; -pub const ComponentType = enum(usize) { - component_stub = 0, +pub const ComponentType = enum { + component_stub, }; -pub const Component = union(ComponentType) { - component_stub: ComponentStub, - - pub fn init(t: ComponentType, args: anytype) Component { - switch (t) { - ComponentType.component_stub => return Component{ - .component_stub = ComponentStub.init(args), - }, - } - } - - pub fn deinit(self: *Component) void { - switch (self.*) { - .component_stub => |*comp| comp.deinit(), - } - } +pub const Components = struct { + component_stub: ?ComponentStub, }; - -test "stub component" { - var stub = Component.init(ComponentType.component_stub, .{}); - defer stub.deinit(); -} diff --git a/src/ecs/ecs.zig b/src/ecs/ecs.zig index 542de34..919587a 100644 --- a/src/ecs/ecs.zig +++ b/src/ecs/ecs.zig @@ -1,62 +1,37 @@ const std = @import("std"); const component = @import("component.zig"); - -const ComponentList = struct { - entities: std.AutoHashMap(usize, component.Component), -}; +const ComponentType = component.ComponentType; pub const EntityComponentSystem = struct { - entities: std.ArrayList(usize), - components: std.AutoHashMap(usize, ComponentList), + allocator: std.mem.Allocator, + components: std.MultiArrayList(component.Components), available_ids: std.ArrayList(usize), next_id: usize, - pub fn init(allocator: std.mem.Allocator) !EntityComponentSystem { - var ecs = EntityComponentSystem{ - .entities = std.ArrayList(usize).init(allocator), - .components = std.AutoHashMap(usize, ComponentList).init(allocator), + pub fn init(allocator: std.mem.Allocator) EntityComponentSystem { + return EntityComponentSystem{ + .allocator = allocator, + .components = .{}, .available_ids = std.ArrayList(usize).init(allocator), .next_id = 0, }; - - inline for (std.meta.fields(component.ComponentType)) |comp| { - try ecs.components.put(comp.value, ComponentList{ - .entities = std.AutoHashMap(usize, component.Component).init(allocator), - }); - } - - return ecs; } pub fn deinit(self: *EntityComponentSystem) void { - self.entities.deinit(); self.available_ids.deinit(); - - var component_iterator = self.components.iterator(); - while (component_iterator.next()) |component_entry| { - var comp = component_entry.value_ptr; - - var entity_iterator = comp.entities.iterator(); - while (entity_iterator.next()) |entity_entry| { - var entity = entity_entry.value_ptr; - - entity.deinit(); - } - - comp.entities.deinit(); - } - self.components.deinit(); + self.components.deinit(self.allocator); } pub fn createEntity(self: *EntityComponentSystem) !usize { const reuse_id = self.available_ids.popOrNull(); - if (reuse_id != null and reuse_id.? < self.entities.items.len) { - self.entities.items[reuse_id.?] = reuse_id.?; + if (reuse_id != null and reuse_id.? < self.components.items(.component_stub).len) { return reuse_id.?; } const id = self.next_id; - try self.entities.append(id); + try self.components.append(self.allocator, .{ + .component_stub = null, + }); self.next_id += 1; return id; } @@ -67,18 +42,102 @@ pub const EntityComponentSystem = struct { entity: usize, args: anytype, ) !void { - var comp_list = self.components.getPtr(@intFromEnum(comp)) orelse return; + switch (comp) { + ComponentType.component_stub => self.components.items(.component_stub)[entity] = component.ComponentStub.init(args), + } + } + + pub fn deleteEntity(self: *EntityComponentSystem, entity: usize) !void { + inline for (std.enums.valuesFromFields(ComponentType, std.meta.fields(ComponentType))) |comp| { + self.componentRemoveEntity(comp, entity); + } + try self.available_ids.append(entity); + } - try comp_list.entities.put(entity, component.Component.init(comp, args)); + pub fn componentRemoveEntity( + self: *EntityComponentSystem, + comp: component.ComponentType, + entity: usize, + ) void { + switch (comp) { + ComponentType.component_stub => { + var comp_opt = self.components.items(.component_stub)[entity]; + if (comp_opt != null) comp_opt.?.deinit(); + self.components.items(.component_stub)[entity] = null; + }, + } } }; test "add entities to components" { - var ecs = try EntityComponentSystem.init(std.testing.allocator); + var ecs = EntityComponentSystem.init(std.testing.allocator); + defer ecs.deinit(); + + for (0..100) |i| { + const entity = try ecs.createEntity(); + try std.testing.expectEqual(i, entity); + try ecs.componentAddEntity(ComponentType.component_stub, entity, .{}); + try std.testing.expect(ecs.components.items(.component_stub)[entity] != null); + } +} + +test "remove entities from components" { + var ecs = EntityComponentSystem.init(std.testing.allocator); + defer ecs.deinit(); + + const entity = try ecs.createEntity(); + try ecs.componentAddEntity(ComponentType.component_stub, entity, .{}); + const entity2 = try ecs.createEntity(); + try ecs.componentAddEntity(ComponentType.component_stub, entity2, .{}); + + try std.testing.expect(ecs.components.items(.component_stub)[entity2] != null); + ecs.componentRemoveEntity(ComponentType.component_stub, entity2); + try std.testing.expect(ecs.components.items(.component_stub)[entity2] == null); +} + +test "delete entities" { + var ecs = EntityComponentSystem.init(std.testing.allocator); defer ecs.deinit(); const entity = try ecs.createEntity(); - try std.testing.expectEqual(0, entity); + try ecs.componentAddEntity(ComponentType.component_stub, entity, .{}); + const entity2 = try ecs.createEntity(); + try ecs.componentAddEntity(ComponentType.component_stub, entity2, .{}); + + try std.testing.expect(ecs.components.items(.component_stub)[entity2] != null); + try ecs.deleteEntity(entity2); + try std.testing.expect(ecs.components.items(.component_stub)[entity2] == null); + try std.testing.expectEqual(1, ecs.available_ids.items.len); +} + +test "recycle entities" { + var ecs = EntityComponentSystem.init(std.testing.allocator); + defer ecs.deinit(); + + const entity = try ecs.createEntity(); + try ecs.componentAddEntity(ComponentType.component_stub, entity, .{}); + const entity2 = try ecs.createEntity(); + try ecs.componentAddEntity(ComponentType.component_stub, entity2, .{}); + + try ecs.deleteEntity(entity2); + try std.testing.expectEqual(1, ecs.available_ids.items.len); + + const entity3 = try ecs.createEntity(); + try std.testing.expectEqual(1, entity3); + try std.testing.expectEqual(0, ecs.available_ids.items.len); + + const entity4 = try ecs.createEntity(); + try std.testing.expectEqual(2, entity4); + + try ecs.deleteEntity(entity); + try std.testing.expectEqual(1, ecs.available_ids.items.len); + + const entity5 = try ecs.createEntity(); + try std.testing.expectEqual(0, entity5); + try std.testing.expectEqual(0, ecs.available_ids.items.len); - try ecs.componentAddEntity(component.ComponentType.component_stub, entity, .{}); + try ecs.deleteEntity(entity5); + try ecs.deleteEntity(entity4); + try ecs.deleteEntity(entity3); + try std.testing.expectEqual(3, ecs.available_ids.items.len); } |