How does ZayES compare with Ashley?

Why doesn’t EntityData have a method like

EntityData.createNewEntity(EntityComponent... components)

?

I have to do instead

 entityData.setComponents(entityData.createEntity(),
//                the components...
 );

Because a pure entity creation is only a matter of attributing an ID. An entity doesn’t need any component to exist. The components addition and removal are common events in the life of an entity.

Althought nothing prevent you to create such method ^^

Oh, ok. I thought that there was some “bad practice” involved in my usage :smile:

An API should be useful but should also make clear specific things about what’s going on under the covers. In this case, splitting creation from setting components communicates, at least subliminally, some key concepts:

  1. creating an entity is an entirely different thing than setting components on it.
  2. creating an entity is a cheap, nearly-free operation.
  3. settings components is not an atomic operation and certainly not atomic with respect to entity creation.

The last one is important, I guess.

re: documentation, I’m struggling with this right now. I want to start a Zay-ES documentation push like there was for Lemur… and one necessary set of pages is general ES stuff. There is already some stuff on the JME wiki but it might be nicer to have something closer to where Zay-ES lives.

Anyone is welcome to contribute to that as I can no longer easily run off the “ES manifesto” from memory any more. Too internalized by now. :smile:

Edit: would love help with that more general ES wiki page for anyone wanting to volunteer.

Maybe that way:

Manifest
General ES stuff. The problem with that part will be that I’m not a native English speaker on one hand and on the other hand I’m very new to this topic.

Patterns

  • Visual System (important to see something on the screen)
  • Control System (a state which changes the position of the visual things)
  • Decay System
  • Link System (it is some kind of a entity follows entity which I often use, for example light source follows hero, some orbital stuff rotating around my space ship)
  • Collistion System (just basic with radius to get the idea)
  • Damage System (mine is for example build that way that I have entites with damage component to apply damage to others and entites with shiled components which absorbs damage, I callculate up each other)
  • Explosion Effect System (to show how easy that can be solved with ES)

I propose examples because ES needs something concrete to show how beautiful it solves problems. I think the patterns above can be found in many games I suppose. Not that sure, I’m still too new to this topic, but would love to contribute some examples.
You guys could come up with the expert stuff :wink:

Additional question: where?
:wink: here in jme? I don’t think I have the right to write something…

I suggest beside Zay-ES.

I would be glad to describe some design too. I think it is important to provide many little exemple to cover the reccurent need and allow one to understand how to solve many problems. That’s what I lacked the most at the beginning.

But I think its also a good thing to present some more complexe/complete stuffs, because it’s sometime hard to understand the big scheme.

I found in the internet some simple examples, even the one in JME is very basic. The problem with those simple, basic example for me was that I could not see what happens, I had no real feedback only a theoretical one. From that I was unable to understand it. That’s why I suggested the visual one. As soon as I had that from asteroid panic, I had something which gives me feedback, that was the beginning of understanding.
Of course I started then to understand as well the theoretical samples I found much better, as I had some kind of big picture, as you said.

I also like the beginners section in JME, so somehow it would be cool if we had samples which build on each others.

Me again: I started a blog article series on http://fprintf.logdown.com/ about how to use an ES with a sample game. This may or may not be useful. I have so fare 4 articles and 2 of them online. Maybe the sample can be reused in some way?

2 Likes

Lovely idea, definitely useful articles. Keep up the good work!

Please have a look at this code:

public class EnemyCollisionState extends BaseAppState {

    private EntityData ed;
    private EntitySet entities;
    private EntitySet shootable;

    @Override
    protected void initialize(Application app) {
        ed = getState(EntityDataState.class).getEntityData();
        entities = ed.getEntities(AOE.class, HPDeltaPF.class);
        shootable = ed.getEntities(Shootable.class);
    }

    @Override
    protected void cleanup(Application app) {
        // Release the entity set we grabbed previously
        entities.release();
        entities = null;
        shootable.release();
        shootable = null;
    }

    @Override
    public void update(float tpf) {
        entities.applyChanges();
        shootable.applyChanges();
        for (Entity a : entities) {
            Geometry aoe = (Geometry) getState(ModelState.class).getSpatial(a.getId()).getChild("hitbox");
            for (Entity s : shootable) {
                Geometry enemy = (Geometry) getState(ModelState.class).getSpatial(s.getId()).getChild("hitbox");
                if (checkCollision(aoe, enemy)) {
                    ed.setComponent(ed.createEntity(),
                            ed.getComponent(a.getId(), HPDeltaPF.class),
                            new Touching(s.getId())
                            );
                }
            }
        }
    }

    @Override
    protected void onEnable() {
    }

    @Override
    protected void onDisable() {
    }
}

Basically I want to apply a damage per second over entities that steps inside an area. It probably works however this code creates new entities for each tpf… probably not the best approach :frowning:

My DOT is doing the same : create a damaging entity each time the entity takes damage. But of course, my DOT doesn’t tick at each game loop ! only three times per second in my game :smile: This leads to much less entity creation (if we have to worry about it).

Off topic : you will certainly find it more simple to create a dedicated appstate to create your systems. Mine have four methods to overide :

  • OnEntityAdded(Entity e)
  • onEntityRemoved(Entity e)
  • onEntityUpdated(Entity e)
  • onEachTick(Entity e)

Plus an abstract one that need to be overriden :

  • registerTo(Class<? extends EntityComponent> compClasses…)

This gives a good canvas. here is the code if someone interested :

public abstract class Processor extends AbstractAppState {

protected EntityData entityData;
private Map<String, EntitySet> sets = new HashMap<>();

@Override
public final void initialize(AppStateManager stateManager, Application app) {
	super.initialize(stateManager, app);
    entityData = stateManager.getState(DataState.class).getEntityData();

    registerSets();
    for(EntitySet set : sets.values())
        for (Entity e : set)
            onEntityAdded(e);
    onInitialized(stateManager);
}

@Override
public final void update(float elapsedTime) {
	if(!isEnabled())
		return;
	try{
        for(EntitySet set : sets.values()){
	        if (set.applyChanges()) {
	            for (Entity e : set.getChangedEntities()) {
	            	onEntityUpdated(e);
	            }
	            for (Entity e : set.getAddedEntities()) {
	            	onEntityAdded(e);
	            }
	            for (Entity e : set.getRemovedEntities()) {
	            	onEntityRemoved(e);
	            }
	        }
            for (Entity e : set) {
            	onEntityEachTick(e);
            }
        }
        onUpdated();
	} catch(RuntimeException e){
		LogUtil.severe("Exception in processor : " + this.getClass().getSimpleName() + " : " + e.getMessage());
		e.printStackTrace();
		
	}
}

@Override
public final void cleanup() {
    for(EntitySet set : sets.values())
    	for (Entity e : set)
    		onEntityRemoved(e);
    onCleanup();
    for(EntitySet set : sets.values())
    	set.release();
    super.cleanup();
}

@SafeVarargs
protected final void registerDefault(Class<? extends EntityComponent>... compClass){
	sets.put("", entityData.getEntities(compClass));
}

@SafeVarargs
protected final void register(String setName, Class<? extends EntityComponent>... compClass){
	sets.put(setName, entityData.getEntities(compClass));
}

protected EntitySet getDefaultSet(){
	return sets.get("");
}

protected EntitySet getSet(String setName){
	return sets.get(setName);
}

protected final void setComp(Entity e, EntityComponent comp){
	entityData.setComponent(e.getId(), comp);
}

protected final <T extends EntityComponent> void removeComp(Entity e, Class<T> compClass){
	entityData.removeComponent(e.getId(), compClass);
}
/**
 * Activate the system.
 *
 * @return entity used with this system.
 */
protected abstract void registerSets();

protected void onInitialized(AppStateManager stateManager){}

/**
 * Called each frame.
 *
 * @param tpf
 */
protected void onUpdated(){}

/**
 * Called when an entity is added.
 *
 * @param e entity to add.
 */
protected void onEntityAdded(Entity e){}

/**
 * Called when an entity got an update.
 *
 * @param e updated entity.
 */
protected void onEntityUpdated(Entity e){}

/**
 * Called when an entity is removed.
 *
 * @param e removed entity.
 */
protected void onEntityRemoved(Entity e){}

/**
 * Called each frame for each entity.
 *
 * @param e removed entity.
 */
protected void onEntityEachTick(Entity e){}

/**
 * Called when the system is removed, used to clean his mess.
 */
protected void onCleanup(){}

}

I think this was already covered above. Add the damage entity when they walk into the area. Remove it when they walk out.

The other damage system will apply the damage every frame while that entity exists. No need to create an entity per frame.

So… I have to somehow bind together the ID of the target with the ID of the AOE. I think that I should create a new Entity with this relationship, right?

{Target, AOE}

I can’t bind the Target component directly on the AOE, as it might affect multiple Targets at once. But if I create new Entities for each collision, am I supposed to check if is already present before creating it?

if (getEntity(Target, AOE)==null)
createEntity(Target, AOE)

Maybe I’m missing something obvious… :frowning:
EDIT: It would probably work, but feels unnecessarily cumbersome…

So, just to make sure we are all on the same page. This discussion assumes you’ve read:

It seems like you probably have but I felt it should be explicit.

If I understand your issue then, it’s not how to add the damage entity when they enter the area but how to remove it when they’ve left. You have a few options here based on how scalable you want to be.

For a few hundred active AOEs… just keep a data structure in the system that is detecting when entities enter/exit the AOEs. A map of <aoe entityId + mob entityId, damage entityId> or whatever. Managing data structures inside the system like this is perfectly fine for most games that won’t run on giant server farms. When a mob leaves the area, look up its damage entity ID and remove it or decay it.

The purely scalable way would have some kind of CreatedBy component that is added to the damage entity and points back to the AOE. So when a mob leaves the AOE you look that up. It’s essentially the same processing you do in the last paragraph but less efficient. If your entities are basically in memory anyway then just use the easy way from above.

Note: an even better option that handles things like fire better would be to automatically put a decay component on any damage entity applied. Then while the mob is still in the AOE, just update the decay component on the damage entity. Now, you might say “but wait, isn’t that the same lookup as above but now I have to do it all the time?” Sort of… except you were already looping over all mob entities in the active AOEs. Now you wouldn’t have to do that anymore since you’d be iterating over the damage entities and checking to see if their target is still in an AOE. It’s effectively the same processing but now you’ve moved it to what you are actually managing: damage. It’s more “ES” and is precisely the kind of different way of looking at a problem that a data-oriented approach provides.

So basically this:

…And have a decay that lasts one tick?

No… he creates an entity every time. I’m just saying to reset the decay component to a bit more into the future.

No… have a decay that lasts however long you want the damage to keep going after the step out of the AOE. Most damage might continue damaging for at least a few frames (especially fire)… and it nicely covers the case where they jump out and into the AOE really quickly.

Yes… if you only want damage to instantly stop then set the decay very small. But large enough that it survives for just one frame. (Though even if not then it will get recreated and it’s just a tad wasteful is all.)

That way you could have more or less sticky damage. Love the idea. I will add that to my list of sytems :smile:

I’d like to use a Filter for when I DON’T have a component… like this:

entities = ed.getEntities(Filters.and(MycomponentA.class, Filters.not(MycomponentB.class));

So I want entities to be populated by entities which have a ComponentA and don’t have ComponentB…

My use case: when the hitpoints are depleted, the entity is marked as EOL. However, there are some entities that are permanent even when the hitpoint are depleted, so I’d like to attach a “Unremovable” component when needed.

The Entity removal system looks for entities that are marked as EOL but are not marked as Unremovable…

I’d like to keep the life checking system agnostic of the “unremovable” component.

Good or bad practice?