To entity or not to entity?

Multithreaded is harder to debug. That is orthogonal to an ES. ES games need not be multithreaded… in fact none of my single player ES games are.

I actually use relative positions and rotations (it is easier to place them this way, like you say your tank turret must be 1f (let’s say 1f = 1 meter) higher than tank hull center and 1 meter to the back), and if you need to calculate positions in multiple systems, you may implement some common one with all these generic methods, and inherit other systems from it…
Something like this

protected Quaternion getParentWorldRotation( EntityData ed, EntityId eId )
{
    Quaternion parentWorldRotation = new Quaternion();
    for ( EntityId baseId = getPhysicalBaseId(ed, eId); baseId != EntityId.NULL_ID; baseId = getPhysicalBaseId(ed, baseId) )
    {
        PhysicalObject baseObj = ed.getComponent(baseId, PhysicalObject.class);
        if ( baseObj == null ) return Quaternion.IDENTITY;
        parentWorldRotation = baseObj.getFacing().mult(parentWorldRotation);
    }
    return parentWorldRotation;
}

where getPhysicalBaseId() returns EntityId of entity that is upper in hierarchy AND has PhysicalObject component (which means it has position and orientation). If you inherit your systems from the system with generic methods like this one, they all will be able to calculate absolute positions/rotations anytime in pure math, nothing from scene graph…

Well a few of those are: The AI needs a raytrace to check whether the civilians could see the gun, the gun itself needs a raytrace against all bounding boxes or the world.

I agree that some systems might have different interpretations, for example I could use the physics raytrace as a fast raytrace and then do a raytrace only on the enemy to have the “hitbox information”, however I feel that the actual position might be used by multiple systems and as soon as it is, it would be better to store the calculated position, right?

That would be the system approach from @ia97lies basically but that implies that this system is the first in the update order.

Regarding the multi-threaded: Isn’t the applyChanges thing going to help here, since the changes of the systems aren’t applied till the next frame? However you would need to apply them before multithreading the systems again…

Yep, but you calculate the same thing multiple times where you could listen to changes in the Position Component and then apply it down the graph.

The thing which worries me here is that I don’t know the math too good (the translation depends on the parents rotation and I don’t know how the scale actually comes into play here. Does it reduce the translation or only the translation of the children and such things.

Yes. The ES supports multithreading “out of the box” so to speak… and that’s why. I was commenting on the “ESes are harder to debug” comment than went on to really talk about multithreading debugging that really has nothing to do with an ES.

a) game objects probably don’t need scale. I doubt one gun can be a different scale for different people.

b) the source code to JME is available and you can see how straight-forward using the Transform class is.

It’s also very likely that your “hierarchy” is never more than two deep. ie: you’ll have objects without parents and objects with a parent without a parent… and that’s it. Calculating a Position from a ChildPosition is pretty easy in that case.

Hmm well you can calculate it on demand - and it is up to you under what conditions you call the method. When you need the data - it has to be calculated somewhere anyway, you can’t avoid that. But you don’t need to place that code everywhere, just in one common place…

I would argue on that a bit, with the same tank turret: you can rotate turret around hull’s local Y and incline barrel(s) around turret’s local X and move the hull somehow at the same time. So you have hull-turret-barrel system already with three levels… if the tank is driving, say, aircraft carrier’s runway, you have one more relative level… but yeah, math probably won’t go much further than two-three-…-N multiplications instead of one.

update: @Darkchaos I take it you don’t want to calculate it “by hand” at all - but well, you need it in logic anyway. But imagine the freedom you getting when you control the logic - if you implement it on server, you don’t even need client to be JME and Java-based at all… you don’t need scene graph, you can pass pure data to some super-duper rendering system that can be not even written by you in the end…

1 Like

I have deferred that bit for until I have a bit more entity feeling so I started with weapons and such. If I got the ECS principle right that is the good thing about it: I can modify unrelated systems without problems.

Anyhow I’ve seen quite some material recently and that lead to questions:
I’ve seen a talk where they talked about ECS being inherently bad for Garbage Collection which is why they don’t generate new Instances anymore. I guess that is a situation of: Wait until you really see those frame drops in a specific scenario with really many entities and see whether you can get a way with one and only one setter for the specified value (when you don’t need the Changes System)

So far it is working halfway well, it is just complicated to think about a good structure which I might to change anytime and I still have some dependency on the SceneGraph but I guess that is also unavoidable.

I only don’t know yet how I handle all those skillable values like walking speed etc. Maybe having a dedicated class which simply iterates over the Entities Buffs and such is okay? (Versus storing the skilled values inside the related components).

Both features don’t support handling the applyChanges though, so I am open to suggestions.

My ES code has absolutely no dependencies on the scene graph. A Spatial is not a game object. So including it in the game-object stuff is an anti-pattern.

You may have to provide more detail. But there are two aspects at play here. WalkingSpeed… which is a component that your movement system might use to decide how fast a mob walks. And a “speed buff” which might adjust the WalkingSpeed of a particular mob.

A rabbit or other NPC may have a WalkingSpeed but not bother with any other buffs or whatever. It’s just hard-coded with a specific speed.

There are a variety of ways to do buffs. Either with special “buff” entities that link to the target entity or with a “component per buff” approach. It just depends on your game and how many different kinds of buffs you think you might have. The special “buff entities” approach is nice because then it’s trivial to have them auto-expire (Decay component) or have Names, etc… because they are entities and can have any component like any other entity.

Well since I use bullet that’s at least some unavoidable part currently. Since my ES does not represent the Meshes all raycasts need to be done in the scene graph as well (Though I plan to at least add BoundingBoxes to the EntitySystem, so I might only need the SceneGraph for Detail (Hitboxes and whatever)

As for the Buffs my question was rather related to how to calculate the actual walking speed.
Let’s take it like this: All constants which you usually pull out of thin air (Speeds, Damages, Regeneration Rates, …) can be influenced by a Skilltree, Buffs and the Equipment.

Since the WalkSpeed is part of a Component of each NPC, I could calculate the value and set it, but then?
What happens when a buff expires? I could either recalculate every value on every frame or try to use the EntitySets and when a Buff fades, I have them in “removedEntities”.

For Area of Effect Buffs, I would then need some field affectedEntities and affectedPosition, but I guess that is another topic on it’s own.

I guess I should just try to build something and see what happens, actually.

Nope. Bullet does not require spatials. JME wraps some Bullet stuff for you but that’s really doing 90% of the stuff you expect the ES to do for you anyway. Bullet in an ES is using only RigidBodies and you ditch the spatials.

This is important because just because you use a 50,000 triangle mesh in the scene graph does not mean that you are using a 50,000 triangle mesh in the physics engine. These two things are completely separate. The model system will load appropriate spatials for the “model info” component. The physics system will load appropriate collision shapes/meshes for the “model info”. These may occasionally be the same thing but quite often not.

I’d argue the same for ray casts. Ray casting into a scene meant for visualization is not always a very good idea… unless it’s supposed to be purely camera-based style ray casting… like even that pixel in that leaf texture should clip the ray.

Separate all of this into different concerns.

You have a WalkSystem. The WalkSystem watches all entities that have Position and WalkSpeed. Once a frame it moves these entities.

Some other buff system watches for all entities with a Buff component. The Buff component has a target pointing to the entity to which it applies. Every frame, the buff system goes through all of the current buff entities and accumulates total buffs per target entity. (You may have many speed buffs at once, after all… plus slow buffs, and so on.) At the end of this loop, it goes through all of the target entities and applies the collected buffs, in this case WalkSpeed. That’s it. That’s all it does.

There is another DecaySystem that watches for any entity with a Decay component and removes it after a certain amount of time. That’s it. That’s all it does.

If you want to have a temporary buff then you create a buff entity that has a decay component.

If you want your buffable mob to have a default walk speed then you create a ‘permanent’ buff for it… which is just a buff entity without a Decay component.

That’s it. You have three separate systems that do very specific jobs, are otherwise unaware of each other, and can be combined in a bunch of different ways.

Area of effect buffs are similar. A system that detects if an entity has entered some area and creates buff entities on it. When it leaves the area, it removes them again (or they auto-decay and you do a little book-keeping to keep them refreshed or whatever).

Simple systems doing simple jobs. Reusable.

Similar, in my entity system I kinda replicated larger parts of an scenegraph, but independently. This will also allow later to use doubles for a larger world (I don’t need a infinite world, but a float is a bit small) so doubles are a nice compromise.

Okay that sounds good.
One question about the Set of removed Entities though:
Currently I am unable to clean things up because I can’t access the Components anymore after the Entity has been removed.

Is there a good way to solve this other than adding some HashMaps which contain the data needed to remove the Entity?

What are you trying to remove, exactly?

In this case the ModelNode from the related rootNode.
I know that Asteroid Panic has it’s Model HashMap for this but I was thinking what happens when you simply remove one Component which in turn wants to remove a control or even worse: a light (because you can remove controls by Class Name)

Your code shouldn’t be just wildly removing whatever is in the component. It sounds like you are including JME class names in your components or something… which is like storing Java classes in a database. It’s backwards.

You remove the node because the node was associated with the entity that’s gone now. You already had to manage this relationship. (Which is done for you if you use EntityContainer, by the way.)

It’s so rare that you need to get the ‘component of the entity that is no longer in this set’ that I’m having trouble coming up with a use-case that isn’t better done a different way.

Well actually I was storing all the visual representations of the Data in the Entity inside of it, which now seems like a huge anti pattern to me.
I didn’t know of the EntityContainer, so yeah, this is a design mistake on my side, I guess.

EntityContainer is a utility class in my SiO2 library… but you can also just cut-paste it to your own project if you don’t want to depend on SiO2.

The sim-eth examples use that class a bunch, though.

Well I think the Event Bus might come in handy sooner or later as well, so I think it’s worth adding.

Another question arose: Currently I have a very specific order in which I would update my system, which feels a bit wrong.
However this only applies to the view part not the actual logic:

I update the ModelContainer as the very first system so the other components can add to the model. (Without that I would need to sort of shift all the “add component” code into an iteration over all components, which feels wrong and makes things obstrusive).

On the other hand when I wanted to remove all components, I would need the Inverse Order: First I would need to remove the Controls and then I would remove the Node. If I don’t do that, I can’t call removeControl so it’s cleanup code can’t run.

For Nodes I could run removeFromParent but for Controls: Should I manually call some method on them in case the Node is null

It’s ok to sometimes have order-dependent systems even on the ‘back end’. But when you can it’s often better to decouple them.

For example, if you have a model system and some other system that depends on models… then you can let that other system acquire and release models from the first system. Even if the other system runs first, the model system could supply entity-specific placeholders.

That being said, it’s usually pretty rate to have to do this. Sometimes it might be better for core systems to just talk better… like if you have a separate model and animation system you can just lump those entity containers together in the same app state and let them cross talk as needed.

And that being said, it’s usually something like the model system where this becomes important when it does so it might be worth going ahead and adding the acquire/release thing from the beginning.

When you talk about controls, which controls do you mean?

2 Likes

Something like a Queue where you can enqueue the actions which are processed as soon as the model is there or rather invoking addObject() for a particular Entity?

Things would even get more complicated when I didn’t want the loadModel Call to be blocking, actually…

I’ve just stumbled over a use case where the order doesn’t even help me out:
In the Weapon System, I spawn a bullet. This bullet is explosive which is why I have to add some CollisionListener to it. Now the problem is that the ExplosiveSystem is updated after the WeaponSystem but before the Renderables (which would be the next frame) so there is no Model available.

I know all my issues are bullet centric right now but re-wrapping the whole physics system is a large task and currently I don’t feel like that would be worth it.

That being said, these relations could happen anywhere. For Example there is the Healthbar which should be added after the Node is available, in that case it would be Lemur’s GuiControl which couldn’t be removed from the Model Root Node

No. I mean ModelState.acquireModel(entityId) that will create a Node of the model hasn’t been loaded yet and keep track of who is using it. Then if the model state creates it later then it uses the same node. When the model state detects that the model should be removed then it hides it but doesn’t actually remove it until every caller that acquired it has also released it.

And yes, a huge amount of your problems is that you are trying to use JME’s Spatial wrappers around bullet, I guess. This buys you nothing but problems and you could pretty trivially just use RigidBodies directly in a ‘back end’ system. But alas, you aren’t… so you will have to work through the pain. Ultimately, I think you will probably do 4x or 5x the work working around this… but that’s your choice in the end.

I don’t know what you mean by “re-wrapping” though. You aren’t wrapping anything, really. Just following a standard ‘copy these values from the body to the entity’ process that is repeated in several examples.

This is a good example of where you could do it the more proper ECS way and have the systems be completely independent. You already have the entity’s position so there is no reason to attach the health bar to the model itself. Just position the healthbar where you want it. Decoupling has advantages because you can now show each independently no matter what.