{"id":281,"date":"2010-05-01T03:45:00","date_gmt":"2010-05-01T09:45:00","guid":{"rendered":"http:\/\/elysianshadows.com\/2010\/05\/transforms-subsystems-and-components\/"},"modified":"2010-05-01T03:45:00","modified_gmt":"2010-05-01T09:45:00","slug":"transforms-subsystems-and-components","status":"publish","type":"post","link":"http:\/\/elysianshadows.com\/updates\/transforms-subsystems-and-components\/","title":{"rendered":"Transforms, Subsystems, and Components"},"content":{"rendered":"\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">I have also implemented a good deal of additional functionality (runtime getting and setting of the terrain and tile\/object attributes). These methods will probably only be utilized through scripts (C++ or Lua). I&#8217;m posting the class declaration, just so you can have a look at function prototypes that have been implemented.<\/p>\n<pre>class TerrainSystem: public System { private: \tunsigned char currentTile[256]; \tunsigned char currentObject[256]; \t\/\/toggles \tbool renderTileLayer[2], renderObjectLayer[2]; \tbool animate, renderSolidity; \tbool isValidLayer(const unsigned short int layer) const; \tbool isValidTile(const unsigned char index) const; \tbool isValidObject(const unsigned char index) const; \tbool isInMapBounds(const unsigned short int x, const unsigned short int y) const; public: \tTerrainSystem(); \tvoid Update(); \tvoid Render(); \t\/\/void DBGDump(); \t\/\/-------LUA STUFF--------- \tvoid getMapSize(int &amp;w, int &amp;h) const; \tunsigned short int getTileAmount() const; \tunsigned short int getObjectAmount() const; \t\/\/Toggles \tbool getAnimate() const; \tvoid setAnimate(const bool v); \tbool getRenderSolidity() const; \tvoid setRenderSolidity(const bool v); \tbool getRenderTileLayer(const unsigned short int layer) const; \tvoid setRenderTileLayer(const unsigned short int layer, const bool v); \tbool getRenderObjectLayer(const unsigned short int layer) const; \tvoid setRenderObjectLayer(const unsigned short int layer, const bool v); \tTile *getTile(const unsigned char index) const; \tObject *getObject(const unsigned char index) const; \tTile *getCurrentTile(const unsigned char index) const; \tObject *getCurrentObject(const unsigned char index) const; \tunsigned char getTileLayer(const unsigned short layer, const int x, const int y) const; \tvoid setTileLayer(const unsigned short layer, int x,  int y, const unsigned char index); \tunsigned char getObjectLayer(const unsigned short layer, const int x, const int y) const; \tvoid setObjectLayer(const unsigned short layer, const int x, const int y, const unsigned char index); }; <\/pre>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">[b]gyro::Transform Parenting[\/b]<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">Transform parenting is a very important aspect of the transform matrix. It allows us to create an entity (such as a sprite, collidable region, etc) whose location is [i]relative[\/i] to another entity. In our engine, each entity is basically a rectangle. When you attach something like a &#8220;sprite&#8221; its transform becomes parented by the entity&#8217;s transform. This enables the sprite to move around based on where the entity is located. Collidable regions work similarly. Some entities might have collidable regions that aren&#8217;t the same as their sprite or rect regions. These collidables can have their own local position that serves as an offset from the parent transform.<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">Mathematically, this is implemented by transforming a transform by its parent (3&#215;3 Matrix multiplication in 2D). For the behavior to be as we would expect, the child&#8217;s transform must be [i]relative[\/i] to the parent&#8217;s. This actually becomes quite a pain in the ass and is the reason I&#8217;m not yet done.<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">So what if we have a transform heirarchy? The child&#8217;s parent has a parent? Well, we must traverse the hierarchy upwards and examine each parent to determine value&#8217;s for the child that is relative to each. It&#8217;s technically a O(n) traversal every time we want to screw with a child&#8217;s transform. (Sounds smart, huh?) I have yet to implement that functionality.&nbsp;<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">Here is what I have of the Transform2D class. It is a bunch of ugly ass linear-algebra math. It&#8217;ll be much uglier when I move this to assembly on the Dreamcast or PSP.&nbsp;<\/p>\n<pre>class Transform2D: private Matrix3x3 { private: \tbool updateTransform; \tVector2 position; \tVector2 size; \tVector2 scale; \tfloat orientation; \tfloat z; \tTransform2D *parent;  public: \tinline Transform2D(): Matrix3x3(), parent(NULL), position(0, 0), size(1.0f, 1.0f), scale(1.0f, 1.0f), orientation(0.0f), z(50.0f), updateTransform(true) {} \tinline Vector2 getPosition() { return position; } \tinline void getPosition(float &amp;x, float &amp;y) const { x = position.x; y = position.y; } \tinline void setPosition(const Vector2 pos) { position = pos; updateTransform = true; } \tinline void setPosition(const float x, const float y) { position.x = x; position.y = y; updateTransform = true; } \tinline float getZ() const { return z; } \tinline void setZ(const float p_z) { z = p_z; updateTransform = true; } \tinline Vector2 getSize() const { return size; } \tinline void getSize(float &amp;x, float &amp;y) const { x = size.x; y = size.y; } \tinline void setSize(const Vector2 &amp;p_size) { size = p_size; updateTransform = true; } \tinline void setSize(const float x, const float y) { size.x = x; size.y = y; updateTransform = true; } \tinline Vector2 getScale() const { return scale; } \tinline void getScale(float &amp;x, float &amp;y) const { x = scale.x; y = scale.y; } \tinline void setScale(const Vector2 &amp;p_scale) { scale = p_scale; updateTransform = true; } \tinline void setScale(const float x, const float y) { scale.x = x; scale.y = y; updateTransform = true; } \tinline float getOrientation() const { return orientation; } \tinline void setOrientation(float angle) { orientation = angle; updateTransform = true; } \tinline Matrix3x3 getMatrix3x3() { UpdateMatrix3x3(); return *this; } \tinline void setMatrix3x3(const Matrix3x3 &amp;tr) { *((Matrix3x3*)this) = tr; updateTransform = false; } \tinline void setParent(Transform2D &amp;p) { parent = &amp;p; } \tinline void Rotate(float angle) { orientation += angle; updateTransform = true; } \tinline void Move(const Vector2 &amp;dist) { position += dist; updateTransform = true; } \tinline void Move(const float xdist, const float ydist) { position.x += xdist; position.y += ydist; updateTransform = true; } \tinline void Scale(const Vector2 &amp;amount) { scale *= amount; updateTransform = true; } \tinline void Scale(const float xamount, const float yamount) { scale.x *= xamount; scale.y *= yamount; updateTransform = true; } \tinline Vector2 Transform(const Vector2 &amp;vec) {  \t\tUpdateMatrix3x3(); \t\tif(parent) parent-&gt;UpdateMatrix3x3(); \t\treturn (!parent)? (*((Matrix3x3*)this) * vec) : ((*((Matrix3x3*)this) * (*((Matrix3x3*)parent)))) * vec;  \t\t\/\/return (*((Matrix3x3*)this)*vec); \t} \tinline void UpdateMatrix3x3() {  \t\tif(!updateTransform) return; \t\tVector2 relativeSize = size*scale; \t\tCalculateTransform(orientation, relativeSize, position); \t\tupdateTransform = false; \t} }; <\/pre>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">[b]CameraSystem[\/b]<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\"><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-279\" src=\"http:\/\/elysianshadows.com\/updates\/wp-content\/uploads\/2010\/05\/ES016.jpg\" border=\"0\" alt=\"\" width=\"524\" height=\"782\" srcset=\"http:\/\/elysianshadows.com\/updates\/wp-content\/uploads\/2010\/05\/ES016.jpg 524w, http:\/\/elysianshadows.com\/updates\/wp-content\/uploads\/2010\/05\/ES016-201x300.jpg 201w\" sizes=\"auto, (max-width: 524px) 100vw, 524px\" \/><\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">The camera system is currently NOT done. The plan was to be able to set an entity&#8217;s transform as the camera transform&#8217;s parent. This would allow the camera to follow any entity without having to be constantly passed a position every frame. If a script needs to manipulate the camera directly, it can set the camera&#8217;s parent to NULL, and directly manipulate the transform&#8217;s position, rotation, and scale. This is useful for cutscenes especially. I need to finish parenting functionality completely before I can do this, though.<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">[b]New Scripting Hierarchy[\/b]<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\"><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-280\" src=\"http:\/\/elysianshadows.com\/updates\/wp-content\/uploads\/2010\/05\/ES017.jpg\" border=\"0\" alt=\"\" width=\"551\" height=\"782\" srcset=\"http:\/\/elysianshadows.com\/updates\/wp-content\/uploads\/2010\/05\/ES017.jpg 551w, http:\/\/elysianshadows.com\/updates\/wp-content\/uploads\/2010\/05\/ES017-211x300.jpg 211w\" sizes=\"auto, (max-width: 551px) 100vw, 551px\" \/><\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">First of all, note that the &#8220;script&#8221; inheritance hierarchy has changed a little bit. Components that are built-in to our engine are simply inheriting from component (sprite, collidable, warp, rigidbody, etc).&nbsp;<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">The next level down brings us to a &#8220;behavior.&#8221; This is what I referred to as a &#8220;script&#8221; before. A behavior has a group of trigger functions like OnHit(), OnTalk(), OnMove(), OnUpdate(), etc that are called when a specific event occurs.<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">Any compiled C++ behavior simply inherits from this level (with it&#8217;s own editor and engine implementation). It simply overwrites each virtual trigger that it wishes to implement for a particular behavior.<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">On the other end of the spectrum, we have a LuaBehavior, or a &#8220;script.&#8221; The LuaBehavior&#8217;s implementations of these virtual functions simply invoke functions from the Lua Script. So you can almost think of the Lua scripts as virtually inheriting from LuaBehavior.<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">[b]Dynamic C++ Behavior Registration[\/b]<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">This is going to be difficult to explain&#8230; it is really just a solution that I found to help further separate user-defined C++ behaviors from our actual &#8220;engine.&#8221; It&#8217;s a pretty, object-oriented solution.&nbsp;<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">The &#8220;Entity&#8221; class will contain a static vector of &#8220;allocator&#8221; functions. An allocator function basically provides an integer for its corresponding component, receives a file-handle, and allocates\/deserializes its respective component.&nbsp;<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">This way each new C++ behavior will not have to be some hardcoded addition to the Entity::Load()&#8217;s component switch statement. Entity simply calls the allocator (in its internal static array) that corresponds to the component index. The entity allocator gets passed a file handle, and returns its respective component (which is then polymorphed back up to a behavior and added to the entity&#8217;s list of behavior&#8217;s).<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">Don&#8217;t worry if I&#8217;ve confused you. Just know it&#8217;s very pretty.<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">[b]Conclusion[\/b]<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">Everything that I have done so far is in my repository. It all builds perfectly with a fresh version of Visual Studio 2008 (provided that you set the correct working directory). [b]All that it does is render a map[\/b] through the TerrainSystem currently. You will notice plenty of &#8220;could not load&#8221; errors in your console when you run the engine. This is because we have yet to save\/load or handle things like rigidbodies, warps, enemies, etc. and the level function is expecting them.<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">I will next be working on command-line arguments so that Marcel&#8217;s level editor can easily invoke the engine with a current Level and Area. Hopefully this will be an easy-to-access File-&gt;Run Current that allows you to seamlessly test your levels as you develop them. Peace, gents.<\/p>\n","protected":false},"excerpt":{"rendered":"<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\"><strong>Originally posted in our Private Development forums on 5.1.10.<\/strong><\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">This is going to be my final gigantic post\/update until after finals. I purposely worked my ass off all during the week, so that I would be able to contribute (and have all weekend to study). I have finals next week and the Monday\/Tuesday after that. I intend to study my ass off, so you might not see me around quite as much.<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">[b]TerrainSystem[\/b]<\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\"><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-278\" src=\"http:\/\/elysianshadows.com\/updates\/wp-content\/uploads\/2010\/05\/ES015.jpg\" border=\"0\" alt=\"\" width=\"494\" height=\"782\" srcset=\"http:\/\/elysianshadows.com\/updates\/wp-content\/uploads\/2010\/05\/ES015.jpg 494w, http:\/\/elysianshadows.com\/updates\/wp-content\/uploads\/2010\/05\/ES015-189x300.jpg 189w\" sizes=\"auto, (max-width: 494px) 100vw, 494px\" \/><\/p>\n<p style=\"color: #333333; font-family: Tahoma, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 15px;\">The terrain system is pretty much done. This is the system that renders and facilitates access to the terrain (when I say terrain, I&#8217;m referring to object\/tile layers 1 and 2). This system will also be responsible for animating the tiles. While the level itself contains the actual tileset and objectset, the TerrainSystem contains a &#8220;currentset&#8221; for each, which is the tile that is currently occupying the space (tile 3 might swap to 2 and back when animating. The actual map contains 3, but the current array could have 2 or 3). This also allows me to update tiles based on simply swapping indeces rather than iterating through the map (which would be completely fucktarded).<\/p>\n","protected":false},"author":1,"featured_media":278,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"class_list":["post-281","post","type-post","status-publish","format-standard","hentry","category-underlying-technology"],"_links":{"self":[{"href":"http:\/\/elysianshadows.com\/updates\/wp-json\/wp\/v2\/posts\/281","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/elysianshadows.com\/updates\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/elysianshadows.com\/updates\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/elysianshadows.com\/updates\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/elysianshadows.com\/updates\/wp-json\/wp\/v2\/comments?post=281"}],"version-history":[{"count":0,"href":"http:\/\/elysianshadows.com\/updates\/wp-json\/wp\/v2\/posts\/281\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/elysianshadows.com\/updates\/wp-json\/wp\/v2\/media\/278"}],"wp:attachment":[{"href":"http:\/\/elysianshadows.com\/updates\/wp-json\/wp\/v2\/media?parent=281"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/elysianshadows.com\/updates\/wp-json\/wp\/v2\/categories?post=281"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/elysianshadows.com\/updates\/wp-json\/wp\/v2\/tags?post=281"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}