Overview of Entreri's Main Classes
There are four classes that you will need to be comfortable with to use Entreri. They are:
The EntitySystem represents the game world or, equivalently, the collection of entities and components in that world. Entities are created from the factory methods provided by the EntitySystem, which they are then a member of until they are removed. Internally, the EntitySystem is responsible for storing and packing all of the component data into an efficient and cache-friendly manner. Luckily this has been hidden from you, and all you really need to do is add and remove entities as they are spawned or die according to your game rules. An entity created by a system is always referenced by the system and won't be garbage collected until it's been explicitly removed from the system.
The main methods you'll need are addEntity(), removeEntity(), iterator(), iterator(Class<? extends Component), and fastIterator(). The fastIterator() method returns a specialized iterator that efficiently iterates over entities matching a specific pattern of Components, but more on this will said in the ComponentIterator section.
An Entity is the basic unit or thing that can exist in the game world. A soldier on the battlefield is an entity, a bird or a tree is an entity. It can be as detailed as every bullet is an entity. You may also choose to design entities that logically represent collections, such as a particle-system entity instead of modeling each particle as an entity.
By itself, an Entity is a pretty boring object. It is only interested once Components have been attached to it. An Entity's components contain its data and implicitly describe the behaviors it can perform in a game. Because entities and components only hold and describe data, however, these behaviors must be implemented by the game when processing the system.
An Entity is a map from component type to an instance of that component. Because of this, it's best to avoid iterating directly over every entity in the system and accessing components by a map lookup. The ComponentIterator provides a much more efficient model using flyweight instances that avoids repeated invocations of a hash function.
Components describe the data associated with particular entities. You can think of adding a component to an entity as dynamically updating the entity's type by decorating it with the component's type. To use Entreri you must define your own component types specific to your game. Logically, a specific component type is a collection of properties, which are named, typed values. Internally, Entreri packs all values for a particular property together across all components so that garbage collection cache scrambling is avoided.
Because Entreri uses a little bit of black magic to achieve optimal performance, there are some limitations and conventions to how components are defined. A new component type must be a Java interface that extends Component. Each logical property is defined by a getter and setter method following the Java Bean semantics. The type of the property is defined by the return type of the getter. The setter must have a matching input parameter.
This convention can get you a long way. Entreri provides much more advanced control over component definition. See Defining Components for more details.
Entreri also provides an annotation processor that will generate an implementation of all discovered component interfaces that will be loaded at runtime when you add the component to an entity. This allows the component definitions to be very succinct while still letting the internal engine do its thing.
The ComponentIterator class is a specialized iterator that takes advantage of Entreri's entity component model. Instead of processing entities in a system and repeatedly checking if an entity matches a particular combinations of components you're interested in, you can configure the ComponentIterator with the required and optional component types and iterate with it.
The ComponentIterator creates special flyweight instances for each component type you configured. As you call the next() method of the iterator, the flyweight instances are updated to access the same correct component data for each matching entity. It will automatically skip over entities that don't fit the pattern.