Table of Contents

Components

Storing Data

In Frent, you compose entities using components. Components can be almost anything.

To create an entity from some components, you must use the World class. Think of the World like an optimized collection of entities.

In the example on the right, you can see the Name and Species component being used to create an entity. But components can do more than just store data - they can have behavior.

Adding Behavior

Implementing behavior in a component usually starts with some kind of IUpdate interface. The most simple of these interfaces is, well, IUpdate. This interface requires an Update method with zero arguments. Different IUpdate interfaces have different arguments for different purposes.

On the right, you can see the behavior of Name.Update, but where is its output? Add a world.Update(); call after entity creation, which calls all Update methods on all components in the world.

Note

What is a record struct? What is a using statement?

Component interfaces

There are many update interfaces, each with a different purpose, all with a Update method. The main interfaces are: IUpdate, IEntityUpdate, IUniformUpdate<TUniform>, and IEntityUniformUpdate<TUniform>. Each interface name follows the scheme of I[...]Update. The content inside the brackets tell you what arguments the update method will have. For example, IUpdate has no arguments and IEntityUniformUpdate<TUniform> has two arguments (Entity self, TUniform uniform).

Try adding behavior to the Decay component below such that the entity is deleted once the decay timer is over. You will need to change the interface used to IEntityUpdate to get access to the Entity from inside the update method. You can delete an entity by calling the .Delete() instance method.

Interacting Components

A single component is boring. Components together strong. While you can use entity.Get<T> to get components on the same entity to interact with, this method is verbose and slow.

To automatically inject a component value into the Update method, simply add a generic type. IUpdate.Update() becomes IUpdate<TComp>.Update(ref TComp). If you need another component injected, add another generic type.

Try modifying the Decay component above to take into account DecaySpeed when decrementing. You'll need IEntityUpdate<T> for this one.

Component lifetime

All components have a lifetime based on when they enter and exit the world.

You can hook onto these events with the IInitable and IDestroyable interfaces.

Interface Invoked when?
IInitable Component added, entity created
IDestroyable Component removed, entity deleted

Note that since components can be added to multiple entities, the Init/Destroy methods are not always guaranteed to occur as a pair.

In addition, all destroyers are called when a world is disposed of. Try removing the e.Delete() line on the right, and the using statement will implicitly call the destroyer.