aboutsummaryrefslogtreecommitdiff
path: root/src/ecs/ecs.zig
blob: 542de3426ecff359f16a7d6f4acd4575295f23f4 (plain)
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
const std = @import("std");
const component = @import("component.zig");

const ComponentList = struct {
    entities: std.AutoHashMap(usize, component.Component),
};

pub const EntityComponentSystem = struct {
    entities: std.ArrayList(usize),
    components: std.AutoHashMap(usize, ComponentList),
    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),
            .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();
    }

    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.?;
            return reuse_id.?;
        }

        const id = self.next_id;
        try self.entities.append(id);
        self.next_id += 1;
        return id;
    }

    pub fn componentAddEntity(
        self: *EntityComponentSystem,
        comp: component.ComponentType,
        entity: usize,
        args: anytype,
    ) !void {
        var comp_list = self.components.getPtr(@intFromEnum(comp)) orelse return;

        try comp_list.entities.put(entity, component.Component.init(comp, args));
    }
};

test "add entities to components" {
    var ecs = try EntityComponentSystem.init(std.testing.allocator);
    defer ecs.deinit();

    const entity = try ecs.createEntity();
    try std.testing.expectEqual(0, entity);

    try ecs.componentAddEntity(component.ComponentType.component_stub, entity, .{});
}