https://github.com/elnudev/konoyo
A very simple ECS implemented in Zig with heavy use of comptime.
https://github.com/elnudev/konoyo
Last synced: 9 months ago
JSON representation
A very simple ECS implemented in Zig with heavy use of comptime.
- Host: GitHub
- URL: https://github.com/elnudev/konoyo
- Owner: ElnuDev
- License: lgpl-3.0
- Created: 2025-08-31T00:49:45.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2025-08-31T03:19:14.000Z (10 months ago)
- Last Synced: 2025-08-31T03:32:44.988Z (10 months ago)
- Language: Zig
- Size: 33.2 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# konoyo
A very simple ECS implemented in Zig with heavy use of comptime. Doesn't do anything fancy like archetypes.
To run the raylib exmaple, run `zig build -Dexample run`.
## Getting started
To get started, import konoyo and initialize an ECS world type definition with a component list.
Component types must meet the following requirements:
- name must end in "Component". This convention is enforced so it's clear what types in your project are queryable.
- cannot be named "EntityComponent"
- cannot be zero-sized (e.g. empty structs)
Once you have declared your world type, you can initialize it with an allocator. For each of the provided components, konoyo internally stores a hash table mapping from a `u32` entity ID to component instances.
Supposing you have already defined a `TransformComponent` and `SpriteComponent` (the ones used here are the same in the [example](example)), you can set up konoyo as follows.
```ZIG
const std = @import("std");
const ecs = @import("konoyo");
const World = ecs.World(&[_]type{
TransformComponent,
SpriteComponent,
});
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
var world = World.init(allocator);
defer world.deinit();
```
### Spawning entities
To create an entity, call `world.createEntity`. This will return a unique ID for the created entity.
```ZIG
const entity = world.createEntity();
```
You can then add any component that was defined in the world definition.
```ZIG
world.insert(entity, TransformComponent {
...
});
world.insert(entity, SpriteComponent {
...
});
```
### Querying entities
To query the world, call `world.query`, passing in a query slice of types you want your query to return. The query will return an array list of `QueryResult(Query)`. Each query result will contain an `entity` field with the entity ID and one field for each type in your query, e.g. querying for a `TransformComponent` will give you a `transform` field in every query result.
```ZIG
const Query = &[_]type{ *TransformComponent, *const SpriteComponent };
const results = world.query(query);
defer world.allocator.free(results);
for (results) |e| {
std.debug.print("Entity ID: {}\n", .{ e.entity });
e.transform.position.x += 42;
e.sprite.draw(e.transform.position);
}
```
Optional components are also supported.
```ZIG
const Query = &[_]type{ *TransformComponent, ?*const SpriteComponent };
```
Queried types are immutable by default: `Component` is a valid shorthand for `*const Component`.
```ZIG
const Query = &[_]type{ *TransformComponent, ?SpriteComponent };
```
### More utils
```ZIG
// get total number of components with given component
_ = world.count(SpriteComponent);
const entity = 0;
// deleteEntity returns whether or not the entity existed to begin with
_ = world.deleteEntity(entity);
// delete returns whether or not the component existed to begin with
_ = world.delete(entity, TransformComponent);
// check if entity exists
_ = world.entityExists(entity);
```
## Acknowledgements
Reimu fumo sprite by Jaysa under CC0 via [OpenGameArt.org](https://opengameart.org/content/touhou-fumo-factory)