Entity,Components: Issue in immediate refresh

Started by
1 comment, last by FrogJohnson 9 years, 1 month ago

My question: How do you tackle new entity/component addition on the fly?

Background:

I'm using the c++ port of artemis framework https://github.com/vinova/Artemis-Cpp to architect my game objects. In artemis, whenever you create a new entity or add a component to an entity, you have to call refresh() on that same entity for the changes to take effect.


entity->addComponent(xyz);
entity->refresh();
  • Entities in artemis possess 3 attributes: a unique id, a type bitstring(identifies which components it has), a system bitstring(identifies which systems will call this entity).
  • When calling addComponent, the type bitstring is updated, but not the system bitstring. When calling refresh, the entity is added to a 'refreshed' array.
  • At the start of each game loop iteration, a function loopstart() is called. This function goes over all the objects in the 'refreshed' array, and updates the systembits by looking at the type bitstring of those objects.
  • The last sentence makes it clear that all new updates will be reflected in the next iteration. If I shoot a bullet, it will appear 1 frame later. If I want to process collisions, it will start 1 frame later.
  • How would you suggest I tackle this ? If I add a component, I would like that entity to be processed by a new system immediately

What I've done so far

  • Change the order of system updates. Call the removal system first, before any other, so that all entities with a 'destroyed' component collected in the previous frame will be destroyed in the beginning of the current frame

Problem: Even removal will need a refresh, which will not happen immediately. This causes invalid pointer access as the subsequent systems will expect to see some components which are now not there thanks to removal

  • Instead of refresh, I call the function EntityManager::refreshEntity. This function is responsible for actually updating the system bits so that the entity is acted upon by any new system if a component is added to it. And the result is exactly how I want it

Problem: This function has a loop inside it, to update the bits for all the systems present. This can be a problem if there are tons of entities each frame being updated. Which is why, design-wise, it is called inside loopstart, only at the beginning

Thanks for reading !

Advertisement

[…] If I add a component, I would like that entity to be processed by a new system immediately

There is the following reasoning against the generalization of such an approach. It does not concretely answer your question, but it may make you rethink...

A game loop usually defines a sequence of updates on sub-systems in a fixed order. See for example this book excerpt over there at Gamasutra. This is done to get control over things that happen concurrently in reality, but cannot be simulated concurrently. If you don't do it that way, a single change may cause a cascade of sub-sequent changes that (a) may not settle in appropriate time, hence causing a delay and stutter to the frame rate, or (b) is canceled at some point, leaving the world in an incorrect state.

Obviously it is possible then that a sub-system updated early in the game loop is allowed to make changes that has an impact only on sub-systems later in the game loop. For example, the input sub-system is traditionally the very first sub-system updated. The player control, using input in its update, can be done very soon after that. If the player control detects a "fire weapon" input situation and the belonging action is not blocked due to some reason, it can cause the instantiation of a BulletShot entity immediately, because the entity's updates, shot's collision detection, and so on will be done later in the game loop. However, if the collision sub-system detects an entering into a trigger volume, it must not cause the spawning of a new enemy immediately, because things like animation and physics are already done, and adding a new entity at that time may draw the previous results partly meaningless.

So you need to clarify whether the issue explained in the 1st paragraph above may occur, and if so you have to judge on whether they may harm the experience with your game, and if so you have to decide which way to go. This thinking has to be done for each phase in the game loop where you want immediate changes.

Obviously the easiest way to deal with that problem is to defer all changes. Unfortunately I'm not familiar enough with Artemis to know what can be done. My attempts would be to have both immediate and deferred handling. If the framework does not provide it (and it is fine to use otherwise), then patching it may be an option!?

Thanks for the reply!

Obviously the easiest way to deal with that problem is to defer all changes. Unfortunately I'm not familiar enough with Artemis to know what can be done. My attempts would be to have both immediate and deferred handling. If the framework does not provide it (and it is fine to use otherwise), then patching it may be an option!?

Actually, this is how artemis deals with entity changes by default. You add a component, then call refresh on that entity. Refresh() will just add that entity to an array. At the beginning of the next frame, you just need to call loopstart() which will take the refreshed array from the previous frame and update all the entities in it.

The reason why I asked about immediate updates is that the order in which I call my updates and handle the data in the systems was giving me trouble with deferred updating. I think I'll try to rectify that problem now instead of hacking my way around deferred updating.

Cheers!

This topic is closed to new replies.

Advertisement