Entity System with Artemis example

@t0neg0d read more

No matter how self-contained your ES is, it still must be wrapped into OOP… there is no way around this…. it starts as OOP, becomes ES and then is used in OOP. This is Java after all.
Yep, its till OOP but it is a completly different style of coding.
If you have 3 separate systems to manage damage, have you saved yourself anything at this point? Besides the 2 extra threads (that will eventually be locked and waiting their turn by the others to ensure you don’t corrupt the data) to manage a single component of some entity. On top of this, you have to collect the list of components 3 separate times
Where do we have 3 systems in pspeeds example? You can add damage componentes everywhere to the unit and there exists only one "system" which is subtracting the health of the unit and removing the damage components.
that will eventually be locked and waiting their turn by the others to ensure you don’t corrupt the data
This problem does not exists.

Here is the ES manifesto:
http://hub.jmonkeyengine.org/forum/topic/entitymonkey-a-simple-entity-system-for-jme/#post-186678
and here pspeed explains EntitySets:
http://hub.jmonkeyengine.org/forum/topic/an-introduction-to-entity-systems/#post-196576

Btw my entity system si basically more procedual than oop, the oop are just there because there is no struct in java, if it were i would not that much objects at all.

@t0neg0d said: One last thing that makes me stand-off-ish about ES is... it's become the latest fad... and that usually means that people will find a way to use the fad, whether or not it is a) appropriate or b) the best solution of task at hand.

Not saying I think they are not useful… especially in game development, however, it is hard to weed your way through the bullshit when people are saying it cures cancer AND contains your personal key to salvation… not to mention it is tasty on toast.

Yeah agree. And I also think its not an OOP pattern. The implementation we describe is an OOP implementation but the ES details per se don’t resemble OOP at all. Thats why I definitely would not recommend it to anyone learning java, jme and coding all at the same time. Also its bloat for some kinds of games really. You want it when you know that you don’t yet know what you want but that it will be big, to put it this way ^^

1 Like

Hi atomix,

I was hoping you could fix the link you provided as the zip file is currently unavailable at that url

I am quite interested in how you are using Artemis to handle initializing the nodes in jmonkey I have managed to create HealthAndMana systems, movement and rotation systems and a few others that are quite trivial but i am not sure on how to use the more complex examples yet

Thanks

@duindain

First thought, I recommend you to check the new Zay-ES example for sake of statable and compatiable. As seen in the topics conversation, the guys prove that Artemis is a naive approach which will mislead you when come to multi threading (physics, etc…) and complex stuffs.

If you still persist I will inbox you a new link.

Have a nice day, :stuck_out_tongue:

@atomix said: @duindain

First thought, I recommend you to check the new Zay-ES example for sake of statable and compatiable. As seen in the topics conversation, the guys prove that Artemis is a naive approach which will mislead you when come to multi threading (physics, etc…) and complex stuffs.

If you still persist I will inbox you a new link.

Have a nice day, :stuck_out_tongue:

Just in case… here is the link to the full Zay-ES example: http://hub.jmonkeyengine.org/forum/topic/zay-es-full-example/

@atomix said: First thought, I recommend you to check the new Zay-ES example for sake of statable and compatiable. As seen in the topics conversation, the guys prove that Artemis is a naive approach which will mislead you when come to multi threading (physics, etc...) and complex stuffs.

If you still persist I will inbox you a new link.

Can you post a link to that argument?
That might help my own understanding of ESes.

@toolforger said: Can you post a link to that argument? That might help my own understanding of ESes.

I don’t have the link handy. My biggest problem with Artemis as I recall is that they seek to needlessly codify the idea of “systems”. It’s misleading, unnecessary, and limiting.

This overview touches on it a little bit:
https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:contributions:entitysystem:introduction

I suspect if you chose to roll your own ES and kept working to make it “correct”… you’d end up with Zay-ES. If there is something about Zay-ES that looks strange to you then it’s a thread worth pulling on in the “understanding ESes” vein.

Edit: note that there is a very important picture missing in that introduction that I think would give some people their “ahah” moment… but unfortunately I don’t have time to add it. It’s the system-centric perspective of “entities” where each “entity” from the system’s point of view is like a row in a table with only the components that the system is interested in.

Heh… the million-dollar-question being: “What is ‘correct’ for an entity system?”
There doesn’t seem to be an authoritative answer. Which means that any answer given would need to argue why it is the correct one.

Entity systems as presented on the tutorial page are two key concepts:

  1. Implement multiple inheritance by delegating all the inherited classes to separate Component objects. I.e. each potential superclass becomes a Component class.
  2. Eliminate the silly delegation code by putting each kind of Component into a separate Map<EntityId,? extends Component>. Superclass code that would run on all entities will become a System that iterates over all elements of the corresponding Map.

What’s worrying me is that this probably misses some aspects. The above would mean that you can extract any interface into a delegate object, put the delegates into a Map, and call that an Entity System; Zay-ES is pretty minimal, but it’s a bit more than just a bunch of Maps.
The tutorial doesn’t tell me what I’m missing, unfortunately, so I’m unsure where to look for the missing elements.

@toolforger said: Heh... the million-dollar-question being: "What is 'correct' for an entity system?" There doesn't seem to be an authoritative answer. Which means that any answer given would need to argue why it is the correct one.

I can argue my decisions pretty well by this point and I can show why some choices in other systems break the idea of an ES… or at least greatly confuse its intent.

@toolforger said: Entity systems as presented on the tutorial page are two key concepts: 1) Implement multiple inheritance by delegating all the inherited classes to separate Component objects. I.e. each potential superclass becomes a Component class. 2) Eliminate the silly delegation code by putting each kind of Component into a separate [map reference removed to see if it will fix formatting[. Superclass code that would run on all entities will become a System that iterates over all elements of the corresponding Map.

What’s worrying me is that this probably misses some aspects. The above would mean that you can extract any interface into a delegate object, put the delegates into a Map, and call that an Entity System; Zay-ES is pretty minimal, but it’s a bit more than just a bunch of Maps.
The tutorial doesn’t tell me what I’m missing, unfortunately, so I’m unsure where to look for the missing elements.

I think that both (1) and (2) are kind of wrong. If you think in OOP terms then it is already backwards. It’s a data oriented architecture… which turns out to be a specific term and is the underpinnings of the idea behind an entity system.

Components are just data. Think of a component type like a database table. Every table has an ID field that is the entity Id do which that particular row in the table belongs. The data in the row is the component.

If some bit of code (a system) wants to operate on positions and collision shapes then it will only look at those two tables and join them. It doesn’t care what other 20 tables might be out there and it never touches them.

If you wrap all that in some master delegate then you’ve completely undermined the whole point: that systems can be independent of each other. They could even operate on entirely separate machines if the ES supported it. The only thing that ties anything together is the entity ID. But that only matters when looking at the application as a whole.

Ah right, the Systems aren’t tied into the Components in an OO manner, right.
I’m not sure how that improves stuff. Or distracts from it. You definitely lose the ability to enforce application constraints on the Components. That’s more flexible but also more error-prone.

No single master delegate!
The evolution I’m seeing is:

[java]class ArmoredRobot extends Human, Tank {
// aww does not work in Java
}
Map<EntityId, Human> humans; // includes all ArmoredRobots
Map<EntityId, Tank> tanks; // includes all ArmoredRobots
[/java]

[java]class ArmoredRobot implements IHuman, ITank {
Human humanDelegate;
float getJumpHeight() {
return humanDelegate.getJumpHeight();
}
// more boilerplate for other functions
Tank tankDelegate;
// another set of delegation boilerplate
}
Map<EntityId, IHuman> humans; // includes all ArmoredRobots
Map<EntityId, ITank> tanks; // includes all ArmoredRobots
[/java]

[java]
// No more ArmoredRobot
class Human {…}
class Tank { … }
Map<EntityId, Human> humans; // includes all ArmoredRobots
Map<EntityId, Tank> tanks; // includes all ArmoredRobots
[/java]

Variant 1 is what I call the abstract design, the thing I really want - armored robots that are both Humans and Tanks. If Java had multiple inheritance like C++ or Eiffel, it could be implemented directly, but well we’re in Java land so this doesn’t work.

Variant 2 is the typical interface&delegate implementation of multiple inheritance.

Variant 3 is the entity system.

No, not really. I’m not sure what variant 3 is. But if you have something called Humans and something called Tanks, then you are still implementing OOP… just poorly.

Components are attributes of specific concern. Position is a common component. Humans have positions, tanks have positions, map markers have positions, tribal chiefs have positions, footprints have positions, sounds often have positions, etc… Combine that with another component and you start to get interesting systems. Maybe a ModelType component and a Position component are interesting to the rendering system. A Position component and a Velocity component might be interesting to a physics system. And so on.

The systems never care what the entities are… just that they have the components that they want to operate on. In this way, you could add something new later and if you give it position, model type, and velocity then it will already appear in game and behave appropriately with physics. In the Asteroid Panic example, the ship, the asteroids, the debris, and the bullets are all handled by these separate sorts of cross-cutting systems.

Or you could add some new component and system and add entirely new behavior without really affecting any existing behavior. In fact, if your entities are created through data templates you could add these behaviors to existing types of entities (type in the game object sense) without touching any of that code. That might be extremely common in an online RPG/MMO.

Ah right, I forgot the last step: Splitting each class according to concerns. And that’s indeed one step beyond a mere multiple inheritance hierarchy.

Actually I might be doing OO as a “split along concerns” thing by instinct already - see the “tear lines” in the ScreenObject class in http://hub.jmonkeyengine.org/forum/topic/monkey-blaster-toolforger-edition-p1/ . Each block between tear lines would be a candidate for componentization I think, though I’m not sure that I’d do such fine-grained components in the end. Splitting stuff is all fine and dandy, but it runs into too many Map lookups as soon as you have code that needs to touch more than one component.
(In the database analogy, people tend to clump unrelated concerns into the same table if they happen to share the same unique keys; you could split stuff up, but you’d be doing lots of joins.)
These tear lines I’m doing are an Eiffel influence, Eiffel has the concept of a “feature group”. An example is at EiffelWebNino/http_connection_handler.e at master · jvelilla/EiffelWebNino · GitHub , feature group headers have the form feature [export list] – comment. Not all Eiffel feature groups indicate component boundaries in practice, but many do.

I’m not sure whether this radical split into components is really a good idea though.
The advantage is that it forces programmers to formalize aspects so you don’t have that huge bunch of ad-hoc classes containing a mixed jumple of aspects (which would become components); that’s in fact a good thing.
The disadvantage is that you lose all encapsulation. If a specific kind of entity has consistency conditions between different components, you’re back at conventions since there’s no way to enforce them anymore; you’d have to check all systems whether they’re upholding the invariants for each kind of entity. This doesn’t affect software that’s small, or where there are no component-spanning invariants in the first place. (Databases are bad at this, too - well, you could write a constraint that does a SELECT on another table, but I have never seen that being done, probably for fear or performance problems.)

I’m wondering whether it’s possible to avoid the disadvantages by turning the components into Java interfaces. E.g. class Ship implements PositionComponent, VelocityComponent, ModelTypeComponent, … more components here.
I’m not saying that this is the best design yet… maybe no good design exists and an entity system is just a different trade-off that works better in some circumstance (though I’m still unsure how one would recognize such circumstances).

Let me outlne a use case for component-spanning rules:
There’s a PositionComponent and a VelocityComponent.
Footsteps cannot have any velocity other than zero. This can be handled by never creating a Velocity object for a Footstep object, but how do I make sure that the noob programmer next cubicle over didn’t accidentally create one? Or at least make sure that he’s the one getting the exceptions flying - where do I put the code that checks this, can I check this at all?
Now for units. They can’t move horizontally while underground. VelocityComponent’s constructor can check that, and if you go against advice and use setters, these can check that, too, so that’s covered.
Enter burrowers. These can move freely while underground. The check now would have to take into account whether the entity in question is a burrower or not, but the VeclocityComponent doesn’t know about entity types, so the check would have to move to a System (and I’d agree if you said that the check never belonged to a component class anyway). But now how to I make sure that no system ever creates a VelocityComponent that violates these rules? If I have multple kinds of burrowers (say, with different kinds of rules for burrowing in earth, lava, water), how do I code these checks without duplicating the checks all over the place?

Another interesting question: Which parts of the whole program know what componenties are tied into an entity - just those that create an entity? Then the program will have trouble with interacting components; you’ll have to encode entity type somewhere in the component so that the code even knows it has to do something special. (The encoding could be partial - e.g. the Velocity component might now have a VelocityRestrictions enum that detailed what kinds of velocities might be allowable. A more sophisticated system with parameterized restrictions might be set up with references to VelocityRule objects. It would be a lot of code to distinguish ground units, swimmers, burrowers, and flyers, and any System could still accidentally create invalid velocities.)

Just some random thoughts as I don’t have time to drill in too deeply and I feel like I’ve already gone over similar material in other threads… but…

too many Map lookups as soon as you have code that needs to touch more than one component.
  • This is entirely an implementation detail. In fact, in Zay-ES there is no map lookup but an array search. But since arrays are generally only two or three elements big then this is often faster than a hashmap lookup. A C-based ES that is meant to run on consoles might generate structs where the members were the components (to pack them into cache friendly memory) so systems are accessing struct members directly.

  • Components are created to serve the systems that need them. If you really have constraints across components then you don’t have multiple components. None of your examples are good ones, really, because your constraints are arbitrary and only specific to one kind of thinking. What if there was suddenly a good reason to have footprints move or burrowers dig diagonally? The Velocity use system doesn’t care about any of this. It’s the code that produces the components that cares… that’s the only place that cares even in an OOP program. In this case there is no encapsulation needed because likely only one bit of code is setting those components in the first place.

In data oriented designs, code tends to be smaller and more direct. You don’t end up doing the same things all over the place so it’s less a big deal to enforce the kind of rules one is used to doing through encapsulation. Footprints don’t have velocity components because the only place that creates footprints doesn’t give them velocity components.

What comes up in my use-cases is atomic consistency between components… but even this is possible to deal with in the rare cases it comes up. And it only comes up for me because many of my systems in Mythruna run on separate threads. (which is something I get for free, by the way)

Hm… well, I kind of see the points.

I’m just wondering whether that’s going to scale beyond a one-person project.
Or whether one can build a game that way and hand it over to a group of somewhat competent modders. Can one expect them to work with it without breaking assumptions and requiring constant handholding?

If the answer is a confident YES, I’ll be impressed :slight_smile:

I think it’s safer than regular OOP. I think many MMOs would agree since it’s a very common architecture in those environments were separation and massive scalability are a requirement.

@guy : I think we should definitely have two seperate topics:

  1. Categories of Entity System and Comparation between implementations
    In which , Artemis , Zay-ES and the discontinued EntityMonkey,… and others non java should be arrange in line.

  2. The detailed implementation of Zay-ES arcording to @pspeed suggestion and explanation here and in other topic.

So I will start them, and I believe others will need them anyway after all these duplicated conversations. For the sake of clarify, @pspeed and guys can help me to correct the terms and ideas of the category, as I my self 've read tons of papers and codes, struggle to let the COP drug run through my neurons… :stuck_out_tongue:

Topic1:
Main parts:

  1. Introduction:
  • Basic idea of ES : Entity, Processor(System), other terms.
  • Core elements and its alternative
  • What is NOT an ES…
  1. Why, when, where ES matter. Pros - cons?
  2. Implementation, and scope of each projects:
  • Initial philosophy
  • Pure data or not?
  • Multi-threading, concurency enable or not?
  • Communication: Event messaging enable or not?
  • Is database (and other kind of persistent) friendly or not?
  • Is enterprise friendly (expanable/ extensible/ modulizable) or not?
  • Script possibilities?
  • Restrictions and limitation
  • Dependecies
  • Current status: Long term, stable, community?
    [More]
  1. Alternative approaches
  • Smart bean framework
  • Actor framework

Check here:
http://hub.jmonkeyengine.org/forum/topic/entity-system-topic-united/

Also just as a note There is a special subtype of EntitySystems wich I think pspeeds and mine are, they are in fact MetaEntitySystems in comparison to Artemis.
(I’m not 100% sure about pspeeds so I will only talk about mine)

If in my system you get the component storage for a given entity at a time, it is frozen, and will never change, wich allows you to have multiple times simultanously running in the es. (While sounding somewhat fancy I mostly use it for the database backend, I make a snapshot of the entity/the whole es and write out in the background)

Also somewhat relvant
http://entity-systems.wikidot.com/es-approaches

@pspeed said: I think it's safer than regular OOP.

Mmmm… right. I keep forgetting that Java doesn’t safeguard you much against subclasses doing nonsensical stuff.
I’m coming from a Design-by-Contract background, i.e. I’d never break stuff by misdesigning a subclass, but many people do, of course.

@Guys :
MetaEntity or the Component is immutable?

The main judgement about Immutate Component solution is, it not a clear contract for multi-threading success!!!

Check my united post please, I listed all the concerns there :stuck_out_tongue:

- Pure data : very debatable - – Mutable : Component as bean with setter and getter - – Immutate : Component as bean with getter, should be replace if changed.
  • Multi-threading, concurency enable : very debatable
  • – As my experience, pure data or not is not clear contract to multi-threading success. Consider other things happen outside of ES scope, so it not an solid waranty that those component will not be touched by any other thread.
  • – Also if there is a contract that no other thread touching those data, in Java style via synchonization or other paradigm like actor… multi-threading also consider success but more just complicated!