Giter Club home page Giter Club logo

zig-ecs's Introduction

Zig ECS

Zig ECS is a zig port of the fantasic Entt. Entt is highly templated C++ code which depending on your opinion is either a good thing or satan itself in code form. Zig doesn't have the same concept as C++ templates (thank goodness!) so the templated code was changed over to use Zig's generics and compile time metaprogramming.

What does a zigified Entt look like?

Below are examples of a View and a Group, the two main ways to work with entities in the ecs along with the scaffolding code.

Declare some structs to work with:

pub const Velocity = struct { x: f32, y: f32 };
pub const Position = struct { x: f32, y: f32 };

Setup the Registry, which holds the entity data and is where we run our queries:

var reg = ecs.Registry.init(std.testing.allocator);

Create a couple entities and add some components to them

var entity = reg.create();
reg.add(entity, Position{ .x = 0, .y = 0 });
reg.add(entity, Velocity{ .x = 5, .y = 7 });
...

Create and iterate a View that matches all entities with a Velocity and Position component:

var view = reg.view(.{ Velocity, Position }, .{});

var iter = view.iterator();
while (iter.next()) |entity| {
    const pos = view.getConst(Position, entity); // readonly copy
    var vel = view.get(Velocity, entity); // mutable
}

The same example using an owning Group:

var group = reg.group(.{ Velocity, Position }, .{}, .{});
group.each(each);

fn each(e: struct { vel: *Velocity, pos: *Position }) void {
    e.pos.*.x += e.vel.x;
    e.pos.*.y += e.vel.y;
}

zig-ecs's People

Contributors

actondev avatar bluesillybeard avatar codehz avatar foxnne avatar jacobhin2 avatar joachimschmidt557 avatar justinbraben avatar justinryanh avatar leroycep avatar luna1996 avatar mbcrocci avatar menduz avatar mikedjc avatar nektro avatar prime31 avatar rudedogg avatar sashiri avatar stefanpartheym avatar tekkunsan avatar vvcarvalho avatar wdkr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

zig-ecs's Issues

Make zig-ecs compatible with current zig version (0.11.0-dev)

First of all, thanks for the effort. I tried this library with zig v0.9.1 and I got started very fast.

However, one thing that would be nice is to use zig-ecs with the current v0.11.0 version of the zig compiler.
Currently, if I try to build a simple project (or the examples) using zig v0.11.0-dev.1571+c1f71963a I receive a quite generic error:

$ zig build
error: zigecs-test...
error: The following command terminated unexpectedly:
/home/stefanpartheym/.zvm/master/zig build-exe /home/stefanpartheym/develop/stefanpartheym/zigecs-test/src/main.zig --cache-dir /home/stefanpartheym/develop/stefanpartheym/zigecs-test/zig-cache --global-cache-dir /home/stefanpartheym/.cache/zig --name zigecs-test --pkg-begin ecs /home/stefanpartheym/develop/stefanpartheym/zigecs-test/deps/zig-ecs/src/ecs.zig --pkg-end --enable-cache 
error: the following build command failed with exit code 11:
/home/stefanpartheym/develop/stefanpartheym/zigecs-test/zig-cache/o/ee157244c8abf2f8e61ae7f5813ecc82/build /home/stefanpartheym/.zvm/master/zig /home/stefanpartheym/develop/stefanpartheym/zigecs-test /home/stefanpartheym/develop/stefanpartheym/zigecs-test/zig-cache /home/stefanpartheym/.cache/zig run

If I then try to execute the actual command line run by zig build:

$ /home/stefanpartheym/.zvm/master/zig build-exe /home/stefanpartheym/develop/stefanpartheym/zigecs-test/src/main.zig --cache-dir /home/stefanpartheym/develop/stefanpartheym/zigecs-test/zig-cache --global-cache-dir /home/stefanpartheym/.cache/zig --name zigecs-test --pkg-begin ecs /home/stefanpartheym/develop/stefanpartheym/zigecs-test/deps/zig-ecs/src/ecs.zig --pkg-end --enable-cache
fish: Job 1, '/home/stefanpartheym/.zvm/maste…' terminated by signal SIGSEGV (Adressbereichsfehler)

... the process segfaults.

I suspect, this is may be due to some very complex comptime syntax in src/ecs/component_storage.zig, which might be deprecated in current compiler versions:
In line 186 of component_storage.zig there is pub usingnamespace if (is_empty_struct). Which, if I remove like follows, reveals a different error (but at least not a segfault):

diff --git a/src/ecs/component_storage.zig b/src/ecs/component_storage.zig
index e3aa6b7..72a4408 100644
--- a/src/ecs/component_storage.zig
+++ b/src/ecs/component_storage.zig
@@ -183,17 +183,6 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type {
             return self.set.len();
         }
 
-        pub usingnamespace if (is_empty_struct)
-            struct {
-                /// Sort Entities according to the given comparison function. Only T == Entity is allowed. The constraint param only exists for
-                /// parity with non-empty Components
-                pub fn sort(self: Self, comptime T: type, context: anytype, comptime lessThan: fn (@TypeOf(context), T, T) bool) void {
-                    std.debug.assert(T == Entity);
-                    self.set.sort(context, lessThan);
-                }
-            }
-        else
-            struct {
                 /// Direct access to the array of objects
                 pub fn raw(self: Self) []Component {
                     return self.instances.items;
@@ -262,7 +251,6 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type {
                         self.set.arrange(length, swap_context, SortContext.sort, swap_context);
                     }
                 }
-            };
 
         /// Direct access to the array of entities
         pub fn data(self: Self) []const Entity {

Using this patch will result in the following compilation error:

deps/zig-ecs/src/ecs/registry.zig:287:13: error: unable to resolve comptime value
        self.assure(@TypeOf(value)).add(entity, value);
        ~~~~^~~~~~~
deps/zig-ecs/src/ecs/registry.zig:287:13: note: argument to function being called at comptime must be comptime-known
deps/zig-ecs/src/ecs/registry.zig:217:54: note: expression is evaluated at comptime because the generic function was instantiated with a comptime-only return type
    pub fn assure(self: *Registry, comptime T: type) *Storage(T) {
                                                     ^~~~~~~~~~~
referenced by:
    add__anon_4436: deps/zig-ecs/src/ecs/registry.zig:287:13
    main: src/main.zig:16:8
    remaining reference traces hidden; use '-freference-trace' to see all reference traces

Finally, as reference, the build.zig and src/main.zig files I used:

build.zig:

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "zigecs-test",
        .root_source_file = .{ .path = "src/main.zig" },
        .target = target,
        .optimize = optimize,
    });
    exe.addModule("ecs", b.createModule(.{
        .source_file = std.build.FileSource{ .path = "deps/zig-ecs/src/ecs.zig" },
    }));
    exe.install();

    const run_cmd = exe.run();
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

    const exe_tests = b.addTest(.{
        .root_source_file = .{ .path = "src/main.zig" },
        .target = target,
        .optimize = optimize,
    });

    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&exe_tests.step);
}

src/main.zig

const std = @import("std");
const builtin = @import("builtin");
const ecs = @import("ecs");

const Position = struct {
    x: f32,
    y: f32,
};

pub fn main() !void {
    std.debug.print("## Testing zig-ecs (zig v{}) ##\n", .{ builtin.zig_version });

    var reg = ecs.Registry.init(std.heap.page_allocator);

    var player = reg.create();
    reg.add(player, Position{ .x = 10, .y = 10 });
}

Thanks and best regards
Stefan

Using two groups at the same time

I don't get it, why doesn't it work 🤔

Code:

...
{
    var group = world.group(.{ Position, Orbiting }, .{}, .{});
    var group_iter = group.iterator(struct { pos: *Position, orb: *Orbiting });

    while (group_iter.next()) |e| {
        ...
    }
}

{
    var group = world.group(.{ Position, Renderer }, .{}, .{});
    var group_iter = group.iterator(struct { pos: *Position, ren: *Renderer });

    while (group_iter.next()) |e| {
        ...
    }
}
...

Error Logs:

thread 258336 panic: reached unreachable code
/nix/store/ypzkr8d6sff2vcdjadcbblqdwjf1ia72-zig-0.12.0-dev.1+a327d8b99/lib/std/debug.zig:343:14: 0x342e6c in assert (z-space)
    if (!ok) unreachable; // assertion failure
             ^
/home/jp3/.local/src/z-space/libs/zig-ecs/src/ecs/registry.zig:530:33: 0x344d73 in group__anon_6485 (z-space)
                std.debug.assert(check);
                                ^
/home/jp3/.local/src/z-space/src/main.zig:74:36: 0x3424b4 in main (z-space)
            var group = world.group(.{ Position, Renderer }, .{}, .{});
                                   ^
/nix/store/ypzkr8d6sff2vcdjadcbblqdwjf1ia72-zig-0.12.0-dev.1+a327d8b99/lib/std/start.zig:564:22: 0x341dc9 in main (z-space)
            root.main();
                     ^
???:?:?: 0x7ffff7d1facd in ??? (libc.so.6)
Unwind information for `libc.so.6:0x7ffff7d1facd` was not available, trace may be incomplete

PS. Did you thought about adding better error messages - it would have been really helpful 😄

Unable to create an Owning Group with no include and no excludinig components.

Problem

Not able to create an Owning Group with no includes and no exludes.

pub const Position = struct { x: f32, y: f32 };

pub fn main() !void {
    var reg = ecs.Registry.init(std.heap.c_allocator);
    defer reg.deinit();

    var e = reg.create();
    reg.add(e, Position { .x = 1, .y = 1 });

    var group = reg.group(.{Position }, .{}, .{});   // <-----
}

Result

fails assert in registry.zig: 471
std.debug.assert(owned.len + includes.len + excludes.len > 1);

Am I using the library incorrectly?

C ABI

Hi, I know that Zig can compile using the C ABI, and I'd like try binding this to Odin. Would there be any difficulties when using this as a static/dynamic library?

Basisc Groups don't have an `each` method

The Readme states that...


The same example using a non-owning Group:

var group = reg.group(.{}, .{ Velocity, Position }, .{});
group.each(each);

fn each(e: struct { vel: *Velocity, pos: *Position }) void {
    e.pos.*.x += e.vel.x;
    e.pos.*.y += e.vel.y;
}

zig complains:

error: no member named 'each' in struct '.zig-ecs.ecs.groups.BasicGroup'

After looking for it I only managed to find the method each for OwningGroups.
Not that I know if there should or shouldn't be such method but just wanted to point out that the readme seems(?) wrong.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.