{"id":97,"date":"2022-07-30T03:47:24","date_gmt":"2022-07-30T03:47:24","guid":{"rendered":"https:\/\/blog.jdkendall.com\/?p=97"},"modified":"2022-07-30T03:47:24","modified_gmt":"2022-07-30T03:47:24","slug":"medusa-and-entity-component-systems","status":"publish","type":"post","link":"https:\/\/blog.jdkendall.com\/?p=97","title":{"rendered":"Medusa and Entity Component Systems"},"content":{"rendered":"\n<p>With the rewrite to Rust, the Medusa system is moving from a Javascript prototype-based engine (half OO, half data-driven) to a strictly typed entity component system, which is a somewhat confusing model to wrap one&#8217;s head around.<\/p>\n\n\n\n<p>My best understanding to date for the entity component system is along the lines of, a warehouse of colorful pallets with ID numbers printed on the front (entities as the pallet, entity class as the pallet color, and components as objects on the pallet), and workers\/machines that pull pallets from the warehouse and change them according to some logistics (ie, systems). <\/p>\n\n\n\n<p>If you want everything on a pallet, you can pull it by ID &#8211; maybe you&#8217;re going to clear the pallet out, or you have a use for everything present.<\/p>\n\n\n\n<p>Maybe you just want the pallets that have food items so you can assess allergens, so you pull all pallets containing allergens to check at the machine.<\/p>\n\n\n\n<p>Maybe you have all baseball items on red pallets, so you only want to pull red pallets when readying a shipment to the local sports store.<\/p>\n\n\n\n<p>So on and so forth &#8211; you mix and match criteria about what is on the pallets or identify by the pallet ID itself to accomplish goals, and just like machines you can process the inventory in a dependent order or freely as the stock comes in.<\/p>\n\n\n\n<p>(There are some breakdowns in metaphor, but that&#8217;s the rough mental model I&#8217;m starting on.)<\/p>\n\n\n\n<p>Medusa&#8217;s current engine needs to be broken down into its entities, components, and systems. Entities is simple, since we&#8217;re using Bevy &#8211; everything in the ECS is just part of the same overarching Entity type. That&#8217;s one easy hurdle over, but it means that we no longer have a way to paint our pallets a certain color.<\/p>\n\n\n\n<p>To overcome this, we can introduce a new type of component &#8211; a tag component. Tag components exist only to &#8220;paint the pallet&#8221; &#8211; we can use them as a way to pull entities of a certain category. This seems like a good second place, so we&#8217;ll start with one Tag component for each type of entity we have in the game; we can remove unused tags if needed later.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Medusa<\/li><li>Snake<\/li><li>Static mirror<\/li><li>Rotating mirror<\/li><li>Flipping mirror<\/li><li>Floor tile mirror<\/li><li>Door<\/li><li>Panel<\/li><li>Button<\/li><li>Lever<\/li><li>Perseus<\/li><li>Bitmap text<\/li><li>Menu cursor<\/li><li>Logo<\/li><li>Icon<\/li><\/ul>\n\n\n\n<p>That&#8217;s a starting point, we can at least spawn these into the framework now when loading a map, though not much else &#8211; they won&#8217;t even render. We&#8217;ll need some real components to give them some meat, and some systems to, er&#8230; cook that meat&#8230; <\/p>\n\n\n\n<p>&#8230;maybe no more metaphors. <\/p>\n\n\n\n<p>We can start with a simple system first, the render system. Thankfully, Bevy comes prepackaged with everything we need for that, so we only need to provide a component for the sprites! Anything we want to render will need a sprite <em>(conveniently ignoring non-sprite rendering)<\/em> so we&#8217;ll add that to every entity. We&#8217;ll use <code>TextureAtlasSprite<\/code> for this, as it will make animation easier later.<\/p>\n\n\n\n<p>Next, all of these are located somewhere on screen. As such, they need a position &#8211; this can be handled just on transforms, but since we may want to mess with the visual position without affecting the game world position, we&#8217;ll opt to have a dedicated <code>Position<\/code> component with <code>x<\/code> and <code>y<\/code> integers as fields. While we&#8217;re at it, many of the entities have a direction they face as well, so let&#8217;s throw in a <code>Facing<\/code> component which contains a direction enum field as well.<\/p>\n\n\n\n<p>We&#8217;ll want a system to calculate the transform positions based on the objects&#8217; game world positions and update it accordingly, so we&#8217;ll add a <code>PositionSystem<\/code> for that which for now will just set the transforms for our sprites to match our positions on screen through a camera transform.<\/p>\n\n\n\n<p>That gives us enough of a starting point to get these fellas on screen, so I&#8217;ll go do that now. Next post on the topic, we&#8217;ll look at entity-specific behaviors and try to build up something simple: a rotating mirror.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>With the rewrite to Rust, the Medusa system is moving from a Javascript prototype-based engine (half OO, half data-driven) to a strictly typed entity component system, which is a somewhat confusing model to wrap one&#8217;s head around. My best understanding to date for the entity component system is along the lines of, a warehouse of&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-97","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blog.jdkendall.com\/index.php?rest_route=\/wp\/v2\/posts\/97","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.jdkendall.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.jdkendall.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jdkendall.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jdkendall.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=97"}],"version-history":[{"count":4,"href":"https:\/\/blog.jdkendall.com\/index.php?rest_route=\/wp\/v2\/posts\/97\/revisions"}],"predecessor-version":[{"id":101,"href":"https:\/\/blog.jdkendall.com\/index.php?rest_route=\/wp\/v2\/posts\/97\/revisions\/101"}],"wp:attachment":[{"href":"https:\/\/blog.jdkendall.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=97"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jdkendall.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=97"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jdkendall.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=97"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}