initial commit
commit
2875fc285d
|
@ -0,0 +1 @@
|
|||
zig-cache
|
|
@ -0,0 +1,18 @@
|
|||
const Builder = @import("std").build.Builder;
|
||||
|
||||
pub fn build(b: *Builder) void {
|
||||
const mode = b.standardReleaseOptions();
|
||||
const lib = b.addStaticLibrary("encompass", "src/encompass.zig");
|
||||
lib.setBuildMode(mode);
|
||||
lib.install();
|
||||
|
||||
var entity_test = b.addTest("src/entity.zig");
|
||||
entity_test.setBuildMode(mode);
|
||||
|
||||
var component_store_test = b.addTest("src/component_store.zig");
|
||||
component_store_test.setBuildMode(mode);
|
||||
|
||||
const test_step = b.step("test", "Run library tests");
|
||||
test_step.dependOn(&entity_test.step);
|
||||
test_step.dependOn(&component_store_test.step);
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const testing = std.testing;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
pub fn ComponentStore(comptime TComponent: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
nextIndex: usize = 0,
|
||||
allocator: *Allocator,
|
||||
entityIDToIndex: std.AutoArrayHashMap(usize, usize),
|
||||
indexToEntityID: std.ArrayList(usize),
|
||||
components: std.ArrayList(TComponent),
|
||||
|
||||
pub fn init(allocator: *Allocator) Self {
|
||||
return Self {
|
||||
.allocator = allocator,
|
||||
.entityIDToIndex = std.AutoArrayHashMap(usize, usize).init(allocator),
|
||||
.indexToEntityID = std.ArrayList(usize).init(allocator),
|
||||
.components = std.ArrayList(TComponent).init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.entityIDToIndex.deinit();
|
||||
self.indexToEntityID.deinit();
|
||||
self.components.deinit();
|
||||
}
|
||||
|
||||
pub fn has(self: Self, entityID: usize) bool {
|
||||
return self.entityIDToIndex.contains(entityID);
|
||||
}
|
||||
|
||||
pub fn set(self: *Self, entityID: usize, component: TComponent) void {
|
||||
if (!self.entityIDToIndex.contains(entityID)) {
|
||||
const index = self.nextIndex;
|
||||
self.nextIndex += 1;
|
||||
|
||||
// FIXME: actually handle OOM
|
||||
self.components.append(component) catch unreachable;
|
||||
self.entityIDToIndex.put(entityID, index) catch unreachable;
|
||||
self.indexToEntityID.append(entityID) catch unreachable;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.components.items[self.entityIDToIndex.get(entityID).?] = component;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count(self: Self) usize {
|
||||
return self.components.items.len;
|
||||
}
|
||||
|
||||
pub fn get(self: Self, entityID: usize) !TComponent {
|
||||
var index = self.entityIDToIndex.get(entityID) orelse error.NoComponentError;
|
||||
return self.components.items[try index];
|
||||
}
|
||||
|
||||
pub fn remove(self: *Self, entityID: usize) void {
|
||||
if (self.entityIDToIndex.contains(entityID)) {
|
||||
var storageIndex = self.entityIDToIndex.get(entityID).?;
|
||||
var lastEntity = self.indexToEntityID.items[self.nextIndex - 1];
|
||||
|
||||
self.entityIDToIndex.put(lastEntity, storageIndex) catch unreachable;
|
||||
|
||||
var removedComponent = self.components.swapRemove(storageIndex);
|
||||
var removedEntityID = self.indexToEntityID.swapRemove(storageIndex);
|
||||
var removedEntry = self.entityIDToIndex.remove(entityID);
|
||||
|
||||
self.nextIndex -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_components(self: Self) []TComponent {
|
||||
return self.components.items;
|
||||
}
|
||||
|
||||
pub fn all_entities(self: Self) []usize {
|
||||
return self.indexToEntityID.items();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const TestComponent = struct {
|
||||
number: i32,
|
||||
};
|
||||
|
||||
test "component store set item" {
|
||||
const component = TestComponent {
|
||||
.number = 3
|
||||
};
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const allocator = &arena.allocator;
|
||||
|
||||
var component_store = ComponentStore(TestComponent).init(allocator);
|
||||
component_store.set(12, component);
|
||||
|
||||
testing.expect(component_store.count() == 1);
|
||||
testing.expect(component_store.has(12));
|
||||
testing.expect((try component_store.get(12)).number == component.number);
|
||||
}
|
||||
|
||||
test "iterate items" {
|
||||
const component = TestComponent {
|
||||
.number = 3
|
||||
};
|
||||
|
||||
const componentTwo = TestComponent {
|
||||
.number = 10
|
||||
};
|
||||
|
||||
const componentThree = TestComponent {
|
||||
.number = 15
|
||||
};
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const allocator = &arena.allocator;
|
||||
|
||||
var component_store = ComponentStore(TestComponent).init(allocator);
|
||||
component_store.set(3, component);
|
||||
component_store.set(5, componentTwo);
|
||||
component_store.set(8, componentThree);
|
||||
|
||||
var all_components = component_store.all_components();
|
||||
|
||||
testing.expect(all_components[0].number == 3);
|
||||
testing.expect(all_components[1].number == 10);
|
||||
testing.expect(all_components[2].number == 15);
|
||||
}
|
||||
|
||||
test "has item" {
|
||||
const component = TestComponent {
|
||||
.number = 3
|
||||
};
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const allocator = &arena.allocator;
|
||||
|
||||
var component_store = ComponentStore(TestComponent).init(allocator);
|
||||
component_store.set(5, component);
|
||||
|
||||
testing.expect(component_store.has(5));
|
||||
testing.expect(!component_store.has(6));
|
||||
}
|
||||
|
||||
test "remove item" {
|
||||
const component = TestComponent {
|
||||
.number = 5
|
||||
};
|
||||
|
||||
const componentTwo = TestComponent {
|
||||
.number = 87
|
||||
};
|
||||
|
||||
const componentThree = TestComponent {
|
||||
.number = 124
|
||||
};
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const allocator = &arena.allocator;
|
||||
|
||||
var component_store = ComponentStore(TestComponent).init(allocator);
|
||||
component_store.set(5, component);
|
||||
component_store.set(10, componentTwo);
|
||||
component_store.set(15, componentThree);
|
||||
|
||||
component_store.remove(10);
|
||||
|
||||
testing.expect(component_store.has(5));
|
||||
testing.expect(component_store.has(15));
|
||||
testing.expect(!component_store.has(10));
|
||||
|
||||
testing.expect((try component_store.get(5)).number == 5);
|
||||
testing.expect((try component_store.get(15)).number == 124);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
pub const Entity = @import("entity.zig").Entity;
|
||||
pub const ComponentStore = @import("component_store.zig").ComponentStore;
|
|
@ -0,0 +1,18 @@
|
|||
const std = @import("std");
|
||||
const testing = std.testing;
|
||||
|
||||
pub const Entity = struct {
|
||||
ID: u32,
|
||||
|
||||
pub fn init(id: u32) Entity {
|
||||
return .{ .ID = id };
|
||||
}
|
||||
};
|
||||
|
||||
test "entity init" {
|
||||
const e1 = Entity.init(12);
|
||||
const e2 = Entity.init(21);
|
||||
|
||||
testing.expect(e1.ID == 12);
|
||||
testing.expect(e2.ID == 21);
|
||||
}
|
Loading…
Reference in New Issue