ZincECS
is an entity-component-system package inspired by Simon Schmid's Entitas-CSharp and Atom proof-of-concept but for the go language. ZincECS uses code-generation to achieve a nice API similar to EntitasECS using the built-in ZincCLI. This package puts focus on modularity and ease of use with performance coming in as a close second.
This will install the ZincCLI along with the zinc
package.
go get github.com/SirMetathyst/zinc/...
There isn't much we can do without any components so lets go ahead and generate some before we start.
zinc component add -p components -n position -d x:float32 -d y:float32 -o ./components
zinc component add -p components -n velocity -d x:float32 -d y:float32 -o ./components
We first call the ZincCLI
and pass in some arguments. The p
argument tells the ZincCLI
that we want our generated component to have the package name of components
. Then we tell it we want a component with the name of position
and specify the data. The format must be in name:type
but no checks are done to ensure valid go code. Lastly, we give it a folder where we want our component files to be generated in. Now we have some components generated to play with.
package main
import (
"github.com/SirMetathyst/zinc"
// importing your component package will
// automatically register component types
// with the default entity manager
// see generated files for how to do it manually
// if required. The convention I use is to call it a "kit"
// where the root contains all your components and /systems
// contains all logic for those components
"xxx/xxx/to/yourkit"
)
func main() {
// create an entity
// uses the built-in default entity manager
id := zinc.CreateEntity()
// we can already use our component types
// setting a component will add or update it
yourkit.SetPosition(id, yourkit.PositionData{10, 10})
// get position with id
pos := yourkit.Position(id)
// there is also an API for passing in a different entity manager
// these end in X
pos := yourkit.PositionX(entityManager, id)
// getting all entity ids in the entity manager
entities := zinc.Entities()
// getting groups of entities with specific components
// will return a entity group that has position and velocity component
group1 := zinc.Group(zinc.AllOf(yourkit.PositionKey, yourkit.VelocityKey))
// ids of entities in group
group1.Entities()
// does the group have an entity?
group1.HasEntity(id)
// does the component exist for entity
ok := yourkit.HasPosition(id)
// delete the position component
yourkit.DeletePosition(id)
// will return a entity group that has position but not velocity component
group2 := zinc.Group(zinc.AllOf(yourkit.PositionKey).NoneOf(yourkit.VelocityKey))
}
Zinc has a simple, built-in way to init/update/cleanup your systems
sys := zinc.NewSystems()
sys.Add(yourkit.NewPositionSystem())
sys.Add(yourkit.NewAllSystems()...)
// init systems, must have `Initialize()` method
sys.Initialize()
// update systems, must have `Update(dt float64)` method
sys.Update(deltaTime)
// cleanup systems, must have `Cleanup()` method
sys.Cleanup()
then you can implement a system for moving your position components around. add the system to Systems
and loop through those and that's your game loop. You can even have systems for drawing things in a different Systems
instance and execute them at different times. You can even return Systems
of Systems
and update them as a group of systems as long as that type has the supported method.
import (
"github.com/SirMetathyst/zinc"
"github.com/xxx/yourkit"
)
// PositionSystem ...
type PositionSystem struct {
g zinc.G
em *zinc.EntityManager
}
// NewPositionSystem ...
func NewPositionSystem() *PositionSystem {
return &PositionSystem{
em: zinc.Default(),
g: zinc.Default().Group(zinc.AllOf(yourkit.PositionKey, yourkit.VelocityKey)),
}
}
// NewPositionSystemWith ...
func NewPositionSystemWith(em *zinc.EntityManager) *PositionSystem {
return &PositionSystem{
em: em,
g: em.Group(zinc.AllOf(yourkit.PositionKey, yourkit.VelocityKey)),
}
}
// Update ...
func (s PositionSystem) Update(dt float64) {
for _, id := range s.g.Entities() {
velocity := yourkit.VelocityX(s.em, id)
position := yourkit.PositionX(s.em, id)
position.X += velocity.X * dt
position.Y += velocity.Y * dt
yourkit.SetPositionX(s.em, id, position)
}
}
I dont really have a contribution guideline. Just post an issue or pull request if you'd like to add or change something in ZincECS
. I generally welcome pull requests but don't be disappointed if it gets rejected. You can always fork it.
- Zinckit - Collection of Systems and Components for
ZincECS
projects