{"id":1832,"date":"2012-03-16T17:19:20","date_gmt":"2012-03-16T16:19:20","guid":{"rendered":"http:\/\/t-machine.org\/?p=1832"},"modified":"2015-12-31T18:34:58","modified_gmt":"2015-12-31T17:34:58","slug":"entity-systems-what-makes-good-components-good-entities","status":"publish","type":"post","link":"http:\/\/new.t-machine.org\/index.php\/2012\/03\/16\/entity-systems-what-makes-good-components-good-entities\/","title":{"rendered":"Entity Systems: what makes good Components? good Entities?"},"content":{"rendered":"<p>In the ongoing, epic comments (300+ and counting!) for my Entity Systems posts, one of the recurring questions is:<\/p>\n<blockquote><p>\nWhat makes a good Component?<br \/>\nHow should I split my conceptual model into Entities and Components?<br \/>\nHow should I split my algorithms and methods into Systems?\n<\/p><\/blockquote>\n<p>It&#8217;s often difficult to answer these questions without concrete examples, which are thin on the ground.<\/p>\n<p>Good news, then&#8230;<\/p>\n<p><a href=\"http:\/\/paulgestwicki.blogspot.com\/2010\/06\/entity-system-vs-oo-game-engine.html\">Paul Gestwicki runs a CS315: Game Programming course<\/a>, and last year his students used an Entity System to implement <a href=\"https:\/\/sites.google.com\/site\/morgansraidgame\/\">their game &#8211; Morgan&#8217;s Raid<\/a>. In a recent email conversation, he mentioned he&#8217;d been monitoring the actual number &#8211; and nature &#8211; of the Components and Systems that the teams developed and used on the project.<\/p>\n<p>He&#8217;s now <a href=\"http:\/\/paulgestwicki.blogspot.com\/2012\/03\/components-and-systems-of-morgans-raid.html\">posted this list, along with some brief analysis<\/a>.<\/p>\n<h3>All systems and Components<\/h3>\n<p>Read Paul&#8217;s post &#8211; there are some caveats he mentions, and there&#8217;s a useful diagram showing roughly how many systems were using each component.<\/p>\n<p>I strongly recommend you play the game too (it&#8217;s free, and quick to play) so you can get an idea straight away &#8211; just from the names &#8211; what data and code some of these contain.<\/p>\n<p>To recap, here&#8217;s the list:<\/p>\n<blockquote><p>\n&#8220;For your reading convenience, here&#8217;s a simple tabular view of the systems and components<\/p>\n<table border=\"1\">\n<tr>\n<th>Systems<\/th>\n<th colspan=\"2\">Components<\/th>\n<\/tr>\n<tr>\n<td>\nBackgroundTileSystem<br \/>\nCityNameSystem<br \/>\nDestinationSystem<br \/>\nFadingSystem<br \/>\nGPSToScreenSystem<br \/>\nHoverableSystem<br \/>\nImageRenderingSystem<br \/>\nIntInterpolationSystem<br \/>\nMinimumSleepTimeSystem<br \/>\nMorganLocationSystem<br \/>\nNightRenderingSystem<br \/>\nOnClickMoveHereSystem<br \/>\nOnScreenBoundingBoxSystem<br \/>\nRaidSoundSystem<br \/>\nRailwaySystem<br \/>\nReputationSystem<br \/>\nRevealingTextSystem<br \/>\nSpeedSystem<br \/>\nStepwisePositionInterpolationSystem<br \/>\nSunSystem<br \/>\nTimePassingSystem<br \/>\nTimeTriggeredSystem<br \/>\nTownArrivalSystem<br \/>\nTownArrowSystem<br \/>\nTownUnderSiegeSystem\n<\/td>\n<td>\nAnimationRenderable<br \/>\nArrivesAtTownIndex<br \/>\nBackgroundTile<br \/>\nBeenRaided<br \/>\nCentersOnGPS<br \/>\nCityData<br \/>\nCityImages<br \/>\nCityName<br \/>\nCityPopulation<br \/>\nCityTargets<br \/>\nCommandPoint<br \/>\nDestination<br \/>\nDoesCityHaveMilitia<br \/>\nDoesCityLoseGame<br \/>\nDoesCityWinGame<br \/>\nGPSPosition<br \/>\nGPSPositionList<br \/>\nHasMorganGPS<br \/>\nHoverable<br \/>\nImageRenderable<br \/>\nImageRenderLayer<br \/>\nInGameTime<br \/>\nIntInterpolated\n<\/td>\n<td>\nMinimumSleepTimeOverride<br \/>\nMorgan<br \/>\nMorganLocation<br \/>\nMovesOnClick<br \/>\nOnClickMoveHere<br \/>\nOnScreenBoundingBox<br \/>\nOnScreenBoundingBoxList<br \/>\nPositionInterpolated<br \/>\nRaidable<br \/>\nRaider<br \/>\nRailway<br \/>\nReputation<br \/>\nReputationValue<br \/>\nRevealingText<br \/>\nRoad<br \/>\nRoadsToCity<br \/>\nRouteTaken<br \/>\nSpeed<br \/>\nSun<br \/>\nTerrain<br \/>\nTimeToRaid<br \/>\nTimeTriggeredEvent<br \/>\nTownAdjacency<br \/>\nTownArrow<br \/>\nTownUnderSeige\n<\/td>\n<\/tr>\n<\/table>\n<p>&#8221;\n<\/p><\/blockquote>\n<p>Things I noticed straight away:<\/p>\n<ol>\n<li>There&#8217;s approximately 2:1 ratio of &#8220;components&#8221; to &#8220;systems&#8221;\n<li>In Paul&#8217;s post, all the Systems are accessing *something*\n<li>In Paul&#8217;s post, quite a few Components are NOT accessed\n<li>A couple of components are used by almost every System\n<li>The names of some Systems suggest they&#8217;re very trivial &#8211; perhaps only a dozen lines of effective code\n<li>The names of some Components suggest they&#8217;re being designed in an OOP hierarchy\n<\/ol>\n<p>NB: I haven&#8217;t had time to look at the source code, but <a href=\"https:\/\/sites.google.com\/site\/morgansraidgame\/news\/sourcecodenowavailablenewversionuploaded\">it&#8217;s freely downloadable here<\/a>, so I&#8217;d recommend having a look if you have time.<\/p>\n<h3>How many Components per System?<\/h3>\n<p>I&#8217;ve generally started people off with: &#8220;aim for 1:1 ratio&#8221;. This is mainly to kick them out of the traditional class-based OOP mindset. In practice, there&#8217;s really no need to stick to that religiously &#8211; once you get the hang of ES design, you should be freely adding and subtracting components all over the place.<\/p>\n<p>In reality, the pressures on &#8220;number of systems&#8221; and &#8220;number of components&#8221; are independent. Ideally, you add a new system when you have a major new concept to add to your game &#8211; e.g. &#8220;previously I was using hand-made jumping, now I want to add a complete physics-driven approach. This will mean changing collision-detection, changing the core game-loop, etc&#8221;.<\/p>\n<p>Ideally, you add a new component when you have a new &#8220;dimension&#8221; to the game objects. For instance, if you&#8217;re adding a physics System, you may not need to add any new Components &#8211; it might be that all you need is Location (containing x,y,x position and dx,dy,dz velocity) and RenderState (containing screen-pixels x,y) &#8211; and that you already have those components.<\/p>\n<h3>Zero systems per component<\/h3>\n<p>One of the advantages of an ES is that old code can just fall off the radar and disappear. So I&#8217;m not surprised at all to see some components that appear to be unused &#8211; and it&#8217;s MUCH easier to simply delete this code from your project than it would be on a traditional OOP project. Does anything reference that data? If so, it&#8217;s a set of particular systems. For each system, you can look at MERELY the system and the component, and make a very quick decision about whether you still need this access &#8211; or if you can refactor to move (some of) it somewhere else. The amount of code you need to read to make such decisions safely is typically very small &#8211; i.e. easy, quick, and less error-prone.<\/p>\n<h3>Many systems per component<\/h3>\n<p>This is fine. However, it can also be an early-warning sign of a design or code-architecture bug. Sometimes, there are components that &#8211; innately &#8211; are just needed all over the place. For instance, in a team-based game, the component saying which &#8220;team&#8221; a given object\/player\/item\/building belongs to is likely to affect almost every piece of algorithm code across the board. It&#8217;ll be referenced by many systems.<\/p>\n<p>On the flip-side, it may be a sign that you&#8217;ve put too much data into one component. There are two usual versions of this:<\/p>\n<ol>\n<li>You have &#8211; say &#8211; 8 variables in the struct where you should instead have two structs (components), one with 5 variables, the other with 3.\n<li>You have &#8211; say &#8211; 4 variables in the struct, but different systems are using those variables to mean different things. It works OK for now, but it&#8217;s very fragile &#8211; as soon as the different meanings diverge even a little, your code is going to start breaking\n<\/ol>\n<p>Of course, you get this exact problem in traditional OOP setups, but with an ES it&#8217;s trivial to fix. Split &#8211; or duplicate &#8211; the Component, change a few references in the Systems, and you&#8217;re done. If it turns out a week later that the split wasn&#8217;t necessary &#8211; or worse, was a step backwards (e.g. you find yourself frequently synching the data between those components) &#8211; it&#8217;s extremely cheap to swap it back.<\/p>\n<p>By contrast, with OOP, this is a nightmare scenario, because you have to worry about every method on the original class. Does that method:<\/p>\n<ol>\n<li>Need to exist on both the new classes, or just one?\n<li>Work correctly for the new class it will be on &#8211; or does it currently rely on some of the data  (and shoudln&#8217;t) and will need to be re-written?\n<li>Get used by other parts of the codebase in ways that will break if\/when you split the class?\n<\/ol>\n<h3>Thoughts, Suggestions?<\/h3>\n<p>&#8230;this is just a lightning quick analysis, but I strongly invite you to do you own digging into the classes &#8211; and the codebase &#8211; and come up with your own thoughts and feedback. We have here a convenient, real-life, list of components\/systems &#8211; something to dig our teeth into, and debate the rights and wrongs of each decision. And I&#8217;m sure the students involved on the project would be interested in your feedback on their approaches :)<\/p>\n<h2>Did this post help you?<\/h2>\n<p><a href=\"http:\/\/t-machine.org\/index.php\/2015\/12\/12\/support-me-on-patreon-for-early-access-to-new-entity-systems-articles\/\">Support me on Patreon, writing about Entity Systems and sharing tech demos and code examples<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the ongoing, epic comments (300+ and counting!) for my Entity Systems posts, one of the recurring questions is: What makes a good Component? How should I split my conceptual model into Entities and Components? How should I split my algorithms and methods into Systems? It&#8217;s often difficult to answer these questions without concrete examples, [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[60,9,20],"tags":[],"_links":{"self":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/1832"}],"collection":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/comments?post=1832"}],"version-history":[{"count":3,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/1832\/revisions"}],"predecessor-version":[{"id":3767,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/1832\/revisions\/3767"}],"wp:attachment":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/media?parent=1832"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/categories?post=1832"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/tags?post=1832"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}