Author Topic: Playing around with a new kind of program architecture: "component system"  (Read 38053 times)

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Update:

I just got finished preparing a new version of the MiniRL now with the RenderManager upgraded to a RenderSystem that takes in graphics components. What do you think?:

http://www.mediafire.com/?f8lapm13tkk3vbl

Robobot

  • Newcomer
  • Posts: 8
  • Karma: +0/-0
    • View Profile
Very interesting topic, thanks for the input so far!
I've been looking into the concept and my main problem is how to deal with systems that have to deal with different kinds of entities.
For example, how to deal with a situation like this. We have a city building game, with buildings and peasant who will automatically react to some situations. Suddenly a building is set on fire. A peasant who currently has nothing to do should immediately try to extinguish the flames.
My first idea would be to make the system that set the building on fire emit an event, which would make an UnemployedPeasantSystem add an ExtinguishFireComponent to some peasant.  According to requerent, this is probably not the best idea, and it would be better to not mix event- and component/entity-based programming.
Another way would be to have some kind of FireBrigadeSystem that handles all BurningComponent entities. This system would then pull all jobless peasants from the entity manager and add an ExtinguishFireComponent to one of them. This seems to be the way that Artemis for Java prefers. Somehow this does not seem right to me, as one system pulls entities it did not originally subscribe to.

More generally, how do we handle updates on entities the current system is not subscribed to? Or, in a more general sense, how do we handle tasks without knowing who might handle them?
Thanks a lot!

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Quote
My first idea would be to make the system that set the building on fire emit an event, which would make an UnemployedPeasantSystem add an ExtinguishFireComponent to some peasant.  According to requerent, this is probably not the best idea, and it would be better to not mix event- and component/entity-based programming.

I did say that, but at the same token-- many people have a lot of success mixing them.

One thing I dislike about events is that you need to have a strong idea of what everything does before hand. One of the advantages of components is that you don't need to know anything. When you mix them, you can add events as you go along that get triggered by component systems, but you really shouldn't have to be doing this. The system should do all the event management internally.

Edit: Most major game engines (like UDK or Unity) use a hybrid type system where component systems raise events associated with those systems-- however, this is just a tool for interfacing with an engine. It's better to have the low level access necessary to make your own systems and subvert the need for events.

Quote
More generally, how do we handle updates on entities the current system is not subscribed to? Or, in a more general sense, how do we handle tasks without knowing who might handle them?

Systems only work with specific components, not entities. They should never need to know more about an entity than what is in their respective system. A component.owner sort of thing is important though, as you may want to add components to entities within a system. This is true even when a system uses multiple components of the same entity-- it's just important to keep internal references to components parallel.



Quote
Another way would be to have some kind of FireBrigadeSystem that handles all BurningComponent entities. This system would then pull all jobless peasants from the entity manager and add an ExtinguishFireComponent to one of them. This seems to be the way that Artemis for Java prefers. Somehow this does not seem right to me, as one system pulls entities it did not originally subscribe to.

Think about what an entity represents. The problem your having has less to do with components vs entities and more to do with AI.

You have an emission of information into the game world- IE, a burning building.
You have an entity sense that emission and then adopt a particular behavior- IE, a peasant begins dousing the fire.


First we need to rationalize what a building is. Are buildings discrete entities (like in an RTS) or do they contain other entities (like in the SIMs)? I'm assuming that your buildings are discrete, but it's okay if they are not. A building and/or the entities/components that make up the building might have some kind of description to indicate who they belong to, whether it's a faction or an individual.

Then we need to rationalize what it means to be burning. We'd probably implement a fire propagation system and a burning component. This will work for discrete or container buildings, as we only care that something is burning and that there exists an entity who cares that it is burning. A fire propagation system would care about the materials of an object, the objects adjacent to it, world properties like wind and humidity, and as many other things that you may or may not want to deal with.

Then we need some way to alert the AI that they need to do something about it. The question is-- How do we alert them? An emission scheme might be more complicated than your looking for, but it would basically be a map that has sensory data that is significant to an AI. If you just need to send a message directly to all entities to clean up fire, then a FireBrigadeSystem, as you suggest, would make sense.

The FireBrigadeSystem works with AI components and Burning Components. It would just match up ownership/factions/concerns with problems, and then use whatever heuristics that the AI represents to WEIGHT a goal and add it to that entity.

So-- what you can do is have GoalComponents that are attached to entities. When we get to the DecisionSystem, we analyze that entity's goals and choose its behavior accordingly. FireExtinquishingGoal might include information about the location of the fire or a reference to a burning entity, or it might just be managed by the BehaviorSystem which could do a 'closest fire' sort of heuristic. You can nest goals in a single component if you want, but it shouldn't be a big deal.

Alternatively, you can have a set of goals that describe an entity's behavior and weight them based upon emission data. This will prevent a peasant from starving to death even though he's trying to put out a fire.



I think AI schemas work most naturally with component systems- as all we do is update weights according to emissions and our entities will act in their best interest. I posted some thoughts on Sensory Systems in another thread, which got a response that briefly discusses a way of managing AI that works incredibly well with component systems.

http://forums.roguetemple.com/index.php?topic=3289.msg27242#msg27242
« Last Edit: May 04, 2013, 05:00:29 PM by requerent »

Nymphaea

  • Rogueliker
  • ***
  • Posts: 74
  • Karma: +0/-0
  • Maria Fox
    • View Profile
    • Nymphaea.ca
I have been working on a framework of my own, and will probably have more questions eventually as I get my head around the idea, but thought I'd chip in with an idea related to events.

Instead of making an event system as a whole, you could make an event component for specific systems to communicate. The first system evaluates that something is happening, so it adds the data about it to a component. Other systems check the same component, and act upon it.

I also agree though that this seems more like a mapping problem. You should have some form of map state access for all entities, so they can inquire to what is around them. You could go and ask the map "is this tile on fire?" and if it returns true, then the entity will act accordingly.


As for my own question, how would you suggest dividing up the code in a component based framework? Mine is similar to the article posted earlier, without the nodes. Engines store entities and systems, entities store components, and systems reference entities they work with, making it someone key-shaped I suppose. I was originally planning to make a LogicEngine and a RenderEngine, but I'm starting to realize that I should probably split it up even more than that, such as having a separate GUIEngine from the game's RenderEngine.

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Instead of making an event system as a whole, you could make an event component for specific systems to communicate. The first system evaluates that something is happening, so it adds the data about it to a component. Other systems check the same component, and act upon it.

That's the whole point. Systems are the message handlers and creators. You CAN use components as flags or put flags on components for other systems to look at, but you shouldn't NEED to do this. The transmutation of component data should be enough for other systems that use that data to perform their functions properly.

A good example is a Collision Detection System and a Collision Handling System. Suppose we're in a real-time simulation that needs super-precise continuous collision detection. For that to work, we need to have a system to interpolate the physical integration of forces over time. We also need to able to extrapolate from our current orientation to the next collision that would occur within a tick. However- the physical state of our simulation needs to update for ever collision in chronological order.

A quick solution is to make these systems co-routines that yield to one another based upon an Alpha. Essentially, we would make our game/simulation a Finite State Machine of systems- or rather, system-states. We just meander to different system-states when we need to perform some modifications to the data.

Quote
As for my own question, how would you suggest dividing up the code in a component based framework? Mine is similar to the article posted earlier, without the nodes. Engines store entities and systems, entities store components, and systems reference entities they work with, making it someone key-shaped I suppose. I was originally planning to make a LogicEngine and a RenderEngine, but I'm starting to realize that I should probably split it up even more than that, such as having a separate GUIEngine from the game's RenderEngine.

Divide it according to the minimal use-case. If a system only uses X components for something, for example, you may want to split your X and Y location components up (though it's typically okay for a system to work on a position component that contains both X and Y components even if it only works on one).

The idea is to prevent the need to duplicate any data but keep logical components isolate. A position component is used by both the renderer and the physics simulator, but a force component is only used by physics- so it should be its own component. You can rationalize it further by applying multiple forces throughout components and then evaluating/applying velocity when we need to update.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
When is each system's "update" function called, in a turn-based non-real-time game like a roguelike?
« Last Edit: May 04, 2013, 10:00:01 PM by mike3 »

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
(deleted)
« Last Edit: May 04, 2013, 10:00:52 PM by mike3 »

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
When is each system's "update" function called, in a turn-based non-real-time game like a roguelike?

On each logical tick, we wait for input that will manifest as a player action. Once we get a player action, perform it and continue in the loop.

In a turn-based game, you typically want action-resolutions to occur on the same turn, in which case you're going to update each system per entity, instead of each entity per system. This literally just means inverting the game loop so that you do something like,

Code: [Select]
foreach(entityID:entityIDs) foreach(system:systems) system.update(entityID);
Where one of the systems is an input handling one that waits for user input.

Robobot

  • Newcomer
  • Posts: 8
  • Karma: +0/-0
    • View Profile
Thank you, requerent and Nymphaea, very much! This makes it much clearer. Also the linked thread on sensory systems is quite interesting.
On a different note, I really enjoyed your blog, requerent. Keep it up! And as you seem to like Lua, I'm currently reading Programming in Lua, 3rd Edition and like what I've seen so far (half way through). The best part is that there don't seem to be any WTF?! moments I've come to expect when looking at a new language. Also the book is very well written.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
When is each system's "update" function called, in a turn-based non-real-time game like a roguelike?

On each logical tick, we wait for input that will manifest as a player action. Once we get a player action, perform it and continue in the loop.

In a turn-based game, you typically want action-resolutions to occur on the same turn, in which case you're going to update each system per entity, instead of each entity per system. This literally just means inverting the game loop so that you do something like,

Code: [Select]
foreach(entityID:entityIDs) foreach(system:systems) system.update(entityID);
Where one of the systems is an input handling one that waits for user input.

Though you don't want to get input for every entity in the game, just the player, no?

As if the input system waits whenever its update(<entity>) function is called, then you'll get a lot of useless waiting where it waits for input for every monster as well as the PC. So do you have some kind of "input component" on the PC that other entities don't have, and the input system checks for this component, and if there's one present, waits for input, then updates the component with whatever input is given?

Nymphaea

  • Rogueliker
  • ***
  • Posts: 74
  • Karma: +0/-0
  • Maria Fox
    • View Profile
    • Nymphaea.ca
I think it comes to how it's structured, though the component system does seem better geared to real-time / tick based games than turned based. My framework has the ability to disable systems, or even entire engines. That is probably how I would do it, disable all logic except an "InputEngine", and the rendering ones. Once that input has been obtained, enable the other systems again and let them act until they can't (the player entity sets a flag saying it needs input) and then repeat.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
@requerent: In one of your earlier messages you mentioned how one does not need events or messages in a component system. Now does that latter bit mean that I should do away with the "handleMessage" stuff on the components in my test program?

I got the whole "send messages to the components" stuff from reading this:
http://www.gamasutra.com/blogs/MeganFox/20101208/88590/Game_Engines_101_The_EntityComponent_Model.php

Quote
class BaseComponent {

virtual void Startup()

virtual void Update()

virtual void Shutdown()

virtual void HandleMessage(MessageType message) .... }

...

What do you think? Should a component just be raw data (which would mean we wouldn't even have a class... just a struct(!) Wow, that's really departing from usual "OO" ideas...!)?
« Last Edit: May 05, 2013, 01:17:03 AM by mike3 »

Nymphaea

  • Rogueliker
  • ***
  • Posts: 74
  • Karma: +0/-0
  • Maria Fox
    • View Profile
    • Nymphaea.ca
That is the basic idea, you can add some basic access methods that would be used a lot.(for instance, there is a "move()" method in my PositionData class that adds a vector to the current position, and the command to modify health in HealthPointData won't allow it to go below 0 or above 'healthMax')

I think a good way of thinking of it, is to think of a component as a new type. It's there to store data. Some types have methods associated with them, but nothing far reaching.


As for the component code you linked, I think it misses the point. The idea for a component system is that the System contains all the logic code, and uses data from components. There shouldn't be an update method in the components. Your "BaseComponent" looks more like "BaseSystem" to me, but missing the methods to associate entities/components to it(I associate entities, the article on the first page associated nodes full of the components)

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
That is the basic idea, you can add some basic access methods that would be used a lot.(for instance, there is a "move()" method in my PositionData class that adds a vector to the current position, and the command to modify health in HealthPointData won't allow it to go below 0 or above 'healthMax')

I think a good way of thinking of it, is to think of a component as a new type. It's there to store data. Some types have methods associated with them, but nothing far reaching.


As for the component code you linked, I think it misses the point. The idea for a component system is that the System contains all the logic code, and uses data from components. There shouldn't be an update method in the components. Your "BaseComponent" looks more like "BaseSystem" to me, but missing the methods to associate entities/components to it(I associate entities, the article on the first page associated nodes full of the components)

Thanks. I'll see if I can roll out a new version of the mini program with the changes discussed so far.
« Last Edit: May 05, 2013, 01:56:22 AM by mike3 »

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
When is each system's "update" function called, in a turn-based non-real-time game like a roguelike?

On each logical tick, we wait for input that will manifest as a player action. Once we get a player action, perform it and continue in the loop.

In a turn-based game, you typically want action-resolutions to occur on the same turn, in which case you're going to update each system per entity, instead of each entity per system. This literally just means inverting the game loop so that you do something like,

Code: [Select]
foreach(entityID:entityIDs) foreach(system:systems) system.update(entityID);
Where one of the systems is an input handling one that waits for user input.

Though you don't want to get input for every entity in the game, just the player, no?

As if the input system waits whenever its update(<entity>) function is called, then you'll get a lot of useless waiting where it waits for input for every monster as well as the PC. So do you have some kind of "input component" on the PC that other entities don't have, and the input system checks for this component, and if there's one present, waits for input, then updates the component with whatever input is given?

You DO want to get input for ALL entities. Just try to realize that the input isn't coming from a keyboard. The input might be better rationalized as a command or instruction. The AI gives commands to their respective avatars just as the player would-- the only difference is that the human interfaces with a keyboard.

You can have separate systems for this-- Such as an InputSystem to fetch the command for the player, but realize that only the player character's entityID and components are subscribed to that system. So it's fine to call all systems on every creature's turn, because each system is only going to do anything if that entityID is used within it's internal component references. I use entityID as a way to indicate to systems to only update one entity at a time- which is necessary for a turn-based game.

Quote
@requerent: In one of your earlier messages you mentioned how one does not need events or messages in a component system. Now does that latter bit mean that I should do away with the "handleMessage" stuff on the components in my test program?

I got the whole "send messages to the components" stuff from reading this:
http://www.gamasutra.com/blogs/MeganFox/20101208/88590/Game_Engines_101_The_EntityComponent_Model.php

She's talking about short-cutting the Component-System idea for broadcast messaging. That is-- you may want to send out global, component-type, or entity-local messages that components capture to perform data transformations on themselves. These transformations could result in other broadcast messages being thrown and... all of a sudden you've begun contradicting the whole point of components.

If you need something like that, the component solution is to just make another system/sub-system that deals with that case specifically. Systems are intended to be logically discrete objects-- they can be numerous and as short as possible.

She goes on to say that you can flexibly solve a larger domain of problems by separating the logic and the data, http://www.gamasutra.com/blogs/MeganFox/20101208/88590/Game_Engines_101_The_EntityComponent_Model.php#comment76795

Code: [Select]
What do you think? Should a component just be raw data (which would mean we wouldn't even have a class... just a struct(!) Wow, that's really departing from usual "OO" ideas...!)?
Other languages have stronger ways of rationalizing data (Like SQL). All that matters is that the system is reading data in manner that is expected. You could use structs, linked lists, or tables. Having a 'Type' isn't necessary or even important. But yes- in C++, you'd most likely use a struct.