You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
243 lines
7.5 KiB
243 lines
7.5 KiB
const std = @import("std");
|
|
const ecs = @import("ecs");
|
|
const Registry = @import("ecs").Registry;
|
|
const BasicGroup = @import("ecs").BasicGroup;
|
|
const OwningGroup = @import("ecs").OwningGroup;
|
|
|
|
const Velocity = struct { x: f32 = 0, y: f32 = 0 };
|
|
const Position = struct { x: f32 = 0, y: f32 = 0 };
|
|
const Empty = struct {};
|
|
const Sprite = struct { x: f32 = 0 };
|
|
const Transform = struct { x: f32 = 0 };
|
|
const Renderable = struct { x: f32 = 0 };
|
|
const Rotation = struct { x: f32 = 0 };
|
|
|
|
fn printStore(store: anytype, name: []const u8) void {
|
|
std.debug.print("--- {} ---\n", .{name});
|
|
for (store.set.dense.items, 0..) |e, i| {
|
|
std.debug.print("e[{}] s[{}]{}", .{ e, store.set.page(store.set.dense.items[i]), store.set.sparse.items[store.set.page(store.set.dense.items[i])] });
|
|
std.debug.print(" ({d:.2}) ", .{store.instances.items[i]});
|
|
}
|
|
std.debug.print("\n", .{});
|
|
}
|
|
|
|
test "sort BasicGroup by Entity" {
|
|
var reg = Registry.init(std.testing.allocator);
|
|
defer reg.deinit();
|
|
|
|
var group = reg.group(.{}, .{ Sprite, Renderable }, .{});
|
|
|
|
var i: usize = 0;
|
|
while (i < 5) : (i += 1) {
|
|
var e = reg.create();
|
|
reg.add(e, Sprite{ .x = @as(f32, @floatFromInt(i)) });
|
|
reg.add(e, Renderable{ .x = @as(f32, @floatFromInt(i)) });
|
|
}
|
|
|
|
const SortContext = struct {
|
|
group: BasicGroup,
|
|
|
|
fn sort(this: *@This(), a: ecs.Entity, b: ecs.Entity) bool {
|
|
const real_a = this.group.getConst(Sprite, a);
|
|
const real_b = this.group.getConst(Sprite, b);
|
|
return real_a.x > real_b.x;
|
|
}
|
|
};
|
|
|
|
var context = SortContext{ .group = group };
|
|
group.sort(ecs.Entity, &context, SortContext.sort);
|
|
|
|
var val: f32 = 0;
|
|
var iter = group.iterator();
|
|
while (iter.next()) |entity| {
|
|
try std.testing.expectEqual(val, group.getConst(Sprite, entity).x);
|
|
val += 1;
|
|
}
|
|
}
|
|
|
|
test "sort BasicGroup by Component" {
|
|
var reg = Registry.init(std.testing.allocator);
|
|
defer reg.deinit();
|
|
|
|
var group = reg.group(.{}, .{ Sprite, Renderable }, .{});
|
|
|
|
var i: usize = 0;
|
|
while (i < 5) : (i += 1) {
|
|
var e = reg.create();
|
|
reg.add(e, Sprite{ .x = @as(f32, @floatFromInt(i)) });
|
|
reg.add(e, Renderable{ .x = @as(f32, @floatFromInt(i)) });
|
|
}
|
|
|
|
const SortContext = struct {
|
|
fn sort(_: void, a: Sprite, b: Sprite) bool {
|
|
return a.x > b.x;
|
|
}
|
|
};
|
|
group.sort(Sprite, {}, SortContext.sort);
|
|
|
|
var val: f32 = 0;
|
|
var iter = group.iterator();
|
|
while (iter.next()) |entity| {
|
|
try std.testing.expectEqual(val, group.getConst(Sprite, entity).x);
|
|
val += 1;
|
|
}
|
|
}
|
|
|
|
test "sort OwningGroup by Entity" {
|
|
var reg = Registry.init(std.testing.allocator);
|
|
defer reg.deinit();
|
|
|
|
var group = reg.group(.{ Sprite, Renderable }, .{}, .{});
|
|
|
|
var i: usize = 0;
|
|
while (i < 5) : (i += 1) {
|
|
var e = reg.create();
|
|
reg.add(e, Sprite{ .x = @as(f32, @floatFromInt(i)) });
|
|
reg.add(e, Renderable{ .x = @as(f32, @floatFromInt(i)) });
|
|
}
|
|
|
|
const SortContext = struct {
|
|
group: OwningGroup,
|
|
|
|
fn sort(this: @This(), a: ecs.Entity, b: ecs.Entity) bool {
|
|
const sprite_a = this.group.getConst(Sprite, a);
|
|
const sprite_b = this.group.getConst(Sprite, b);
|
|
return sprite_a.x > sprite_b.x;
|
|
}
|
|
};
|
|
const context = SortContext{ .group = group };
|
|
group.sort(ecs.Entity, context, SortContext.sort);
|
|
|
|
var val: f32 = 0;
|
|
var iter = group.iterator(struct { s: *Sprite, r: *Renderable });
|
|
while (iter.next()) |entity| {
|
|
try std.testing.expectEqual(val, entity.s.*.x);
|
|
val += 1;
|
|
}
|
|
}
|
|
|
|
test "sort OwningGroup by Component" {
|
|
var reg = Registry.init(std.testing.allocator);
|
|
defer reg.deinit();
|
|
|
|
var group = reg.group(.{ Sprite, Renderable }, .{}, .{});
|
|
|
|
var i: usize = 0;
|
|
while (i < 5) : (i += 1) {
|
|
var e = reg.create();
|
|
reg.add(e, Sprite{ .x = @as(f32, @floatFromInt(i)) });
|
|
reg.add(e, Renderable{ .x = @as(f32, @floatFromInt(i)) });
|
|
}
|
|
|
|
const SortContext = struct {
|
|
fn sort(_: void, a: Sprite, b: Sprite) bool {
|
|
return a.x > b.x;
|
|
}
|
|
};
|
|
group.sort(Sprite, {}, SortContext.sort);
|
|
|
|
var val: f32 = 0;
|
|
var iter = group.iterator(struct { s: *Sprite, r: *Renderable });
|
|
while (iter.next()) |entity| {
|
|
try std.testing.expectEqual(val, entity.s.*.x);
|
|
val += 1;
|
|
}
|
|
}
|
|
|
|
test "sort OwningGroup by Component ensure unsorted non-matches" {
|
|
var reg = Registry.init(std.testing.allocator);
|
|
defer reg.deinit();
|
|
|
|
var group = reg.group(.{ Sprite, Renderable }, .{}, .{});
|
|
|
|
var i: usize = 0;
|
|
while (i < 5) : (i += 1) {
|
|
var e = reg.create();
|
|
reg.add(e, Sprite{ .x = @as(f32, @floatFromInt(i)) });
|
|
reg.add(e, Renderable{ .x = @as(f32, @floatFromInt(i)) });
|
|
|
|
var e2 = reg.create();
|
|
reg.add(e2, Sprite{ .x = @as(f32, @floatFromInt(i + 1 * 50)) });
|
|
}
|
|
|
|
try std.testing.expectEqual(group.len(), 5);
|
|
try std.testing.expectEqual(reg.len(Sprite), 10);
|
|
|
|
const SortContext = struct {
|
|
fn sort(_: void, a: Sprite, b: Sprite) bool {
|
|
// sprites with x > 50 shouldnt match in the group
|
|
std.testing.expect(a.x < 50 and b.x < 50) catch unreachable;
|
|
return a.x > b.x;
|
|
}
|
|
};
|
|
group.sort(Sprite, {}, SortContext.sort);
|
|
|
|
// all the
|
|
var view = reg.view(.{Sprite}, .{});
|
|
var count: usize = 0;
|
|
var iter = view.iterator();
|
|
while (iter.next()) |sprite| {
|
|
count += 1;
|
|
|
|
// all sprite.x > 50 should be at the end and we iterate backwards
|
|
if (count < 6) {
|
|
try std.testing.expect(sprite.x >= 50);
|
|
}
|
|
}
|
|
}
|
|
|
|
test "nested OwningGroups add/remove components" {
|
|
var reg = Registry.init(std.testing.allocator);
|
|
defer reg.deinit();
|
|
|
|
var group1 = reg.group(.{Sprite}, .{Renderable}, .{});
|
|
var group2 = reg.group(.{ Sprite, Transform }, .{Renderable}, .{});
|
|
var group3 = reg.group(.{ Sprite, Transform }, .{ Renderable, Rotation }, .{});
|
|
|
|
try std.testing.expect(!reg.sortable(Sprite));
|
|
try std.testing.expect(!reg.sortable(Transform));
|
|
try std.testing.expect(reg.sortable(Renderable));
|
|
|
|
var e1 = reg.create();
|
|
reg.addTypes(e1, .{ Sprite, Renderable, Rotation });
|
|
try std.testing.expectEqual(group1.len(), 1);
|
|
try std.testing.expectEqual(group2.len(), 0);
|
|
try std.testing.expectEqual(group3.len(), 0);
|
|
|
|
reg.add(e1, Transform{});
|
|
try std.testing.expectEqual(group3.len(), 1);
|
|
|
|
reg.remove(Sprite, e1);
|
|
try std.testing.expectEqual(group1.len(), 0);
|
|
try std.testing.expectEqual(group2.len(), 0);
|
|
try std.testing.expectEqual(group3.len(), 0);
|
|
}
|
|
|
|
test "nested OwningGroups entity order" {
|
|
var reg = Registry.init(std.testing.allocator);
|
|
defer reg.deinit();
|
|
|
|
var group1 = reg.group(.{Sprite}, .{Renderable}, .{});
|
|
var group2 = reg.group(.{ Sprite, Transform }, .{Renderable}, .{});
|
|
|
|
var i: usize = 0;
|
|
while (i < 5) : (i += 1) {
|
|
var e = reg.create();
|
|
reg.add(e, Sprite{ .x = @as(f32, @floatFromInt(i)) });
|
|
reg.add(e, Renderable{ .x = @as(f32, @floatFromInt(i)) });
|
|
}
|
|
|
|
try std.testing.expectEqual(group1.len(), 5);
|
|
try std.testing.expectEqual(group2.len(), 0);
|
|
|
|
_ = reg.assure(Sprite);
|
|
_ = reg.assure(Transform);
|
|
// printStore(sprite_store, "Sprite");
|
|
|
|
reg.add(1, Transform{ .x = 1 });
|
|
|
|
// printStore(sprite_store, "Sprite");
|
|
// printStore(transform_store, "Transform");
|
|
// std.debug.print("group2.current: {}\n", .{group2.group_data.current});
|
|
}
|