October/November development info dump…

So it’s been almost two months since the last update…I guess that means it’s time for a new one!

I’ve done a huge amount of work on the game in that time…..here’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 now have perks
  • the ailment system (hunger, fatigue, bloodloss) was completely redone.
  • new shaders on everything allow for more precise damage decals

Back-end changes:

  • item import system re-written
  • character controller re-written
  • vehicle management system re-written
  • navgrid pathfinding replaced with navmesh pathfinding

Click any of the following images for previews of some of these changes, or click ‘Read More’ below to see all of the explanations in the full post.

Weapons now have durability:

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’s durability is depleted, it ‘breaks’ and is downgraded to a lower level. So, for example, a ‘new axe’ might degrade to a ‘chipped axe’, which then could degrade further into a ‘broken axe’, etc. At each degradation level, the item’s stats are reduced. Eventually repair stations will exist where you can fix your broken items.

Also, items that have durability cannot be stacked on top of each other in the player inventory.

Here is an animated gif showing what happens when an item you are using degrades. As you can see, its icon ‘shatters’, revealing the degraded icon underneath.

Individual items can now have perks:

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’t already contain a perk, the new perk will be chosen at random.

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.

Here’s an image showing where perks are displayed in the inventory panel:

The ailment system was completely redone:

So previously, character ailments (hunger, fatigue, bloodloss) were displayed on-screen in little speech bubbles (here’s a link to the old post which first described them). Aside from the fact that their original design was rather ugly, they weren’t very helpful because until they popped up you’d have no idea how hungry/tired/injured your character was….so unless you kept track of the last time you ate/slept/healed, you’d have no way of figuring out whether your character was close to needing any of those things.

That’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…yet there was no room for any more of those ailment speech bubbles!

So I re-arranged some of the on-screen icons and replaced the old ailment system entirely. Here’s how they look now (although this is just for illustration purposes…they won’t all appear on screen at the same time during gameplay):

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.

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’s an animated gif showing the character entering toxic water and getting poisoned:

Also, as with the original ailment system, if you eat/heal/sleep more than necessary, you’ll get an ailment ‘bonus’ of either a damage, defense or XP boost. Here’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.

New shaders improve damage decals:

So before this last update, I didn’t really know anything about shader languages. I had modified some shaders before but didn’t really understand what I was doing (cg shaders have a structure that can be tricky to understand).

Because of this, I didn’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’s normal texture out with a bloody texture….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…but it worked.

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:

  • store a grunge map in the alpha channel of the zombie texture map
  • 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
  • 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
  • the resulting grunge is then hue-shifted to red

The result is a very nice smooth transition in the zombie texture from normal to fully bloodied that doesn’t require any extra texture maps….and even more importantly: can still be batched because it doesn’t require multiple materials either!

Here is an animated gif showing the effect on a zombie:

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’s an animated gif showing that effect:

Item import system re-written:

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:

items.add(new bluntWeapon("hammer", 20, 1.2, 40, 45, 2, 0, 0, 13, "hammer_attack_animation");

This is similar to how items could be ‘added’ to the game in the old system. Notice the long list of numerical arguments? What do any of those mean? Good question…if I wanted to find out, I’d have to go find the ‘bluntWeapon’ constructor and figure out which argument corresponded to which item property (so, for example, ’40’ might be the damage, ’13’ might be the cost, etc).

Now imagine hundreds of declarations like that, all corresponding to constructors with different arguments. Ugh!!

So I re-wrote every single aspect of the item system, so that it’s now much more organized, and it’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…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.

This new system will greatly speed up how long it takes to add new items to the game — especially craftable items (many of which still need to be added…but that’s for a future update).

Character controller re-written:

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…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.

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.

Vehicle management system re-written:

So as I was about to finish the new city generation system (it’s now done….woohoo!), I realized that my old vehicle management system was needing an upgrade. In the old system, vehicles just existed in the world permanently…no matter where in the map you are standing. This is incredibly inefficient because that means the rigidbody dynamics of a vehicle that’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 ‘active’ would be too high (switching them to kinematic rigidbodies when they’re far away was an option, but that itself would have its own issues).

So I re-wrote the whole system and now, just like every other object in the game, they’re loaded in/out of memory based on how far you are from them. This doesn’t mean a vehicle is ‘deleted’ from the world once you move too far away, it just means that it’s placed back in reserve pool, rather than remaining as an active rigidbody. The added benefit of this is that because they’re now treated like any other in-game prop, they don’t need all of their properties defined by a special vehicle class, they instead just extend the generic prop class. So…they’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’t become ‘active’ until they’re in view.

Navgrid pathfinding replaced with navmesh pathfinding:

This has been the biggest change made to the game, and is what I’ve been working on for the past month.

Basically, as time has progressed in development of Zombox I’ve slowly come to accept the fact that my navgrid pathfinding system simply won’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.

The navgrid system works like this:

  • the world is divided up into a grid of small cells
  • cells are marked as ‘blocked’ when in-game obstacles cover them
  • paths for zombies and NPCs are then generated by traversing unblocked grid cells using the A* search algorithm

In simple cases, this works just fine. But in complex places it can cause several problems. The biggest problems are:

  • 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’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×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…a considerable amount on mobile devices.
  • 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 ‘seem’ 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 ‘trick’ agents (zombies or NPCs) into thinking they cannot traverse an area that is actually wide open.
  • A square grid works great for axis-aligned square objects, but it does not work well with obstacles positioned diagonally…and since vehicles can spin 360 degrees, you run into lots of cases where the navgrid cannot properly correspond to the vehicle obstacles.

So…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).

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’s no point in calculating paths for AI that are far off-screen).

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…success!!

Here’s an outline of how it works, for those interested:

  • Wherever a character is located in the world, navmeshes are generated on nearby tiles in an outward spiral from the character location.
  • Navmeshes are generated by first collecting nearby obstacles and defining a convex polygon around their perimeter.
  • A walkable convex polygon is also defined around the current active tile
  • Using the Clipper library, the obstacle polygons are subtracted from the walkable polygon
  • The resulting hole-containing polygon is then triangulated using the poly2tri library
  • The resulting triangles are then fed into the current navmesh
  • The final list of triangles is processed along with all neighboring navmesh triangle lists to find edge neighbors
  • Once activated, the navmeshes can take pathfinding requests from nearby agents
  • Paths are determined by walking through edges to neighbor triangles until the goal is reached, using A* as the pathfinding algorithm
  • Once a path is found, it is string-pulled using this algorithm to smooth it out

Coroutines are used to generate the navmeshes so that they don’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’t complain about that performance!

Also in the process of working with all those external libraries, I learned C# and can now comfortably code in it. It’s not much different than Javascript but it compiles much faster in Unity and it has a number of other benefits so it’s definitely a good language to know.

Here’s an animated gif showing how the navmeshes are generated as the character moves through the world:

Here’s an animated gif showing how the paths are smoothed (original path is in cyan, smoothed path is in green):

So that’s what’s been happening! If you have any questions, post them down below in the comment section.

 

 

8 Responses to “October/November development info dump…”

  1. cameron c says:

    This game is exactly what I’ve been waiting for. It is boxy, has great destruction physics, able to loot just about everything, and best of all has zombies. Just a question, do you think you will be able to follow your New Years resolution or is there still to much you have to do?

    • Tyson Ibele says:

      No, I don’t think it’ll be out by the end of the year. I’ve got some insane work deadlines to meet by January so I probably won’t be able to do much more work on it until then. And even after that point there’s still a lot left to do!

  2. cameron c says:

    Ok I thought I’d just ask, an I’m not rushing you i totally understand but thanks for even taking time to make this game

  3. AGuy says:

    Hey Tyson. I’ve been following your blog for years now (years) and I just checked back hoping to find that you have a version released.

    Man. To be perfectly honest, the stuff you’re doing right now happens after the release. You get all the systems working, release an alpha, or whatever, and then you rehaul and optimize and bugfix later.

    And I understand that you are implementing new features all the time, but seriously, they are not crucial to gameplay. I think that by this point, you’re losing disgruntled potential customers faster than you’re gaining new excited ones. I mean, you’ve rehauled pathfinding like three times.

    And of course this is all your project, and it’s all up to your best judgement, and heck, I might be the only one thinking this, but honestly it’s a little bit . . . I dunno. I think I’ve pretty much said what I mean and mean what I said.

    Anyway. I do love this game, and you haven’t lost me as a customer, but I think that you should just be trying to release the product, not making it perfect.

    -Some dude

    • Tyson Ibele says:

      Hey some dude,

      Firstly I appreciate the support. Obviously I understand that people want to play the game and so I can empathize with their frustration that it hasn’t been released yet.

      That said, the release model you propose is one that I think it irresponsible from a developer standpoint. I think it would be a big disappointment to a lot of people if I released a buggy/broken version of Zombox. Any of the frustrations that people feel because the game isn’t out yet, would be multiplied tenfold if their first chance to play it was a horrible, broken experience.

      It might seem from the standpoint of fans that I’m endlessly adding features and improving things that don’t need to be improved…but that’s simply because I’ve only shown the best parts of Zombox on the site….not the parts that are buggy, broken and unfinished.

      Here’s a road-map of the last year or so, to get some perspective on what’s been happening:

      * In early 2013, I decided I wanted to increase the size of the Zombox world, and add a much more diverse flavor of zombies and locations. This was a massive change that required a re-write of the entire engine, basically. I felt the payoff was worth it though…with the end result being over 60 zombie types, hundreds of different location types, randomized map support, etc.

      * Then I added the ability for characters to swim. But I didn’t want effortless water-travel to be possible — I wanted it to be something players would use sparsely, so I re-vamped the ailment system to include things like the ability to be poisoned (which is what the water can do to you). The old system looked really ugly and wasn’t user-friendly, so it needed to be replaced anyways.

      * All this time, during testing, it was always in the back of my mind to re-visit the pathfinding. This is a game where the main focus is enemies pursuing you….so if their pursuits are broken, that is very bad. For reasons I won’t explain here (because they’re explained more thoroughly elsewhere in the blog), the A* system was severely lacking and game-breaking….mostly due to many exploits that could be used against it. So I re-wrote the way pathfinding works entirely, using a more flexible, modern navmesh system that a lot of other games use today.

      And that basically brings us to where I am now, save for a few other details I’ve tweaked or changed. There really haven’t been too many little features or things added besides those, in a long time.

      So with all that said, I don’t think your comment about none of these things being related to gameplay is valid. In fact, all of these things are directly tied to core gameplay. Namely, enemy interactions, environment traversal and resource/health management.

      Keep in mind that this is my first game, and I had to teach myself Javascript (and now C#) while I was doing it….so a lot of time has also been spent re-writing horrible code that was written before I knew how to use things like structs, custom classes, constructors, coroutines, etc. Not to mention the fact that I do this only in my spare time….I have a full time job during the day, other priorities, etc that take away from development time.

      At the end of the day, I don’t want Zombox to be perfect — because it’ll never be perfect…but I do want it to be polished, so that the Zombox experience is one that people enjoy, not one that feels rushed or incomplete. Hopefully people will be able to understand that and forgive me for taking so long to get it out 🙂

  4. Destiny says:

    This wetibse makes things hella easy.

Log in or Register

Leave a Reply to AdamM07 Cancel reply

Your email address will not be published. Required fields are marked *