shoal
my silly little ecs engine for odin and raylib :3
contents
install
clone this repo in your project directory
git clone https://git.egfk.net/harper/shoal
and import the package
import ecs "shoal/src"
usage
first create a new app struct. this is where your systems and plugins live.
import ecs "shoal/src"
app: ecs.App
you can run your app with run(). run takes a reference to your app to run it's systems.
main :: proc() {
ecs.run(&app)
}
systems
systems are procedures that run on set schedules
a schedule just determines when a producure runs
schedules are:\
- STARTUP\
- UPDATE\
- DRAW\
STARTUP runs once at the start of an app
UPDATE runs every frame
DRAW runs every frame after update, and makes draw calls to raylib\
main :: proc() {
ecs.add_system(&app, ecs.STARTUP, example_startup)
ecs.add_system(&app, ecs.UPDATE, example_update)
}
example_startup :: proc() {
// system that runs once
// ...
}
example_update :: proc() {
// system that runs every frame
// ...
}
components
components are just structs with data, and kept with other components of that type in Storage.
create a new component
ExampleComponent :: struct {}
and create it's storage
Example: ecs.Storage(ExampleComponent)
spawn entities
create a new entity with spawn_entity()
main :: proc() {
entity := ecs.spawn_entity(&app)
}
and give it new components with add_component()
main :: proc() {
ecs.add_component(entity, &Example) // make sure to pass a reference to the storage, not the component type
}
query
since components are saved in storage next to their entity, you can loop through a Storage and pick out what you like
main :: proc() {
for entity_id, component in ecs.slice(&Example) {
//...
}
}
or if you know your storage only has one entry use single()
main :: proc() {
entity_id, component := ecs.single(&Example)
}
plugins
plugins are just a procedure that takes App as a parameter, meaning it can make changes to app, just like main()
ExamplePlugin :: proc(app: ^App) {
ecs.add_system(app, ecs.STARTUP, some_plugin_system)
}
main :: proc() {
ecs.add_plugin(&app, ecs.DefaultPlugin)
ecs.add_plugin(&app, ExamplePlugin)
}
plugins make your scripts very reuseable. in fact, much of shoal's default behaviors come from plugins via DefaultPlugin()