A Zig ECS library.
Zentig is designed for scalability and ease of use, while staying out of your way. It's heavily inspired by everything that makes bevy_ecs so great and Unity so approachable.
It is not recommended to use zentig for anything major in it's current state. While it is functional and I use it frequently, it is far from battle tested.
That being said, if you encounter any problems please feel free to open an issue!
Fetching for zig master:
zig fetch --save git+https://github.com/freakmangd/zentig_ecs
Fetching for zig 0.13.0:
zig fetch --save https://github.com/freakmangd/zentig_ecs/archive/refs/tags/0.13.0.tar.gz
In both cases, place this in your build.zig
:
const zentig = b.dependency("zentig-ecs", .{});
exe.root_module.addImport("ztg", zentig.module("zentig"));
And import it in your project:
const ztg = @import("ztg");
An entity is just a usize
:
pub const Entity = usize;
A basic component:
pub const Player = struct {
name: []const u8,
};
A basic system:
pub fn playerSpeak(q: ztg.Query(.{Player})) !void {
for (q.items(0)) |plr| {
std.debug.print("My name is {s}\n", .{self.name});
}
}
Registering systems/components into a world:
const MyWorld = blk: {
var wb = ztg.WorldBuilder.init(&.{});
wb.addComponents(&.{Player});
wb.addSystemsToStage(.update, playerSpeak);
break :blk wb.Build();
};
Calling systems is easily integratable into your game framework:
test "running systems" {
var world = MyWorld.init(testing.allocator);
defer world.deinit();
try world.runStage(.load);
try world.runUpdateStages();
try world.runStage(.draw);
// Support for user defined stages
try world.runStageList(&.{ .post_process, .pre_reset, .post_mortem });
}
The .include()
function in WorldBuilder
makes it easy to compartmentalize your game systems.
As well as integrate third party libraries with only one extra line!
main.zig
:
// .include() looks for a `pub fn include(comptime *WorldBuilder) (!)void` def
// in each struct. If the function errors it's a compile error,
// but the signature can return either `!void` or `void`
wb.include(&.{
ztg.base,
@import("player.zig"),
@import("my_library"),
});
player.zig
:
pub fn include(comptime wb: *ztg.WorldBuilder) void {
wb.addComponents(.{ Player, PlayerGun, PlayerHUD });
wb.addSystemsToStage(.update, .{ update_player, update_gun, update_hud });
}
my_library/init.zig
:
pub fn include(comptime wb: *ztg.WorldBuilder) void {
wb.include(&.{
// Namespaces can be included more than once to "ensure"
// they are included if you depend on them
ztg.base,
//...
});
}
See this short tutorial on creating systems and components here
See full examples in the examples folder
zentig is framework agnostic, it doesn't include any drawing capabilities. For that you need something like Raylib, I've created a library that wraps common Raylib components and provides systems that act on those components here.
That page provides installation instructions and usage examples.