System_EntityState class
A System applying EntityState on Entity based on its EntityStateComponent.
Applying = added/removed/modified Component of the Entity.
The System will update EntityStateComponent.currentState and
EntityStateComponent.previousState.
Based on http://www.richardlord.net/blog/finite-state-machines-with-ash but without the EntityStateMachine, because :
-
EntityState changes are applying only on existing
EntityviaEntityProcessingSystembehavior ofEntityStateSystem. -
If a
EntitySystemchange EntityStateComponent.state, theComponentofEntityaren't added/modify/removed, so internalComponentMapperof the System aren't impacted, and Aspect constraints of the System are keep. -
Other
EntitySystemcan compare the value of EntityStateComponent.previousState and EntityStateComponent.currentState to check if state has been changed since last process (to trigger some modifications). - More EntitySystem way of doing (IMHO)
class System_EntityState extends EntityProcessingSystem {
ComponentMapper<EntityStateComponent> _escMapper;
System_EntityState() : super(Aspect.getAspectForAllOf([EntityStateComponent]));
void initialize(){
_escMapper = new ComponentMapper<EntityStateComponent>(EntityStateComponent, world);
}
void processEntity(Entity entity) {
var esc = _escMapper.get(entity);
esc._previousState = esc._currentState;
if (esc.state != null && esc.state != esc.currentState){
var current = esc._states[esc.currentState];
var next = esc._states[esc.state];
assert(next != null);//, "state '${next}' is not defined");
_changeStateOf(entity, current, next);
esc._currentState = esc.state;
}
}
void _changeStateOf(Entity e, EntityState current, EntityState next) {
if (current == next) {
// nothing to do
} else {
if (current != null) {
//TODO optimize the computation of component diff
current.forEach((provider) {
var np = next.getByType(provider.type);
if (np == null || np.id() != provider.id()) {
e.removeComponentByType(provider.type);
}
});
}
// keep existing Component of the same type
// (not previously removed because same provider.id or managed outside of the state machine)
next.forEach((provider){
var components = world.componentManager.getComponentsByType(provider.type);
if (components == null || !components.isIndexWithinBounds(e.id) || components[e.id] == null) {
e.addComponent(provider.createComponent(e));
}
});
next.modifiers.forEach((modifier){
modifier.applyE(e);
});
e.changedInWorld();
}
}
}
Extends
EntitySystem > EntityProcessingSystem > System_EntityState
Constructors
new System_EntityState() #
System_EntityState() : super(Aspect.getAspectForAllOf([EntityStateComponent]));
Properties
Methods
void begin() #
Called before processing of entities begins.
void begin() {}
bool checkProcessing() #
Returns true if the system should be processed, false if not.
bool checkProcessing() => true;
void deleted(Entity e) #
void deleted(Entity e) {
if (_contains(e)) {
_removeFromSystem(e);
}
}
void disabled(Entity e) #
void disabled(Entity e) {
if (_contains(e)) {
_removeFromSystem(e);
}
}
void end() #
Called after the processing of entities ends.
void end() {}
void initialize() #
Override to implement code that gets executed when systems are initialized.
void initialize(){
_escMapper = new ComponentMapper<EntityStateComponent>(EntityStateComponent, world);
}
void inserted(Entity entity) #
Called if the system has received an entity it is interested in, e.g. created or a component was added to it.
void inserted(Entity entity) {}
void process() #
This is the only method that is supposed to be called from outside the library,
void process() {
if(checkProcessing()) {
begin();
processEntities(_actives.readOnly);
end();
}
}
void processEntities(ReadOnlyBag<Entity> entities) #
Any implementing entity system must implement this method and the logic to process the given entities of the system.
void processEntities(ReadOnlyBag<Entity> entities) => entities.forEach((entity) => processEntity(entity));
void processEntity(Entity entity) #
Process a entity this system is interested in.
void processEntity(Entity entity) {
var esc = _escMapper.get(entity);
esc._previousState = esc._currentState;
if (esc.state != null && esc.state != esc.currentState){
var current = esc._states[esc.currentState];
var next = esc._states[esc.state];
assert(next != null);//, "state '${next}' is not defined");
_changeStateOf(entity, current, next);
esc._currentState = esc.state;
}
}
void removed(Entity entity) #
Called if an entity was removed from this system, e.g. deleted or had one of it's components removed.
void removed(Entity entity) {}