1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
const std = @import("std");
const component = @import("component.zig");
const ComponentType = component.ComponentType;
pub const EntityComponentSystem = struct {
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 {
return EntityComponentSystem{
.allocator = allocator,
.components = .{},
.available_ids = std.ArrayList(usize).init(allocator),
.next_id = 0,
};
}
pub fn deinit(self: *EntityComponentSystem) void {
self.available_ids.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.components.items(.component_stub).len) {
return reuse_id.?;
}
const id = self.next_id;
try self.components.append(self.allocator, .{
.component_stub = null,
});
self.next_id += 1;
return id;
}
pub fn componentAddEntity(
self: *EntityComponentSystem,
comp: component.ComponentType,
entity: usize,
args: anytype,
) !void {
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);
}
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 = 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 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.deleteEntity(entity5);
try ecs.deleteEntity(entity4);
try ecs.deleteEntity(entity3);
try std.testing.expectEqual(3, ecs.available_ids.items.len);
}
|