Feel free to join the next Helmholtz Hacky Hour #26 on Wednesday, April 21, 2021 from 2PM to 3PM!

Commit 8e4646a4 authored by Martin Lange's avatar Martin Lange

added ECS-related explanation to every section

parent 1d313524
Pipeline #12103 passed with stage
in 13 seconds
......@@ -2,7 +2,9 @@
This projects demonstrates the use of an Entity-Component-System for the implementation of an individual-based model (IBM). We use Java and the ECS library [Artemis-odb](https://github.com/junkdog/artemis-odb) to build a simple grassing model.
The model description is structured following the ODD protocol (Grimm et al. 2006, 2010) to demonstrate the good fit of ECS and ODD.
The model description is structured following the ODD protocol (Grimm et al. 2006, 2010) to demonstrate the good fit of ECS and ODD. The complete model code is presented along with the descriptions. ECS-specific remarks are shown as indented notes:
> ECS-remarks look like this.
**Contents**
......@@ -35,8 +37,12 @@ The purpose of this model is to demonstrate the use of Entity-Component-Systems
In an ECS, all entities are generic, but characterized by the components they possess. Components contain an entity's state variables.
**Components**
In this grassing model, the only entities are grassers. All grassers possess the components `Position`, `Heading` and `Energy`. Behaviour of grassers is governed by the components `IsGrassing` or `IsSearching`, which each grasser possess one of.
> Components must extend `com.artemis.Component`.
Component `Position` contains continuous coordinates in a two-dimensional world.
```java
......@@ -55,7 +61,7 @@ public class Position extends com.artemis.Component {
}
```
Component `Heading` contains the angle the entity is heading towards.
Component `Heading` contains the angle the entity is heading towards, in radians.
```java
/// file:src/main/java/grassing/comp/Heading.java
......@@ -87,7 +93,7 @@ public class Energy extends com.artemis.Component {
}
```
Component `IsGrassing` labels an entity as currently following the grassing behaviour.
Component `IsGrassing` labels an entity as currently following the grassing behaviour. It contains no state variables.
```java
/// file:src/main/java/grassing/comp/IsGrassing.java
......@@ -96,7 +102,7 @@ package grassing.comp;
public class IsGrassing extends com.artemis.Component {}
```
Component `IsSearching` labels an entity as currently following the searching behaviour.
Component `IsSearching` labels an entity as currently following the searching behaviour. It contains no state variables.
```java
/// file:src/main/java/grassing/comp/IsSearching.java
......@@ -105,7 +111,11 @@ package grassing.comp;
public class IsSearching extends com.artemis.Component {}
```
Entities live on a two-dimensional landscape. The landscape is represented by a grid of grass the grassers consume.
**Resources**
> Resources are "things" that exist only once in the model, contrary to entities, and are potentially available for all submodels. Any instance of a Java class can become a resource. However, only one instance of each class is possible.
Grassers live on a two-dimensional landscape. The landscape is represented by a grid of grass the grassers consume.
```java
/// file:src/main/java/grassing/res/Grass.java
......@@ -126,7 +136,7 @@ public class Grass {
}
```
A single global pseudo random number generator is used for all processes thet include randomness.
A single global pseudo random number generator is used for all processes that include randomness.
```java
/// file:src/main/java/grassing/res/Randomness.java
......@@ -144,9 +154,13 @@ public class Randomness {
}
```
Spatial and temporal scales of the model are arbitrary. The duration of a model step is by orders of magnitude shorter than the average lifespan of an grasser.
## Process overview and scheduling
Processes in the model are grass growth, grasser metabolism, grasser reproduction and the two grasser behaviours grassing and searching. Processes are executed in the given order.
Processes in the model are grass growth, grasser metabolism, grasser reproduction and the two grasser behaviours grassing and searching. Processes are executed in that order.
> In the ECS, processes (or submodels, or systems) are added during world construction via `with(...)`. Resources are added via `.register(...)`.
```java
/// file:src/main/java/grassing/Main.java
......@@ -197,11 +211,13 @@ public class Main {
Grassers grass on the grass, and grass regrows. Grassers have a metabolism consuming their energy. When energy drops to zero, a grasser dies. Grassers reproduce stochastically.
Grassers have two different behaviours: grassing and searching. Behaviour changes based grass availability.
Grassers have two different behaviours: grassing and searching. Behaviour changes are based on grass availability.
## Initialization
The model is initialized with `NUM_GRASSERS` grassers. All grassers start with the grassing behaviour.
The model is initialized with `NUM_GRASSERS` grassers. All grassers start with components `Position`, `Heading`, `Energy` and `IsGrassing` (i.e. with the grassing behaviour).
Position and heading are initialized randomly. Energy is initialized with 1.0.
```java
/// Create entities
......@@ -221,11 +237,15 @@ private static void createEntities(World world, Random rng) {
Submodels are described in their order of execution.
> What the ODD calls submodels is called systems in the ECS world. A system must extend `com.artemis.BaseSystem` or one of it's many sub-classes that serve different purposes.
### Grass growth
Grass growth is logistic, with a capacity of 1.0.
The grassing system does not use any entities, but requires access to the `Grass` grid, which is "injected" by the ECS through the line `@Wire Grass grass;`.
> Since the grassing system does not use any entities, we simply extend `BaseSystem`. However, it requires access to the `Grass` grid, which is "injected" by the ECS through the line `@Wire Grass grass;`.
>
> The method `processSystem` is automatically called at every model step.
```java
/// file:src/main/java/grassing/sys/LogisticGrassGrowth.java
......@@ -263,6 +283,10 @@ The grasser metabolism works on all entities that have the component `Energy`.
In each iteration, grassers lose `consumption` energy. When it's energy drops to zero, a grasser dies.
> Here, we extend `IteratingSystem`, which carries out the work of iterating over the relevant entities. Method `process(int id)` is automatically called at every model step, for every entity (`id`) matching the system's required component(s). Here, we specified a single required component via `@All(Energy.class)`.
>
> To access the component `Energy` of any entity, we use `ComponentMapper<Energy>` in the line `Energy e = mEnergy.get(id);`. The mapper is injected by Artemis automatically, so we don't need to construct it.
```java
/// file:src/main/java/grassing/sys/Metabolism.java
package grassing.sys;
......@@ -302,6 +326,10 @@ In each iteration, each grasser reproduces with a fixed probability.
When reproducing, energy is split in half between the grasser and it's offspring. The offspring starts with the grassing behaviour.
> We extend `IteratingSystem` again. This time we wrote `@All({Position.class, Energy.class})`, which means that we are interested only in entities that have all listed components.
>
> This system also shows how to create entities in a running model.
```java
/// file:src/main/java/grassing/sys/Reproduction.java
package grassing.sys;
......@@ -350,7 +378,9 @@ The grassing behaviour system works on all entities that have the components `Po
If the grasser's energy is 1.0 or above, it does nothing. Otherwise, the grasser decides if there is enough grass in it's landscape cell. If this is the case, the grasser consumes grass, otherwise it switches to the searching behaviour.
The behaviour is switched by removing component `IsGrassing` and adding a new component `IsSearching`.
> The behaviour is switched by removing component `IsGrassing` and adding a new component `IsSearching`.
>
> We extend `IteratingSystem` again, and use `@All(...)` as before, but with an additional component. This time, we want only entities that have `IsGrassing`, in addition to `Position` and `Energy`, which is optional according to our model logic. Thus, grassers that are searching instead of grassing will not be processed by this system. In the `else` branch at the end of the code, we remove `IsGrassing` and add `IsSearching` instead, which means that the respective entity will not be processed here in the next step.
```java
/// file:src/main/java/grassing/sys/GrassingBehaviour.java
......@@ -406,7 +436,7 @@ The grassing behaviour system works on all entities that have the components `Po
The grasser decides if there is enough grass in it's landscape cell. If this is the case, the grasser switches to the searching behaviour. Otherwise, it continues searching ba a random walk.
The behaviour is switched by removing component `IsSearching` and adding a new component `IsGrassing`.
> The behaviour is switched by removing component `IsSearching` and adding a new component `IsGrassing`.
```java
/// file:src/main/java/grassing/sys/SearchBehaviour.java
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment