Jump to content

  • Log In with Google      Sign In   
  • Create Account

Interested in a FREE copy of HTML5 game maker Construct 2?

We'll be giving away three Personal Edition licences in next Tuesday's GDNet Direct email newsletter!

Sign up from the right-hand sidebar on our homepage and read Tuesday's newsletter for details!


We're also offering banner ads on our site from just $5! 1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Component programming. I think?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
32 replies to this topic

#21 Zipster   Crossbones+   -  Reputation: 763

Like
0Likes
Like

Posted 07 March 2013 - 01:33 PM

You say that the damage system spawns some particle effects and sound. This should be avoided, as you are now no longer SOLID (damage system should only take responsibility of damages, not graphical effects and sound).

The damage effect system wouldn't literally spawn anything, it would just set a flag indicating the nature of the effect and a particle system, er, system would come along and do the actual particle spawning.

 

 

Components having logic vs systems having logic:

Isn't it the same thing? Take a component with logic, make all the functions static, add an ID parameter, and move the data into a struct.

Then the entity becomes either a container of structs, or if the systems hold the data, just an ID. You still use it the same way, passing messages with a target entity which modify the component data and spawn other messages or interact with lower-level systems that do the heavy lifting. You can't do everything by setting flags and waiting for the update, that sounds like a nightmare.

Components having logic forces you to choose a single component in which to put every piece of logic. If there's logic that needs to interact with data from several components, or with multiple object instances, where is the best place to put that logic? In my experience with traditional "component" systems, it's just stuffed into whichever component makes the most sense to that particular developer at that particular point in time. Part of the problem is that as OO programmers we've been trained to always stuff our logic and data together, but that only makes sense when the logic can be completely localized to a particular object, otherwise it's no longer self-contained and is no longer an independent "object". To me, the ECS pattern strives to make the distinction between logic and the data it acts on much more explicit. As a result of this looser coupling, its very easy to modify or extend both.

 

And you most certainly can do quite a bit with setting 'flags' and waiting for 'updates'. That's basically how any relational database programming works ;)



Sponsor:

#22 phil_t   Crossbones+   -  Reputation: 3945

Like
1Likes
Like

Posted 07 March 2013 - 02:39 PM

Systems nicely solve the problem of one kind of Component needing to talk to another.

Components shouldn't have any knowledge of each other. Instead, the logic is in the System which knows about all the Components in which it is interested.

#23 larspensjo   Members   -  Reputation: 1557

Like
0Likes
Like

Posted 07 March 2013 - 04:42 PM

The damage effect system wouldn't literally spawn anything, it would just set a flag indicating the nature of the effect and a particle system, er, system would come along and do the actual particle spawning.

 

What name would you give this flag, and in which component would it be set?

 

Using flags in components is one way to indirectly communicate between systems. Please explain how the example of the achievement system (from above) would be implemented using flags.


Current project: Ephenation.
Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

#24 Zipster   Crossbones+   -  Reputation: 763

Like
0Likes
Like

Posted 07 March 2013 - 05:39 PM

What name would you give this flag, and in which component would it be set?

You would either have a DamageEffectComponent, or just a generic VisualEffectComponent, which holds a list of visualizations that need to occur, depending on your definition of an 'effect'. It could be a particle system, a screen-space effect (like fades or blood splatter), or even sound effects (in which case you probably wouldn't call it VisualEffectComponent, but you get the idea), etc. This list can be populated by the DamageSystem, but I would personally create a new DamageEffectSystem with the express purpose of translating damage state into effects and have DamageSystem only handle the raw damage calculations. Then the ParticleSystem, ScreenEffectSystem, and AudioSystem would come around and cherry-pick the effects they're each responsible for out of the list. The nice thing about ECS is that components are designed to be extremely lightweight, and systems very specific in purpose, so it encourages you to have more components and systems, rather than try and pigeonhole new data and logic into existing components because it might be easier. At first it seems like more components and systems would be a bad thing, but you'd be surprised just how easy it is to find and organize things when each piece only has a single responsibility.

 

Using flags in components is one way to indirectly communicate between systems. Please explain how the example of the achievement system (from above) would be implemented using flags.

The communication is meant to be passive and indirect so that there isn't any tight coupling between components or systems. You're not sending messages between components per se, but rather storing data that can be consumed by systems, which can then respond to that data by adding/removing components, modifying their data, etc. In the case of the achievement system, you could have an AchievementComponent and AchievementSystem, where the component is populated with statistics from the DamageSystem (i.e. "player X killed monster Y at time Z with weapon W"). The AchivementSystem then analyses this data and determines if an achievement has been satisfied.



#25 larspensjo   Members   -  Reputation: 1557

Like
0Likes
Like

Posted 08 March 2013 - 12:20 AM

You would either have a DamageEffectComponent, or just a generic VisualEffectComponent, which holds a list of visualizations that need to occur, depending on your definition of an 'effect'.

Sorry for pushing this, but to make my point, we need to go into depth. Suppose the solution with a VisualEffectComponent is used. I suppose this would be a temporary component? That is, it is added for this purpose, and removed when "used"?

 

How would you implement the sound effect? Would you create a "SoundEffectComponent" for that? How would you create the log message in the chat window, would you create a "LogMessage" component for that?

 

Now back to the other proposal, using a "DamageComponent". I suppose this solution would also be a temporary component, which is removed when used? If so, who would have  the responsibility to remove the component again? How long will the component stay attached on the entity (monster)?

 

You're not sending messages between components per se, but rather storing data that can be consumed by systems

Please enlighten me, what kind of data will you store in the achievement component to solve the specific achievement problem i listed above? The example I had was an achievement where the player had to hit a number of monsters with arrows in a limited time period. How would you solve this with an achievement component?


Current project: Ephenation.
Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

#26 EWClay   Members   -  Reputation: 659

Like
0Likes
Like

Posted 08 March 2013 - 01:44 AM

I would like to understand this too. A complete novice could come in and explain how to solve a problem with messages, but we have not yet had a coherent example using flags. So far it sounds like you somehow cache the content of the messages in one of the components, and have every system come along and look at the list later. Not seeing how that's better.

#27 Zipster   Crossbones+   -  Reputation: 763

Like
1Likes
Like

Posted 08 March 2013 - 10:11 PM

Sorry for pushing this, but to make my point, we need to go into depth. Suppose the solution with a VisualEffectComponent is used. I suppose this would be a temporary component? That is, it is added for this purpose, and removed when "used"?

It could be a temporary component, yes. The alternative would be to make it permanent and have it store an empty list most of the time, but then the interested systems would waste time iterating over it to only find an empty list. If it's temporary, systems can create and destroy it as they deem it necessary. However either approach technically works.

How would you implement the sound effect? Would you create a "SoundEffectComponent" for that? How would you create the log message in the chat window, would you create a "LogMessage" component for that?

The effect component would contain an abstract description of the sound effect, and the sound effect system would just play it using whatever sound library the engine provides. There is no sound effect component to be created. Likewise there is no need for a log message component, whenever a system needs to log a message it just does so using the logging API, or sending an event that the UI can listen for to display a visual message.

Now back to the other proposal, using a "DamageComponent". I suppose this solution would also be a temporary component, which is removed when used? If so, who would have  the responsibility to remove the component again? How long will the component stay attached on the entity (monster)?

This would be a permanent component, the existence of which also acts as a 'tag' (or 'aspect' if you will) to indicate that its parent entity can take damage, and thus any systems that deal damage for whatever reason should be on the look out for these entities. Removing the component would mean the entity can no longer take damage, which could be a very helpful feature during development.

Please enlighten me, what kind of data will you store in the achievement component to solve the specific achievement problem i listed above? The example I had was an achievement where the player had to hit a number of monsters with arrows in a limited time period. How would you solve this with an achievement component?

Whenever damage is done to an entity (which would mean it has a DamageComponent), the system applying the damage would also log an event, some packet of data, to the AchievementComponent of the attacker, if they have one. In this case only the player entity would have this component. If you log information pertaining to which entity was damaged, at what time, and with what weapon, the achievement system then has all the information it needs to determine whether the player hit a certain number a monsters in some time period. At that point it's just a data-mining problem: query all the damage events that have occurred in the past 10 seconds, with an arrow weapon, and count the number of unique monsters. If it's greater than or equal to 5, award the respective achievement.

#28 Zipster   Crossbones+   -  Reputation: 763

Like
1Likes
Like

Posted 08 March 2013 - 10:53 PM

I would like to understand this too. A complete novice could come in and explain how to solve a problem with messages, but we have not yet had a coherent example using flags. So far it sounds like you somehow cache the content of the messages in one of the components, and have every system come along and look at the list later. Not seeing how that's better.

I think I've provided a few coherent examples, but that's just my opinion smile.png You might be missing the forest for the trees and focusing too much on the message-passing aspect of the design (or lack thereof), which is really just a side effect of removing all logic from components so that they no longer can communicate directly. Instead of components responding to messages from other components, systems respond to all changes in component data and make further updates to components as necessary. It's an inversion of responsibility, where instead of individual components trying to wrangle what happens to other entities and components in addition to themselves, entire systems become responsible for these tasks. As long as you adhere to that guiding principle, everything else is pretty much an implementation detail - which components are permanent vs transient, how systems can communicate with each other, how systems know when they need to run, and how often, etc.

#29 EWClay   Members   -  Reputation: 659

Like
0Likes
Like

Posted 09 March 2013 - 07:01 PM

Whenever damage is done to an entity (which would mean it has a DamageComponent), the system applying the damage would also log an event, some packet of data, to the AchievementComponent of the attacker, if they have one. In this case only the player entity would have this component. If you log information pertaining to which entity was damaged, at what time, and with what weapon, the achievement system then has all the information it needs to determine whether the player hit a certain number a monsters in some time period. At that point it's just a data-mining problem: query all the damage events that have occurred in the past 10 seconds, with an arrow weapon, and count the number of unique monsters. If it's greater than or equal to 5, award the respective achievement.


If I read that right, every system has to be aware of the achievement component, and has to log everything that ever happens because achievements can be triggered by any weird combination of factors over any time period. And the achievement system has to mine a huge amount of data on a constant basis. Whereas using messages and an observer nothing else needs to know that achievements even exist, and the overhead is minimal.

#30 Zipster   Crossbones+   -  Reputation: 763

Like
0Likes
Like

Posted 11 March 2013 - 11:40 AM

Whenever damage is done to an entity (which would mean it has a DamageComponent), the system applying the damage would also log an event, some packet of data, to the AchievementComponent of the attacker, if they have one. In this case only the player entity would have this component. If you log information pertaining to which entity was damaged, at what time, and with what weapon, the achievement system then has all the information it needs to determine whether the player hit a certain number a monsters in some time period. At that point it's just a data-mining problem: query all the damage events that have occurred in the past 10 seconds, with an arrow weapon, and count the number of unique monsters. If it's greater than or equal to 5, award the respective achievement.


If I read that right, every system has to be aware of the achievement component, and has to log everything that ever happens because achievements can be triggered by any weird combination of factors over any time period. And the achievement system has to mine a huge amount of data on a constant basis. Whereas using messages and an observer nothing else needs to know that achievements even exist, and the overhead is minimal.

 

Achievements are always going to be a data mining problem regardless of where that data is stored or how it gets there. You simply replaced logging events to a component with sending a message. In either case, the code needs to know that some event X is "significant" enough to be stored to a component, or in your case warrants a message to be sent. The fact that it's called the "achievement" component is irrelevant; you could instead call it the "stats" components to make its purpose less specific and more reusable (and this is probably what I would call it in a real design), but it would still need to store data required to evaluate achievements. And if a history is required to evaluate a particular achievement, then that cached data isn't suddenly going to go away when the data transfer mechanism changes.

 

Achievement systems always tend to require very specific data to be collected across multiple gameplay systems, and often times that data isn't relevant to anything but achievements. So we can tell ourselves that we're collecting monster damage data for some unknown yet hopefully non-specific, reusable purpose, but in many cases the developer just had to add that data logging to be able to award some achievement somewhere down the road, and otherwise that data is useless smile.png



#31 Zipster   Crossbones+   -  Reputation: 763

Like
1Likes
Like

Posted 11 March 2013 - 01:21 PM

Also, just to be clear, I'm not advocating the complete removal of events or messages from the design. All I'm saying is that the components themselves should neither send nor receive these messages. The systems, however, are free to communicate among themselves. As a matter of a fact, signaling would probably be the most efficient way to handle the achievement system, since it only needs to run occasionally. Whenever another system modifies component state that could affect achievement status, it sends a signal to the achievement system to wake it up. The achievement system runs once, awarding any achievements it detects, then goes back to sleep until it receives another "reevaluate" signal.



#32 larspensjo   Members   -  Reputation: 1557

Like
0Likes
Like

Posted 11 March 2013 - 01:33 PM

All I'm saying is that the components themselves should neither send nor receive these messages. The systems, however, are free to communicate among themselves.

 

Ah, then I agree completely. It may be we argued around a misunderstanding.


Current project: Ephenation.
Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

#33 EWClay   Members   -  Reputation: 659

Like
0Likes
Like

Posted 11 March 2013 - 01:43 PM

As a matter of a fact, signaling would probably be the most efficient way to handle the achievement system, since it only needs to run occasionally.


Well, that was my point. Agreed then.

Where the logic lives isn't a great concern to me; as long as the most suitable algorithms can be allowed to work.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS