esper - API documentation

Processors

class esper.Processor

Base class for all Processors to inherit from.

Processor instances must contain a process method, but you are otherwise free to define the class any way you wish. Processors should be instantiated, and then added to the current World context by calling esper.add_processor(). For example:

   my_processor_instance = MyProcessor()
   esper.add_processor(my_processor_instance)

All the Processors that have been added to the World context will have their

esper.Processor.process() methods called by a single call to esper.process(). Inside the process method is generally where you should iterate over Entities with one (or more) calls to the appropriate methods:

def process(self):
    for ent, (rend, vel) in esper.get_components(Renderable, Velocity):
        your_code_here()

Components

esper does not define any specific Component base class to inherit from. Instead, a normal Python class can be used. Also, while it’s not required, the the @dataclass decorator from the dataclasses module can be useful to help write compact Component classes.

The World context

esper.switch_world(name: str) None

Switch to a new World context by name.

Esper can have one or more “Worlds”. Each World is a dedicated context, and does not share Entities, Components, events, etc. Some game designs can benefit from using a dedicated World for each scene. For other designs, a single World may be sufficient.

This function will allow you to create and switch between as many World contexts as required. If the requested name does not exist, a new context is created automatically with that name.

Note

At startup, a “default” World context is active.

esper.delete_world(name: str) None

Delete a World context.

This will completely delete the World, including all entities that are contained within it.

Raises PermissionError if you attempt to delete the currently active World context.

esper.list_worlds() List[str]

A list all World context names.

esper.create_entity(*components: _C) int

Create a new Entity, with optional initial Components.

This funcion returns an Entity ID, which is a plain integer. You can optionally pass one or more Component instances to be assigned to the Entity on creation. Components can be also be added later with the esper.add_component() funcion.

esper.delete_entity(entity: int, immediate: bool = False) None

Delete an Entity from the current World.

Delete an Entity and all of it’s assigned Component instances from the world. By default, Entity deletion is delayed until the next call to esper.process(). You can, however, request immediate deletion by passing the immediate=True parameter. Note that immediate deletion may cause issues, such as when done during Entity iteration (calls to esper.get_component/s).

Raises a KeyError if the given entity does not exist in the database.

esper.entity_exists(entity: int) bool

Check if a specific Entity exists.

Empty Entities (with no components) and dead Entities (destroyed by delete_entity) will not count as existent ones.

esper.add_processor(processor_instance: Processor, priority: int = 0) None

Add a Processor instance to the current World.

Add a Processor instance to the world (subclass of esper.Processor), with optional priority.

When the esper.World.process() function is called, Processors with higher priority will be called first.

esper.remove_processor(processor_type: Type[Processor]) None

Remove a Processor from the World, by type.

Make sure to provide the class itself, not an instance. For example:

# OK:
self.world.remove_processor(MyProcessor)

# NG:
self.world.remove_processor(my_processor_instance)
esper.get_processor(processor_type: Type[Processor]) Processor | None

Get a Processor instance, by type.

This function returns a Processor instance by type. This could be useful in certain situations, such as wanting to call a method on a Processor, from within another Processor.

esper.component_for_entity(entity: int, component_type: Type[_C]) _C

Retrieve a Component instance for a specific Entity.

Retrieve a Component instance for a specific Entity. In some cases, it may be necessary to access a specific Component instance. For example: directly modifying a Component to handle user input.

Raises a KeyError if the given Entity and Component do not exist.

esper.components_for_entity(entity: int) Tuple[_C, ...]

Retrieve all Components for a specific Entity, as a Tuple.

Retrieve all Components for a specific Entity. This function is probably not appropriate to use in your Processors, but might be useful for saving state, or passing specific Components between World contexts. Unlike most other functions, this returns all the Components as a Tuple in one batch, instead of returning a Generator for iteration.

Raises a KeyError if the given entity does not exist in the database.

esper.add_component(entity: int, component_instance: _C, type_alias: Type[_C] | None = None) None

Add a new Component instance to an Entity.

Add a Component instance to an Entiy. If a Component of the same type is already assigned to the Entity, it will be replaced.

A type_alias can also be provided. This can be useful if you’re using subclasses to organize your Components, but would like to query them later by some common parent type.

esper.remove_component(entity: int, component_type: Type[_C]) _C

Remove a Component instance from an Entity, by type.

A Component instance can only be removed by providing its type. For example: esper.delete_component(enemy_a, Velocity) will remove the Velocity instance from the Entity enemy_a.

Raises a KeyError if either the given entity or Component type does not exist in the database.

esper.get_component(component_type: Type[_C]) List[Tuple[int, _C]]

Get an iterator for Entity, Component pairs.

esper.get_components(__c1: Type[_C], __c2: Type[_C2]) List[Tuple[int, Tuple[_C, _C2]]]
esper.get_components(__c1: Type[_C], __c2: Type[_C2], __c3: Type[_C3]) List[Tuple[int, Tuple[_C, _C2, _C3]]]
esper.get_components(__c1: Type[_C], __c2: Type[_C2], __c3: Type[_C3], __c4: Type[_C4]) List[Tuple[int, Tuple[_C, _C2, _C3, _C4]]]

Get an iterator for Entity and multiple Component sets.

esper.has_component(entity: int, component_type: Type[_C]) bool

Check if an Entity has a specific Component type.

esper.has_components(entity: int, *component_types: Type[_C]) bool

Check if an Entity has all the specified Component types.

esper.try_component(entity: int, component_type: Type[_C]) _C | None

Try to get a single component type for an Entity.

This function will return the requested Component if it exists, or None if it does not. This allows a way to access optional Components that may or may not exist, without having to first query if the Entity has the Component type.

esper.try_components(entity: int, __c1: Type[_C], __c2: Type[_C2]) Tuple[_C, _C2]
esper.try_components(entity: int, __c1: Type[_C], __c2: Type[_C2], __c3: Type[_C3]) Tuple[_C, _C2, _C3]
esper.try_components(entity: int, __c1: Type[_C], __c2: Type[_C2], __c3: Type[_C3], __c4: Type[_C4]) Tuple[_C, _C2, _C3, _C4]

Try to get a multiple component types for an Entity.

This function will return the requested Components if they exist, or None if they do not. This allows a way to access optional Components that may or may not exist, without first having to query if the Entity has the Component types.

esper.process(*args: Any, **kwargs: Any) None

Call the process method on all Processors, in order of their priority.

Call the esper.Processor.process() method on all assigned Processors, respective of their priority. In addition, any Entities that were marked for deletion since the last call will be deleted at the start of this call.

esper.timed_process(*args: Any, **kwargs: Any) None

Track Processor execution time for benchmarking.

This function is identical to esper.process(), but it additionally records the elapsed time of each processor call (in milliseconds) in the`esper.process_times` dictionary.

esper.clear_database() None

Clear the Entity Component database.

Removes all Entities and Components from the current World. Processors are not removed.

esper.clear_cache() None

Manually clear the Component lookup cache.

Clearing the cache is not necessary to do manually, but may be useful for benchmarking or debugging.

esper.clear_dead_entities() None

Finalize deletion of any Entities that are marked as dead.

This function is provided for those who are not making use of esper.add_processor() and esper.process(). If you are calling your processors manually, this function should be called in your main loop after calling all processors.

Events

For convenience, esper includes functionality for dispatching and handling events. This is limited in scope, but should be robust enough for most general use cases.

esper.dispatch_event(name: str, *args: Any) None

Dispatch an event by name, with optional arguments.

Any handlers set with the esper.set_handler() function will recieve the event. If no handlers have been set, this function call will pass silently.

Note::

If optional arguments are provided, but set handlers do not account for them, it will likely result in a TypeError or other undefined crash.

esper.set_handler(name: str, func: Callable[[...], None]) None

Register a function to handle the named event type.

After registering a function (or method), it will receive all events that are dispatched by the specified name.

Note

A weak reference is kept to the passed function,

esper.remove_handler(name: str, func: Callable[[...], None]) None

Unregister a handler from receiving events of this name.

If the passed function/method is not registered to receive the named event, or if the named event does not exist, this function call will pass silently.