Asteroid Panic: Why is Spatial in HashMap instead a Component

Hi

I tried out the asteroid panic game, works after some adjustment of the example (seemed a bit outdated). Btw if someone is interessted in the slightly polished asteroid panic, I could provide :smile:
I now started to study. I was curious how the separation of the graphic from the logic was done. And how to design a ES based game in general.

The lessons so far learned

  • Every thing has an id
  • Every aspect is expressed with a component
  • Every system cares for one aspect.

What I wonder was that the spatial of spaceship, asteroid, ā€¦ are organized in a HashMap<Model, EsId>. Why not a component letā€™s say VisialComponent for the spatial? Looks like an indirection to me?! Maybe somebody can shade some light?

Thanks

If i remember correctly, the main reason was that you want completely decouple visuals and the data. Also to keep up thread safety all the data has to be unmodifyable, which is not the case as soon you attach scenegraph objects.

But Paul probably can give you some deeper insights since i suck at ES

Ah ok, the unmodifiable makes sense in threaded environment. But If you have a state (== thread) cares only for the ā€œspatial componentā€, it should be feasible to hold the spatial in component. That is what I thought is the case, a state cares for one thing only.

Because putting a spatial in a component is like storing a JTextField in the database.

Edit: more to the point, you may have several different visual representations of a model. A spatial is only oneā€¦ thatā€™s why itā€™s ā€˜viewā€™ and not ā€˜dataā€™. Your components should in general not by some graphics implementation specific thing.

Makes sense. That way I could have a view which shows the regular game view and a view for a map in a corner of the game screen. I did think too short I see.

Many thanks @pspeed and @zzuegg for fast response and advices. I start to like it. My only concern left is about TDD but think as ES seems to separated stuff in pretty handy chunks it should be a piece of cake.

Well, sort of. After all, the model state needs to know various visual information. (two components).

Many systems will ā€˜queryā€™ more than one component. For example, a lot of stuff will query position + something else.

Some other general rules: your life is easier if only one system produces a particular component. For example, if you had lots of different systems setting the Position component then they risk stomping on each other.

A corollary rule of thumb is that if you feel like multiple systems need to produce the same component that itā€™s really an entity that they are producing and thatā€™s the case where itā€™s ok for more than one system to produce the same componentā€¦ when they are really producing a tagging entity that attaches to some other entity. An example might be some kind of general Damage component. If multiple things can damage a particular entity in one frame then there are really damage entities that reference the damaged entity. The system that handles applying damage and adjusting hitpoints would then watch for those damage entities.

In Asteroid panic, I donā€™t remember if I handle collisions directly or product collision components but if itā€™s the latter, that would be another case for attached entities since there may be more than one collision to produce in a given frame. Doing that also allows different systems to do different things with collisions. One could look a the two colliders and create some damage. Another might show a particle effect. Still another might look a the two colliders and produce a custom sound. Hopefully you get the idea.

Another random note that trips up some people: not all data needs to be a component. Systems may necessarily have their own internal management data that other systems donā€™t care about. There is no reason to do that in a component. (For example, a common mistake is to try to put an AI state machine into a component.)

4 Likes

Many thanks for the lengthy answer.

Yes I get the idea, I suppose. So in short on of the rules is, a system do only produce one kind of component (when ever possible), but a system may ā€œreadā€ many different components to deal with its task. I also observed that in asteroid.

An exactly I did look for this kind of separation, where one system cares for the effects, one for sound, one for detecting that a goal has been reached and so on.

A system may produce more than one componentā€¦ itā€™s rare but it happens. The point of what I was saying was that for a given component, only one system will produce that component. (Unless itā€™s the special case of an attached entity type of situation.)

Ah. I see, makes sense.

So I have now three rules (I like rules or recipes):

  • Writing only one system should produce a set of components.
  • Many system can read various components and react.
  • If many system produce the same components they better produce an entity with those components and link them to the entity they did want add those components.

Iā€™m not totally sure if I understand the special case, but I think I understand that when two or more system produce the same component they stumble over each other, so if they produce an entity with that component and problem is solved.

Yep. And you will recognize it when you come across it. :slight_smile:

I have another question, maybe it fits in this thread maybe not. To get familiar with entity system programming style I started a ā€œSpace Invadersā€ game like we had back in the old days. So I have a bunch of invaders above the head of the space ship organized in wabbeling gride and a space ship of course.

So letā€™s say I have an effect state where I want to add effects like shock waves or explosions when hit by a bullet/rocket. And maybe I also want some sound (maybe this fits in that effect state). I saw that your asteroid panic do not such stuff. Yes there is sound and I did not clearly see it organized in a state.

I thought an hit component could be added by the collision state, so the effect state can react on that (get all entities with a hit component). But now the problem starts. When do I remove this hit component, letā€™s say there is some other fancy state, which is interested in that hit component. Or shall I just do it on the next frame by the collision state maybe? Further more if I have those states in threads, when can I remove it? The next frame idea wont work.

Or is this something I should not solve with an entity system (but actually that was my hope, as I really can easily separated concerns with this kind of approach and I start to like it :smile: ))

There are so many ways to handle this so it just depends.

Most of my games have a Decay component and a state thatā€™s only job is to watch the Decay component and remove the entity once the time is expired. I thought Asteroid Panic did also.

Chances are, if you are trying to warp the ships in a wave or something that this has to be part of the physics simulation. Presumably the ships in their new visual location should also accept collisions and stuff there. Though I suppose having that run before the physics system gets to run is another approach.

Which brings another point, even if you should always design your systems as independently as possible, sometimes itā€™s just easier to consider that they run in a particular order. Design-wise you will just have to keep track of these dependencies if you ever multi-thread things and just make sure to run those systems together. Sometimes there are simple work-arounds so it just depends.

If you have something like a ā€œhitā€ entity or a ā€œcollisionā€ entity that you want other things to be affected by (many systems) then a Decay component with a really short value is one way to deal with it. It avoids having to worry about running systems in a particular order. Mostly I find ā€œwhen to delete an entityā€ is the biggest concern with system ordering so adding such a decay system makes it so I donā€™t have to worry about the order my systems run.

For what itā€™s worth, Monkey Trap is a much more complicated example of an entity system based game. Maybe too complicated to make a good example, I donā€™t know. It had to deal with networking so multi-threading was at its core on some level.

Hey that helped me a lot! Now I get the Idea of this Decay component. Thatā€™s cool. So actually my hit thing is not a component but an entity! That hit entity then have a decay with a very short ttl and position component.
So I also need a Decay system ā€¦

And coupeling some system together in some order is as well a solution. I see now that those then have to run in the same thread. Simple.

But the best thing is I can just add yet another system to add more stuff without to refactor tons of items/objects.

^^ and that, my friend, is an entity system. :slight_smile:

1 Like

:smiley: yeah. I feared a little that I wont be able to get the idea of this magic ES (which is now lesser magic and more concrete). I may show up with some more questions, but I suppose to get something done I have now the tools. Iā€™m not sure if I will pose them in this thread, maybe and maybe I should change the title to ā€œSome questions about ES in Asteroid Panicā€. Itā€™s easier to ask questions about something exist than some hypothetical questions about ES in general, as it seems highly depend on what one wants to achieveā€¦
Thanks for your time.

Ok here my first attempt using Zay ES :smile:
The basic took me 3 days including study Asteroid Panic to write this simple game. Amazing, as I never thought I will be able to handle such an amount of elements that easily.

1 Like

Pretty cool.

I made now a lot more progress. Anyway there is one point I did like to ask: The model component in Asteroid Panic just hold a string. To avoid typos I added some const vars. But when ever I want to add a new one I have to touch this file. I now thougth of storing an object derived from a base class instead that simple sting. just that the java compiler can help me with typos and I then would not to have to touch The model component for new sfuff. This objects ar just used like a string :grinning: But Iā€™m little unsure with that.

If itā€™s used just like a string then why not use a string? I donā€™t understand the difference. Code might help.

Edit: note that you can also keep your constants in a different file. I do this all the time.

Edit 2: also note, typos in this area are no worse than typos in any asset string. You will generally discover them right away.