{"id":454,"date":"2013-11-29T22:11:46","date_gmt":"2013-11-30T05:11:46","guid":{"rendered":"http:\/\/www.zombox.net\/?p=454"},"modified":"2013-11-29T22:28:29","modified_gmt":"2013-11-30T05:28:29","slug":"octobernovember-development-info-dump","status":"publish","type":"post","link":"http:\/\/www.zombox.net\/?p=454","title":{"rendered":"October\/November development info dump&#8230;"},"content":{"rendered":"<p>So it&#8217;s been almost two months since the last update&#8230;I guess that means it&#8217;s time for a new one!<\/p>\n<p>I&#8217;ve done a huge amount of work on the game in that time&#8230;..here&#8217;s an overall outline of the new stuff, followed by detailed explanations of each one:<\/p>\n<p><strong>Front-end features:<\/strong><\/p>\n<ul>\n<li>weapons now have durability<\/li>\n<li>individual items can now have perks<\/li>\n<li>the ailment system (hunger, fatigue, bloodloss) was completely redone.<\/li>\n<li>new shaders on everything allow for more precise damage decals<\/li>\n<\/ul>\n<p><strong>Back-end changes:<\/strong><\/p>\n<ul>\n<li>item import system re-written<\/li>\n<li>character controller re-written<\/li>\n<li>vehicle management system re-written<\/li>\n<li>navgrid pathfinding replaced with navmesh pathfinding<\/li>\n<\/ul>\n<p>Click any of the following images for previews of some of these changes, or click &#8216;Read More&#8217; below to see all of the explanations in the full post.<\/p>\n<p><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_112.gif\"><img decoding=\"async\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_112.jpg\" alt=\"\" \/><\/a><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_113.gif\"> <img decoding=\"async\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_113.jpg\" alt=\"\" \/><\/a><\/p>\n<p><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_114.gif\"><img decoding=\"async\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_114.jpg\" alt=\"\" \/><\/a><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_115.gif\"> <img decoding=\"async\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_115.jpg\" alt=\"\" \/><\/a><\/p>\n<p><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_116.gif\"><img decoding=\"async\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_116.jpg\" alt=\"\" \/><\/a> <a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_118.gif\"><img decoding=\"async\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_118.jpg\" alt=\"\" \/><\/a><\/p>\n<p><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_119.gif\"><img decoding=\"async\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_119.jpg\" alt=\"\" \/><\/a><\/p>\n<p><!--more--><\/p>\n<p><strong>Weapons now have durability:<\/strong><\/p>\n<p>So each weapon in the game now has a durability value. Different weapons also have different durability tolerances (better weapons take longer to degrade). When a weapon&#8217;s durability is depleted, it &#8216;breaks&#8217; and is downgraded to a lower level. So, for example, a &#8216;new axe&#8217; might degrade to a &#8216;chipped axe&#8217;, which then could degrade further into a &#8216;broken axe&#8217;, etc. At each degradation level, the item&#8217;s stats are reduced. Eventually repair stations will exist where you can fix your broken items.<\/p>\n<p>Also, items that have durability cannot be stacked on top of each other in the player inventory.<\/p>\n<p>Here is an animated gif showing what happens when an item you are using degrades. As you can see, its icon &#8216;shatters&#8217;, revealing the degraded icon underneath.<\/p>\n<p><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_112.gif\"><img decoding=\"async\" class=\"alignnone\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_112.jpg\" alt=\"\" \/><\/a><\/p>\n<p><strong>Individual items can now have perks:<\/strong><\/p>\n<p>Combining two identical items will now result in a final item which contains a new perk. Perks can take many forms, and many different types of items can get them (not just weapons). So, for example, a piece of clothing might get a defense boost, or a weapon might get a damage boost, etc. When you combine two items that don&#8217;t already contain a perk, the new perk will be chosen at random.<\/p>\n<p>Items that are eligible for perks can get a maximum of two perks. Combining two items that each already have a perk, will result in a final item that contains both perks.<\/p>\n<p>Here&#8217;s an image showing where perks are displayed in the inventory panel:<\/p>\n<p><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_113.gif\"><img decoding=\"async\" class=\"alignnone\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_113.jpg\" alt=\"\" \/><\/a><\/p>\n<p><strong>The ailment system was completely redone:<\/strong><\/p>\n<p>So previously, character ailments (hunger, fatigue, bloodloss) were displayed on-screen in little speech bubbles (<a href=\"?p=375\">here&#8217;s a link<\/a> to the old post which first described them). Aside from the fact that their original design was rather ugly, they weren&#8217;t very helpful because until they popped up you&#8217;d have no idea how hungry\/tired\/injured your character was&#8230;.so unless you kept track of the last time you ate\/slept\/healed, you&#8217;d have no way of figuring out whether your character was close to needing any of those things.<\/p>\n<p>That&#8217;s not even mentioning the fact that eventually I wanted to make it so the character could get poisoned, or could suffer from radiation sickness while traveling close to the giant meteor in the center of the city&#8230;yet there was no room for any more of those ailment speech bubbles!<\/p>\n<p>So I re-arranged some of the on-screen icons and replaced the old ailment system entirely. Here&#8217;s how they look now (although this is just for illustration purposes&#8230;they won&#8217;t all appear on screen at the same time during gameplay):<\/p>\n<p><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_111.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_111med.jpg\" alt=\"\" width=\"480\" height=\"320\" \/><\/a><\/p>\n<p>Now instead of the three previous ailments, there are 5 in total. Hunger, fatigue, bloodloss, poison, and radioactivity. Also, the hunger and fatigue bubbles are always visible so you can keep track of your food\/sleep levels at all times.<\/p>\n<p>Each ailment has various levels of danger, and if you wait too long to sleep\/eat\/heal (depending on the ailment), you could die from them. Here&#8217;s an animated gif showing the character entering toxic water and getting poisoned:<\/p>\n<p><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_114.gif\"><img decoding=\"async\" class=\"alignnone\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_114.jpg\" alt=\"\" \/><\/a><\/p>\n<p>Also, as with the original ailment system, if you eat\/heal\/sleep more than necessary, you&#8217;ll get an ailment &#8216;bonus&#8217; of either a damage, defense or XP boost. Here&#8217;s an example showing the player activating the damage bonus by eating food. Notice that the duration of the bonus is proportionate to the amount of food eaten, and it can only be activated while the player is at full health.<\/p>\n<p><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_115.gif\"><img decoding=\"async\" class=\"alignnone\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_115.jpg\" alt=\"\" \/><\/a><\/p>\n<p><strong>New shaders improve damage decals:<\/strong><\/p>\n<p>So before this last update, I didn&#8217;t really know anything about shader languages. I had modified some shaders before but didn&#8217;t really understand what I was doing (cg shaders have a structure that can be tricky to understand).<\/p>\n<p>Because of this, I didn&#8217;t realize how powerful they could be. For example, previously, when a zombie is hit with a weapon, it gets blood splatters all over its body. This was accomplished by swapping the zombie&#8217;s normal texture out with a bloody texture&#8230;.and because there are various levels of blood that a zombie can be covered in, I was constantly swapping in\/out multiple textures in order to achieve this. It was a clunky, horrible solution&#8230;but it worked.<\/p>\n<p>Well, now I realized that was all a waste because I can use shaders to achieve the same effect using only one texture map! What I do now is the following:<\/p>\n<ul>\n<li>store a grunge map in the alpha channel of the zombie texture map<\/li>\n<li>when a zombie is damaged, set the vertex colors of its mesh to a linearly interpolated value between 0-255 based on the amount of damage done<\/li>\n<li>the zombie shader then uses the vertex color channel to decide how much of the alpha channel grunge map to clip into the main texture<\/li>\n<li>the resulting grunge is then hue-shifted to red<\/li>\n<\/ul>\n<p>The result is a very nice smooth transition in the zombie texture from normal to fully bloodied that doesn&#8217;t require any extra texture maps&#8230;.and even more importantly: can still be batched because it doesn&#8217;t require multiple materials either!<\/p>\n<p>Here is an animated gif showing the effect on a zombie:<\/p>\n<p><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_116.gif\"><img decoding=\"async\" class=\"alignnone\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_116.jpg\" alt=\"\" \/><\/a><\/p>\n<p>And as a further bonus of this new system, I implemented it into all of the inanimate objects in the world too! So damaged props will now get covered in cracks and marks before finally being destroyed! Here&#8217;s an animated gif showing that effect:<\/p>\n<p><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_117.gif\"><img decoding=\"async\" class=\"alignnone\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_117.jpg\" alt=\"\" \/><\/a><\/p>\n<p><strong>Item import system re-written:<\/strong><\/p>\n<p>So when I was implementing item durability, I realized that my old item system was horribly unmanageable and archaic. It was also very difficult to easily update or even understand. As an example, it was similar to the following:<\/p>\n<p><code>items.add(new bluntWeapon(\"hammer\", 20, 1.2, 40, 45, 2, 0, 0, 13, \"hammer_attack_animation\");<\/code><\/p>\n<p>This is similar to how items could be &#8216;added&#8217; to the game in the old system. Notice the long list of numerical arguments? What do any of those mean? Good question&#8230;if I wanted to find out, I&#8217;d have to go find the &#8216;bluntWeapon&#8217; constructor and figure out which argument corresponded to which item property (so, for example, &#8217;40&#8217; might be the damage, &#8217;13&#8217; might be the cost, etc).<\/p>\n<p>Now imagine hundreds of declarations like that, all corresponding to constructors with different arguments. Ugh!!<\/p>\n<p>So I re-wrote every single aspect of the item system, so that it&#8217;s now much more organized, and it&#8217;s able to import items from a standard spreadsheet! So now I define everything nice and cleanly inside a google spreadsheet document (no more guessing about which value means what&#8230;all values now sit in neatly labeled columns), export it to a text file and everything is auto-imported into the right place. Due to the way in which I import things, memory usage is also cut down.<\/p>\n<p>This new system will greatly speed up how long it takes to add new items to the game &#8212; especially craftable items (many of which still need to be added&#8230;but that&#8217;s for a future update).<\/p>\n<p><strong>Character controller re-written:<\/strong><\/p>\n<p>Similar to the old item system, this was another part of the game that had been nagging me for a very long time. The previous character controller had existed in its current state pretty much since day one&#8230;and it was extremely messy and hard to understand or modify. It was basically just a looooooong list (about 1500 lines long) of if-then clauses, defining every possible state the character could exist in and all the various combinations thereof.<\/p>\n<p>Now I implemented an action queue that is a dream to work with. Instead of trailing through a huge list of clauses to figure out what action needs to be performed, I just pop that particular action to the top of a queue that is processed each frame, and the character responds accordingly.<\/p>\n<p><strong>Vehicle management system re-written:<\/strong><\/p>\n<p>So as I was about to finish the new city generation system (it&#8217;s now done&#8230;.woohoo!), I realized that my old vehicle management system was needing an upgrade. In the old system, vehicles just existed in the world permanently&#8230;no matter where in the map you are standing. This is incredibly inefficient because that means the rigidbody dynamics of a vehicle that&#8217;s all the way across the map from you will still be calculated each frame. On iOS devices, this means I could only ever have a handful of vehicles on the map or else the physics requirements to keep them &#8216;active&#8217; would be too high (switching them to kinematic rigidbodies when they&#8217;re far away was an option, but that itself would have its own issues).<\/p>\n<p>So I re-wrote the whole system and now, just like every other object in the game, they&#8217;re loaded in\/out of memory based on how far you are from them. This doesn&#8217;t mean a vehicle is &#8216;deleted&#8217; from the world once you move too far away, it just means that it&#8217;s placed back in reserve pool, rather than remaining as an active rigidbody. The added benefit of this is that because they&#8217;re now treated like any other in-game prop, they don&#8217;t need all of their properties defined by a special vehicle class, they instead just extend the generic prop class. So&#8230;they&#8217;re now very easy to manage and you could, in theory, have hundreds of them scattered throughout the world without any performance hit, because they wouldn&#8217;t become &#8216;active&#8217; until they&#8217;re in view.<\/p>\n<p><strong>Navgrid pathfinding replaced with navmesh pathfinding:<\/strong><\/p>\n<p>This has been the biggest change made to the game, and is what I&#8217;ve been working on for the past month.<\/p>\n<p>Basically, as time has progressed in development of Zombox I&#8217;ve slowly come to accept the fact that my navgrid pathfinding system simply won&#8217;t ever work the way I want it to. This is not due to any bugs, but instead due to the limitations of navgrid systems.<\/p>\n<p>The navgrid system works like this:<\/p>\n<ul>\n<li>the world is divided up into a grid of small cells<\/li>\n<li>cells are marked as &#8216;blocked&#8217; when in-game obstacles cover them<\/li>\n<li>paths for zombies and NPCs are then generated by traversing unblocked grid cells using the A* search algorithm<\/li>\n<\/ul>\n<p>In simple cases, this works just fine. But in complex places it can cause several problems. The biggest problems are:<\/p>\n<ul>\n<li>In order to properly correspond to small in-game obstacles, the grid itself needs to be small. This can take up a lot of RAM. For example, Zombox&#8217;s procedural world is separated into tiles, 126 of which span the width and height of the map. Each of those tiles is then subdivided into 16&#215;16 navgrid cells. Combined, that is over 4 million total navgrid cells required to create the entire navgrid. Each cell must contain a certain amount of information in order to describe its state (number of obstacles covering it, type of obstacles covering it, etc). I eventually decided to use 16-bit integers to contain this data, because 8-bit integers were too small and 32-bit integers were too big. Even with this limited data type, the total RAM requirement for the navgrid alone was almost 10 mb&#8230;a considerable amount on mobile devices.<\/li>\n<li>Because the granularity of the grid can only be so small, I would often run into cases where paths would not form in areas that &#8216;seem&#8217; open, but area really deactivated due to nearby obstacles overlapping parts of the grid cells. I originally considered this only a minor problem but eventually found there are lots of cases where it is a bigger problem. For example, exploiting this issue makes it easy to &#8216;trick&#8217; agents (zombies or NPCs) into thinking they cannot traverse an area that is actually wide open.<\/li>\n<li>A square grid works great for axis-aligned square objects, but it does not work well with obstacles positioned diagonally&#8230;and since vehicles can spin 360 degrees, you run into lots of cases where the navgrid cannot properly correspond to the vehicle obstacles.<\/li>\n<\/ul>\n<p>So&#8230;after all of this, I finally conceded defeat and switched to navmesh pathfinding. Navmesh pathfinding is different in that instead of using a static grid to define walkable areas for your AI, you use a virtual mesh of triangles to define walkable areas. Because the mesh can take any shape, you can effectively describe walkable\/blocked areas with perfect accuracy (rather than trying to find workarounds to the accurage problems of a navgrid).<\/p>\n<p>The caveat to navmesh pathfinding is that generating a procedural navmesh can be very slow. Thankfully, since the Zombox world is already segmented into thousands of individual tiles, I just use those to define areas for the navmesh system to generate navmeshes and connect them together afterwards. I also pool navmeshes in\/out of memory based on their distance from the player in order to conserve RAM (there&#8217;s no point in calculating paths for AI that are far off-screen).<\/p>\n<p>My final implemenation uses a couple of external libraries, requires no new memory allocations per frame (once the necessary data buffers spin up) and runs wonderfully on my iPhone 4S. So&#8230;success!!<\/p>\n<p>Here&#8217;s an outline of how it works, for those interested:<\/p>\n<ul>\n<li>Wherever a character is located in the world, navmeshes are generated on nearby tiles in an outward spiral from the character location.<\/li>\n<li>Navmeshes are generated by first collecting nearby obstacles and defining a convex polygon around their perimeter.<\/li>\n<li>A walkable convex polygon is also defined around the current active tile<\/li>\n<li>Using the <a href=\"http:\/\/www.angusj.com\/delphi\/clipper.php\">Clipper<\/a> library, the obstacle polygons are subtracted from the walkable polygon<\/li>\n<li>The resulting hole-containing polygon is then triangulated using the <a href=\"http:\/\/code.google.com\/p\/poly2tri\/\">poly2tri<\/a> library<\/li>\n<li>The resulting triangles are then fed into the current navmesh<\/li>\n<li>The final list of triangles is processed along with all neighboring navmesh triangle lists to find edge neighbors<\/li>\n<li>Once activated, the navmeshes can take pathfinding requests from nearby agents<\/li>\n<li>Paths are determined by walking through edges to neighbor triangles until the goal is reached, using A* as the pathfinding algorithm<\/li>\n<li>Once a path is found, it is string-pulled using <a href=\"http:\/\/digestingduck.blogspot.ca\/2010\/03\/simple-stupid-funnel-algorithm.html\">this algorithm<\/a> to smooth it out<\/li>\n<\/ul>\n<p>Coroutines are used to generate the navmeshes so that they don&#8217;t require too much time per frame on mobile devices, and because navmeshes requires less nodes to be traversed during the path search than navgrids, they perform quite fast. On my iPhone 4S, each step of the navmesh generation process usually only take 1-2 ms, and finding an individual path takes only about 0.15 ms. Can&#8217;t complain about that performance!<\/p>\n<p>Also in the process of working with all those external libraries, I learned C# and can now comfortably code in it. It&#8217;s not much different than Javascript but it compiles much faster in Unity and it has a number of other benefits so it&#8217;s definitely a good language to know.<\/p>\n<p>Here&#8217;s an animated gif showing how the navmeshes are generated as the character moves through the world:<\/p>\n<p><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_118.gif\"><img decoding=\"async\" class=\"alignnone\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_118.jpg\" alt=\"\" \/><\/a><\/p>\n<p>Here&#8217;s an animated gif showing how the paths are smoothed (original path is in cyan, smoothed path is in green):<\/p>\n<p><a href=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_119.gif\"><img decoding=\"async\" class=\"alignnone\" src=\"http:\/\/www.zombox.net\/stuff\/zombox_cap_119.jpg\" alt=\"\" \/><\/a><\/p>\n<p>So that&#8217;s what&#8217;s been happening! If you have any questions, post them down below in the comment section.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So it&#8217;s been almost two months since the last update&#8230;I guess that means it&#8217;s time for a new one! I&#8217;ve done a huge amount of work on the game in that time&#8230;..here&#8217;s an overall outline of the new stuff, followed by detailed explanations of each one: Front-end features: weapons now have durability individual items can [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[4,8,5,6,7,3],"tags":[],"_links":{"self":[{"href":"http:\/\/www.zombox.net\/index.php?rest_route=\/wp\/v2\/posts\/454"}],"collection":[{"href":"http:\/\/www.zombox.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.zombox.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.zombox.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.zombox.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=454"}],"version-history":[{"count":15,"href":"http:\/\/www.zombox.net\/index.php?rest_route=\/wp\/v2\/posts\/454\/revisions"}],"predecessor-version":[{"id":463,"href":"http:\/\/www.zombox.net\/index.php?rest_route=\/wp\/v2\/posts\/454\/revisions\/463"}],"wp:attachment":[{"href":"http:\/\/www.zombox.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=454"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.zombox.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=454"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.zombox.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=454"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}