Files
shoal/README.md
T
2026-10-09 12:15:57 -07:00

134 lines
2.5 KiB
Markdown

# shoal
my silly little ecs engine for odin and raylib :3
## contents
- [install](#install)
- [usage](#usage)
## install
clone this repo in your project directory
`git clone https://git.egfk.net/harper/shoal`
and import the package
```odin
import ecs "shoal/src"
```
## usage
first create a new app struct. this is where your systems and plugins live.
```odin
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.
``` odin
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\
```odin
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
```odin
ExampleComponent :: struct {}
```
and create it's storage
```odin
Example: ecs.Storage(ExampleComponent)
```
### spawn entities
create a new entity with `spawn_entity()`
```odin
main :: proc() {
entity := ecs.spawn_entity(&app)
}
```
and give it new components with `add_component()`
```od\
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
```odin
main :: proc() {
for entity_id, component in ecs.slice(&Example) {
//...
}
}
```
or if you know your storage only has one entry use `single()`
```odin
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()
```odin
ExamplePlugin :: proc(app: ^App) {
ecs.add_system(app, ecs.STARTUP, some_plugin_system)
}
```
```odin
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()`