Undertsanding of Entities

This topic is about the understanding / usage of entity-systems. I read many articles about theses systems the best one was the articles of http://t-machine.org. But there are still some open questions especially in terms of JMonkey.



So for my basic understanding the entity is only a number which is representing a game-object (GO). The GO (entity) consist indirect of a various number of components. Theses components only store any data which are indirectly part of the GO. To change these data (concrete components) you have to use so called systems. theses systems can change the value (data) of components. One system is only responsible for a special type of components or a subs set of components. The system is working on theses subsets of components. That’s my current status about the structure of an entity-system in this case specially of t-machine.



One of my questions is now, where or how Should I call / execute the systems. Should they be called in the game-loop every time. Or is the game-loop only calling some of the systems (a subset) and the systems its self can / is calling other systems (if necessary because if you change one component maybe another component should be changed too) to change date of GOs? Or should I call the systems on special events? Or another thought was to send systems a command in a command queue for all components or for a subset of components for which the system is responsible, and the system is processing these commands on the components-data? But then the systems have to be run continuously which sounds and is a bit tricky.



So thank you for helping.

A system can be anything. Actually everything that is not a Component is part of a System. See it like this: There can be any code in the systems really but if it communicates with another system then its only via the Components which are exclusively system-independent data (e.g. no spatials or navmeshes or any data that would be special to one system only).

Systems are called from the game loop every frame. They do all the work. Your components should only be getters and setters.



Here is a snippit of one of my systems:



[java]

public class HealthSystem implements SubSystem {



public void update(EntitySystem es, float tpf) {

Map<Integer, Map<Class<? extends Component>, Component>> all = es.getAllEntitiesWithComponents(HealthComponent.class);



// go through each attackable entity

for (Integer entityId : all.keySet()) {

Map<Class<? extends Component>, Component> comps = all.get(entityId);



HealthComponent healthComp = (HealthComponent)comps.get(HealthComponent.class);

if (healthComp.getCurrentHp() <= 0) {

es.raiseEntityEvent(entityId, “death”);

es.saveComponent(entityId, new DeathComponent());

es.removeComponent(entityId, HealthComponent.class);

}

}

}

…

[/java]



Here is the HealthComponent:

[java]

public class HealthComponent implements Component {



private int maxHp;

private int currentHp;

private boolean beingDisposedOf;



public HealthComponent(int maxHp) {

this(maxHp, maxHp);

}



public HealthComponent(int maxHp, int currentHp) {

this.maxHp = maxHp;

this.currentHp = currentHp;

}



public int getCurrentHp() {

return currentHp;

}



public void setCurrentHp(int currentHp) {

this.currentHp = currentHp;

}



public int getMaxHp() {

return maxHp;

}



public void setMaxHp(int maxHp) {

this.maxHp = maxHp;

}



@Override

public Component clone() {

HealthComponent clone = new HealthComponent(maxHp, currentHp);

clone.beingDisposedOf = beingDisposedOf;

return clone;

}



boolean isBeingDisposedOf() {

return beingDisposedOf;

}



void setBeingDisposedOf(boolean disposing) {

this.beingDisposedOf = disposing;

}

}

[/java]



My advice would be to only use them if you have run into issues with an Actor (hierarchy-based) system. They can be tricky and a pain in the ass in many areas. But they offer great flexibility, modularity, and fewer “hacks”. Their learning curve is also steep.

2 Likes

Mythruna does keeps some other “rules” in its design that allows it to get away with some other things.



Most of my components are immutable. You can set a new version of the component to the entity but you can’t change the values in the component. This means that now matter how many views of an entity I might have across different threads, they all have a consistent view from their perspective and the entity only updates to the latest values the next time the query is done. This is truer to the spirit of the hard-core entity system where you could have systems spread across an entire server farm.



Mythruna does make a few performance optimizations taking advantage of the fact that it is NOT a server farm and is a single process server.



The true entity system will query for its entities on every “update”. Think if it like “SELECT * WHERE Hitpoints, Position, etc.” and then does an operation or set of operations on all of those. These queries are inherently thread-independent so you could pretty easily spread your systems across multiple threads if you wanted to.



In Mythruna, I encapsulate the recurring query into an EntitySet… (implements Set). So I can easily ask for the latest data every time. Because I’m single process, I have a bit of tricky code that distributes entity component changes to the active EntitySet instances. The different EntitySets keep the values until the next “query” is done and instead of requerying the data from scratch, it just applies the changes it accumulated. It’s like hiding an event driven architecture under a thread safe entity system umbrella.



Because I do it this way, I also go ahead and let the EntitySet user know which entities were added to the set (because they now match the filter), updated (but not in a way that affects their membership in the set), or removed from the set (because they no longer match the filter). This information could also easily be provided in other ways without event delivery so I didn’t see it as too much of an ES compromise.



I have some components that ARE mutable but they are thread-buffered in such a way that they meet my access requirements without having to swap out whole components. These are used for interpolated position information, for example, where a given thread already knows what time it wants some position information and so just asks for it. The small history buffer in the component then interpolates.



In my client-server environment, this is all very convenient because for query-only type of information (like a client requesting information) I don’t have to worry about gating access through locks or synchronization. Modification operations already go through a central command dispatch anyway so that the server has authoritative control over command sequence ordering. But the threading does allow command dispatch, physics, and potentially AI (though that will probably also go through command dispatch like a player) to run independently threaded. These already have a consistent idea of “current time” so it is less dangerous than it sounds.



…but I’m rambling a bit now.

5 Likes

And, by the way, my architecture is not really recommended for anyone that isn’t 100% comfortable with multi-threading. If you aren’t clear why Doug Lea is a minor-deity or why the java.util.concurrent API is such a good idea over a bunch of synchronized() blocks… then it’s probably best avoided altogether.

1 Like

@Sploreg Your solution goes straight with my thoughts and tries. So you only check if something is died in the game-loop so you have an extra system which is called by special events to change the health-value of your component? Or do you access the component directly at any needed position in your code?



@pspeed so the EntitySet is a kind of entity-manger which is holding your different entities and is reloading changed components if necessary? Only components which have a kind of flag-attribute like updated, added or removed will be re-queried for performance issues in the database?

So changes on components will be done over commands and the responsible command dispatcher is split in several subsystems for processing them parallel. So server internal changes will also be handled this way, with exception of the mutable ones in some cases?



So what I had in mind was not that wrong I guess xD

EntitySet can be thought of kind of like JDBC’s ResultSet conceptually. The only difference is that in this case I let the caller re-issue the query for new results… and as a convenience, I tell them what changed over the last time they executed the query. There could be any number of implementations under the covers that make that work (to include straight SQL queries each time) but I cache them for the entity set and keep track of the changes at runtime… so reissuing the query is essentially free.



The Entity object in this case is just a local copy for that EntitySet and it’s only loaded with the components that EntitySet needed. A different EntitySet with the same “entity” would have a different Entity instance.



A health value is changed by whatever is delivering damage. It creates a new Health component and sets it to the entity. It probably went straight to the “entity system” to do this instead of using an EntitySet… depending on the source of the damage. Usually when you are delivering damage to an entity you have the ID of the entity and the amount of damage. In my entity system, Entity objects are just local views of some subset of the entity’s components. But you can also go straight to the entity set to ask for a single component or set a component.

As paul is talking about, I also have evolved my ES a bit to have entity objects, which helper methods into the ES and to get the components. It doesn’t break the ES pattern, just bootstraps things a little and makes life easier.



But yes, @risor, the combat system does the damage, the health system could be combined with the combat system, but it was getting kind of large and I wanted to separate it out. It is more like: combat does the damage, health takes the damage and checks if the entity died or not. Sometimes I grab whatever components I want. Combat and Health systems both access the HealthComponent. Many systems access the LocationComponent. Systems talk through components. Some of my components are just a simple flag, such as the DeathComponent (it plays the death animation in the DeathSystem, that also handles removing the entity from the game).

It ends up giving you nice little modular packages.

Thank you, your answers made things a bit clearer to me. So I have to think about it again and try to transfer it to my project.



So one final Question: For updating the data of entities on the server side you get some kind of messages from the client like a message-type move which only contains for example the direction and speed + walking time. So for the other way around to give all clients a world update you send them complete entity-sets with all the data? I would guess the client also works with entities?

Everyone will likely do this a little differently.



In my case, the server knows which entity sets the clients are watching and only sends them relevant changes. For some objects, this includes Position changes.



Real time physics will work differently. Those components will not be sent over the network but there will time-buffered data one both the client and the server. The server has the master position buffer for the object and the client’s have their local view of the position buffer. A separate system knows where the players are and sends them highly compressed object state information just for their zone. I can get full position and rotation state compact enough to send 80 objects worth in a message smaller than typical MTU (less than 1500 bytes).



Component updates go out over TCP but state updates are spewed out over UDP using this separate system 20 times a second or so. The position buffers provide automatic interpolation on the client so if they miss a few packets it’s not a big deal.

I have processed the hints of your answers and came up with some ideas. What do you think about it?



I will divide systems which process and change the data of components in two groups. The first group of systems is called by the game loop every time and processes all kind of components of a specific subset. Such systems would be the healthsubsystem, collisionsubsystem and interestsubsystem. The second group of systems includes systems which are running continuously with a special time tick in a own thread. Each of theses systems has a special subset of components to process and also has a separate kind of event-queue. When for example a message from the client arrives the message will be converted into an event if necessary and has to be inserted in the matching queue of the system.



The interestsubsystem is responsible to collect the needed data for each client. So it is generating and changing the set of entities which are relevant for the client. So it is guaranties that the user only gets the needed data.

Hehe, everyone has a different entity system :stuck_out_tongue:



My entities are somewhat different as well:



My Entity manages physic state(needed be), and replication to clients (objects that are visible are replicated to the Clients, where they are kinda act like a proxy for interaction), while for persistence it has a descriptor object (or multiple if needed, or none if hollow object like a bullet) that is stored in the databases.)

Also it is a 64 bit scenegraph to allow enough distances for solar systems, parenting is done by the SEntity to allow network optimizing, (position of parented objects must only be send relative, so for example a spaceship with 30 modules only need one position update as long as they stay together.

After reading the article pspeed posted in another thread (thanks for the advise to read the comments. I skipped them :roll: Will read them while going by train today) I have questions reading this:



Probably one will have one system dealing with moving entities which should also handle collision if these entities have a collision component, right? (Otherweise I imagine it to be hard to handle collision). Now this system asks the entity for it’s bounding volume and tests for collisions. Afterwards it gets Geometries which collide with my entity and the geometries give access to the entitie’s id they belong to? (Or it’s just terrain and maybe other things hapen).

Do you need jME’s controls then for entities? It seems there are obsolete for this purpose?

And a third thought: Would a sword that my entity holds be an entity by itself or a component?

I think a sword is an entity.



In my case, I have a physics system. It watches entities with the components that it is interested in: Position, MassProperties, CollisionMesh, etc… The physics system then applies physics and resolves collisions. It is technically possible to split the physics into two separate systems… or even three: Physics, CollisionDetection, CollisionResolution… and have Collision components. I saw no point in doing that at the time.



Also, I should point out that I’ve written my own physics engine… so I can make these sorts of “to split or not to split” decisions. A physics engine that is more of a black box will likely have to be treated as a single system anyway.



None of my game systems deal with jme Geometry directly. That’s a view issue. Well, I do have some systems in the client layer that create Geometries and watch entities but that’s strictly view and those classes all use the entity system “read only”.

1 Like

The controls are kind of the opposite way of implementing entities as they are non-centralized operations each on their own geometries. That being said, I do use controls; only one to be exact. As Paul said: the entities are the model and the geometry is the view. So my control lives on the spatial and is basically a System of its own: it checks the location and transformation components of the entities, and moves the geometries accordingly. So if I want to move my entity, I update the LocationComponent. Then that frame the control will check, see that it has changed, and move the geometry accordingly.

This separates the geometry and the data, and I have found it to be very useful. And for networking it is extremely useful.

I did the same for animations and bones/skeleton.

1 Like

Sploreg’s high-level description could apply to my implementation exactly. Nice that we are all converging on similar approaches. :slight_smile:

Take a look at this implementation

http://www.gamadu.com/artemis/





I’m playing around with it right now :slight_smile:

My main complaint about artemis is that they’ve needlessly formalized “systems”. In an “Entity System”, “Systems” are just code that uses entities and components. They will often be managed by other things… for example, in the Mythruna client I use JME controls as some of my systems. On the server, I have different systems… some synchronized to an update loop and some that run their own update loops. It just depends.



Their description of entities and components is decent, though.

Developers with more experience will probably feel caged inside artemis but I think the formalized nature of artemis really shows the concept (or atleast it match my view of it).



I did not know what a entity system really is and I’m probably not gonna need it since I mainly use jME as my playground for shading experiments. :slight_smile:

@kwando said:
Developers with more experience will probably feel caged inside artemis but I think the formalized nature of artemis really shows the concept (or atleast it match my view of it).

I did not know what a entity system really is and I'm probably not gonna need it since I mainly use jME as my playground for shading experiments. :)


Entities and components _should_ be strictly formalized. You _should_ feel caged for a while because that's the OOP reflexes being properly repressed and maligned.

But focusing on system formalization is wrong-headed, in my opinion. The fact that the systems require some kind of bit identifier is a further red flag that they have something wrong.

It's a decent example to look at, though. There was another one I looked at briefly and dropped it because their components had "code" in them. A survey of all of these different implementations is worth doing.