diff --git a/.travis.yml b/.travis.yml index 0eaca80..230bf4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,6 @@ branch: only: - "master" language: go -go_import_path: engo.io/ecs +go_import_path: github.com/EngoEngine/ecs go: - 1.6.2 diff --git a/README.md b/README.md index 7fb1f1c..3607907 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/EngoEngine/ecs.svg?branch=master)](https://travis-ci.org/EngoEngine/ecs) -This is our implementation of the "Entity Component System" model in Go. It was designed to be used in `engo`, however +This is our implementation of the "Entity Component System" model in Go. It was designed to be used in `engo`, however it is not dependent on any other packages so is able to be used wherever! ## Basics @@ -10,16 +10,16 @@ In the Entity Component System paradigm, you have three elements; * Entities * Components -* Systems. +* Systems. -In our implementation, we use the type `World` to work with those `System`s. Each `System` can have references to any number (including 0) of entities. And each `Entity` can have as many `Component`s as desired. +In our implementation, we use the type `World` to work with those `System`s. Each `System` can have references to any number (including 0) of entities. And each `Entity` can have as many `Component`s as desired. An example of creating a `World`, adding a `System` to it, and update all systems ```go -// Declare the world - you can also use "var world ecs.World" +// Declare the world - you can also use "var world ecs.World" world := ecs.World{} -// You can add as many Systems here as you like. The RenderSystem provided by `engo` is just an example. +// You can add as many Systems here as you like. The RenderSystem provided by `engo` is just an example. world.AddSystem(&engo.RenderSystem{}) // This will usually be called within the game-loop, in order to update all Systems on every frame. @@ -39,10 +39,10 @@ type System interface { } ``` -What does this say? It needs to have an `Update` method (which is called from `world.Update`), and it needs to have a `Remove(ecs.BasicEntity)` method. Why require a Remove method, but not an Add method? Because there's no 'generic' `Add` method (the parameters may change), while in order to remove something, all you need it the unique identifier (as provided by the `BasicEntity`). +What does this say? It needs to have an `Update` method (which is called from `world.Update`), and it needs to have a `Remove(ecs.BasicEntity)` method. Why require a Remove method, but not an Add method? Because there's no 'generic' `Add` method (the parameters may change), while in order to remove something, all you need it the unique identifier (as provided by the `BasicEntity`). ### Initialization -Optionally, your `System` may implement the `Initializer` interface, which allows you to do initialization for the given `World`. Basically, it allows you to initialize values, without having to call the function manually before adding it to the `World`. Whenever you add a `System` (one that implements the `Initializer` interface) to the world, the `New` method will be called. +Optionally, your `System` may implement the `Initializer` interface, which allows you to do initialization for the given `World`. Basically, it allows you to initialize values, without having to call the function manually before adding it to the `World`. Whenever you add a `System` (one that implements the `Initializer` interface) to the world, the `New` method will be called. ```go type Initializer interface { @@ -53,7 +53,7 @@ type Initializer interface { ``` ### Priority -Optionally, your `System` may implement the `Prioritizer` interface, which allows the `World` to sort the `System`s based on that priority. If omitted, a value of `0` is assumed. +Optionally, your `System` may implement the `Prioritizer` interface, which allows the `World` to sort the `System`s based on that priority. If omitted, a value of `0` is assumed. ```go type Prioritizer interface { @@ -65,7 +65,7 @@ type Prioritizer interface { ## Entities and Components Where do the entities come in? All game-logic has to be done within `System`s (the `Update` method, to be precise)). `Component`s store data (which is used by those `System`s). An `Entity` is no more than a wrapper which combines multiple `Component`s and adds a unique identifier to the whole. This unique identifier is nothing magic: simply an incrementing integer value - nothing to worry about. -> Because the precise definition of those `Component`s can vary, this `ecs` package provides no `Component`s -- we only provide examples here. The `engo.io/engo/common` package offers lots of `Component`s and `System`s to work with, out of the box. +> Because the precise definition of those `Component`s can vary, this `ecs` package provides no `Component`s -- we only provide examples here. The `github.com/EngoEngine/engo/common` package offers lots of `Component`s and `System`s to work with, out of the box. Let's view an example: @@ -87,7 +87,7 @@ type Player struct { } ``` -Here, the type `Player` is made out of three elements: the unique identifier (`ecs.BasicEntity`) and two `Component`s. A `System` may make use of one or more of those `Component`s. Which are required, is defined by the `Add` method on that `System`. +Here, the type `Player` is made out of three elements: the unique identifier (`ecs.BasicEntity`) and two `Component`s. A `System` may make use of one or more of those `Component`s. Which are required, is defined by the `Add` method on that `System`. Let's view a few examples: @@ -111,7 +111,7 @@ for _, system := range world.Systems() { // Use a type-switch to figure out which System is which switch sys := system.(type) { - + // Create a case for each System you want to use case *MySystem1: sys.Add(&player.BasicEntity, &player.SpaceComponent) @@ -121,13 +121,13 @@ for _, system := range world.Systems() { } ``` -That is all there is to it. +That is all there is to it. ## Custom Systems - How to save Entities? -You more than likely will want to create `System`s yourself. We will now go in depth on what you should do when defining your own `Add` method for your `System`. As seen above, you can create any number (and type of) parameters you want. +You more than likely will want to create `System`s yourself. We will now go in depth on what you should do when defining your own `Add` method for your `System`. As seen above, you can create any number (and type of) parameters you want. -> We do ask you to let *the first argument* be of type `*ecs.BasicEntity` - as a general rule. +> We do ask you to let *the first argument* be of type `*ecs.BasicEntity` - as a general rule. Your `System` should include an array, slice or map in which to store those entities. Now it is important to note that you're not receiving entities per se -- you are receiving references to the `Component`s you need. The actual `Entity` (type `Player` in our example) may contain way more `Component`s. You will most-likely want to create a struct for you to store those pointers in. An example: @@ -147,10 +147,10 @@ func (m *MyAwesomeSystem) Add(basic *ecs.BasicEntity, space *SpaceComponent) { ``` > ### NOTE -> As a convention, please include "System" in the name of your `System` -- at the end. When you define a struct (which contains pointers, as opposed to the `Player` struct we created earlier), please replace that `System` part with `Entity`. You should **only** use this newly-created struct in your similarly-named `System`. You will usually *never* want to export that `Entity` definition, as it is only being used in that `System`. If your system would be called `BallMovementSystem`, then your struct would be called `ballMovementEntity`. +> As a convention, please include "System" in the name of your `System` -- at the end. When you define a struct (which contains pointers, as opposed to the `Player` struct we created earlier), please replace that `System` part with `Entity`. You should **only** use this newly-created struct in your similarly-named `System`. You will usually *never* want to export that `Entity` definition, as it is only being used in that `System`. If your system would be called `BallMovementSystem`, then your struct would be called `ballMovementEntity`. ### Removing Entities from your System -Your `System` must implement the `Remove` method as specified by the `System` interface. Whenever you start storing entities, you should define this method in such a way, that it removes the custom-created non-exported `Entity`-struct from the array, slice or map. An `ecs.BasicEntity` is given for you to figure out which element in the array, slice or map it is. +Your `System` must implement the `Remove` method as specified by the `System` interface. Whenever you start storing entities, you should define this method in such a way, that it removes the custom-created non-exported `Entity`-struct from the array, slice or map. An `ecs.BasicEntity` is given for you to figure out which element in the array, slice or map it is. ```go // Remove removes the Entity from the System. This is what most Remove methods will look like @@ -160,7 +160,7 @@ func (m *MyAwesomeSystem) Remove(basic ecs.BasicEntity) { if entity.ID() == basic.ID() { delete = index break - } + } } if delete >= 0 { m.entities = append(m.entities[:delete], m.entities[delete+1:]...) @@ -169,7 +169,7 @@ func (m *MyAwesomeSystem) Remove(basic ecs.BasicEntity) { // OR, if you were using a `map` instead of a `slice`: -// Remove removes the Entity from the System. As you see, removing becomes easier when using a `map`. +// Remove removes the Entity from the System. As you see, removing becomes easier when using a `map`. func (m *MyAwesomeSystem) Remove(basic ecs.BasicEntity) { delete(m.entities, basic.ID()) } @@ -177,10 +177,10 @@ func (m *MyAwesomeSystem) Remove(basic ecs.BasicEntity) { ``` > #### NOTE -> Even though that a `map` looks easier, if you want to loop over that `map` each frame, writing those additional lines to use a `slice` instead, is definitely worth it in terms of runtime performance. Iterating over a `map` is a lot slower. +> Even though that a `map` looks easier, if you want to loop over that `map` each frame, writing those additional lines to use a `slice` instead, is definitely worth it in terms of runtime performance. Iterating over a `map` is a lot slower. ## Custom Systems - The Update method -Whatever your `System` does on the `Update` method, is up to you. Each `System` is unique in that sense. If you're storing entities, then you might want to loop over them each frame. Again, this depends on your use-case. +Whatever your `System` does on the `Update` method, is up to you. Each `System` is unique in that sense. If you're storing entities, then you might want to loop over them each frame. Again, this depends on your use-case. ```go func (m *MyAwesomeSystem) Update(dt float32) { @@ -249,14 +249,14 @@ func (m *MySystem) AddByInterface(o ecs.Identifier) { } ``` -To use the system, instead of `w.AddSystem()` use +To use the system, instead of `w.AddSystem()` use ```go var myable *Myable w.AddSystemInterface(&MySystem{}, myable, nil) ``` -### Note +### Note This takes **a pointer to** the interface that the system needs implemented to use AddByInterface. Finally, to add an entity, rather than looping through all the systems, you can just diff --git a/doc.go b/doc.go index 69a8d05..c1b3bfe 100644 --- a/doc.go +++ b/doc.go @@ -33,4 +33,4 @@ // // For instance, an animation system may render entities possessing animation // components. -package ecs // import "engo.io/ecs" +package ecs