Hello.
Since we’ve been working on Project Zomboid, we’ve been for the first time introduced to the wonderful world of isometric game making.
This has been somewhat of a nightmare for Binky, seeing as he has to draw isometric tiles and worse, animate isometric characters in 5 directions.
It’s also been a bit of a coding challenge, as I’ve never touched an iso engine before and in fact had only vaguely considered the principals of it prior to making the game.
Since back at this point I was still considering flash for the game, I looked around at various isometric based engines and found a few, but they were all pretty simple. Few had multi-floor support, a must for our game, and generally they all seemed more simplistic and suited to games like Farmville more than an X-COM style engine.
As usual, I dove in quickly to get a feel of how the engine would work. My first bash at it revealed that to draw the isometric map in a way that drew all the tiles correctly, I had to draw the tiles like this:
In the first prototype of the engine, I did this for each z floor of the map, which seemed to work great. Each grid square could have one or more IsoObjects on it. A floor tile, for example, would be added first, and thus drawn first. Secondly, a wall segment if present, on either the west or north walls (tilting your head to the right)
Walls are never present on the south or east walls since they are north or west walls of the adjacent tiles further down the X, Y axis.
After a wall a piece of furniture on the tile could then be placed. This ensured the everything drew correctly and was in its proper place.
Next came adding support for moving objects to the engine. The tricky thing about doing this is that, usually, you maintain an object list for all updating entities in your game, which you iterate to update and draw them. But clearly for an iso engine, where the characters need to be drawn at a precise time, I would need something else.
So to solve this I introduced a list of moving objects for each GridSquare, in addition to the global movingobject list. Subsequent to an object’s update, I removed the object from it’s ‘previous’ grid-square, and added it to its ‘current’ grid-square, updating current and previous after this. So when it comes time to draw the gridsquare, in the correct order, it will then draw all characters who are standing on that square.
This in itself had a few issues, in that if a character was to stray too close to the bottom left / right of an isometric floor tile, their feet would be clipped by the tile in front, which is getting drawn after the character.
Also it highlighted another issue, once stairs were added in. When climbing stairs, the player, or zombies, would get drawn over by the floor above. Since I was drawing entire floors at once, the floor tiles behind the stairs would overwrite the player’s head as he climbed them.
Forgive the shitty graphics, but you get my point.
So obviously the rendering of an entire floor at a time was no good. It was at this stage I started the engine again in LWJGL, and this time I altered it slightly to render vertical slices. That is drawing in the same order, but instead drawing up to the maximum height of the map for each tile, like so…
The above assuming there were only two z levels to the map, of course…
This worked perfectly. Now when the characters were stood on the stairs, it would have already drawn the tiles behind in the above example when it came to draw the character, and so he would draw correctly and not be cut off.
Perfick.
Except not quite. See, we are trying to make Project Zomboid run on as many machines as possible, and thus it needs to be fast as hell. We’ve already got some quite costly line of sight stuff going on (with some crafty cheats in to speed it up) and plenty of pathfinding and whatnot, so it is imperative that the graphics render as fast as possible. We were finding it was struggling on lower end laptops and after profiling it became clear what the cause was.
In OpenGL, which LWJGL uses, in order to draw a texture to the screen you first need to ‘bind’ it. This is a relatively costly action, and it seemed to be a massive bottleneck in rendering the map.
Binding’s purpose is to set up OpenGL to use that texture’s ID, and thus all calls to vertex colouring, setting UV coordinates, and any other quad/tri drawing functions, will operate using that bound texture, and thus when you render quads you end up with them mapped using that texture.
I already had code inside my ‘bind’ function that checks if the texture was the last one that was bound, and if so ignores the call. However it was rarely using this optimization due to the fact that since the isometric draw order required us to draw ‘floor’, ‘wall’, ‘chair’, ‘zombie’, ‘floor’, ‘wall’, it was constantly having to bind, hundreds of time per frame, even when only drawing from a handful of iso sprite sheets.
Obviously this was a big problem, and cue solution #1
z-buffers!
To the uninitiated, a z-buffer, or depth buffer, is a texture that accompanies the screen, which is used primarily in 3D games. When you draw triangles to the screen, they will have a z distance from the camera for each pixel drawn to the screen, depending on the 3D orientation of the triangle relative to the camera. So the left of the triangle may be further away than the right, and so on. This depth information is stored per pixel in the z-buffer, which means that when subsequent triangles are drawn, their pixels will only be slapped on the screen if the z value in the buffer for that pixel is further away than the one they are placing.
Hence it allows you to draw triangles in any order you like, and yet they will appear to have been drawn back to front.
Of course this is mainly intended for 3D games, but I figured it’d work just as well for a 2D game. And indeed it did! Now I could just fake a z value for each gridsquare based on it’s x+y+z value, and batch up all the tile draw calls, and draw them sorted by the sprite sheet they were on.
Instead of having to bind the texture sometimes 3-4 times per gridsquare, I now only had to do it 3-4 times to draw the entire screen of tiles. Result!
Of course there is a big issue when using z-buffers, and that be alpha.
Transparency is a pain in the arse when it comes to z-buffers. The reason for this is the transparent texture may be drawn before stuff that’s supposed to be behind it.
Yup, what a pain in the tits.
So basically, in the left example, where things are sorted properly and the garden is drawn first, then Mr. T, then the window, all is good and proper.
In the second example, the garden is drawn first, then the window, and then Mr. T. So we get the garden properly ‘transparentised’ by the transparent window (technical term) and then when it comes to draw Mr. T after, it draws him fine in the gap where the window is open (since the values in the z-buffer are far away garden values) but he fails to draw at all in the upper part of the window since those pixels of the depth buffer have a value closer than Mr. T (i.e. the window) and so all the pixels of Mr. T are discarded.
So why was this a problem for Project Zomboid?
Well, since we have a isometric viewpoint, we need to be able to transparentise the walls to make the player visible through them if he wanders too close. Otherwise navigating tight interiors would be a nightmare, you’d get munched by unseen zombies. It would suck.
SO, we need transparent walls. What’s the problem? Well we’re drawing ALL walls at the same time, so that means that things we want to be visible through the transparent walls we need to draw first, before the walls. This means effectively walls need to be drawn last, because anything could feasibly be visible through a transparent wall.
But then we have zombies, and line of sight.
When something comes into view it appears. To make it suddenly pop on at full opacity would look horrible, so we have them fading on nicely. But then… uh oh. Transparency.
That means that we need to have them drawn after anything we could feasibly want to show through them while transparent. But… what happens if a zombie fades in when stood in front of a wall? We have to draw characters before walls otherwise they will be invisible when viewed through a transparent wall, which defeats the whole purpose of doing it.
And if the zombies are drawn before walls, then if the zombie fades in while in front of a wall, we won’t see the wall at all through the transparent zombie, but whatever is behind the wall. The floor, or perhaps grass. Resulting in a grassy silhouette of a zombie instead of a transparent one. GARGH!
So yeah. Screw the z-buffer. We needed another solution.
This one has a happier ending, since we were being grossly wasteful with our textures. Basically we had the walls / floors / doors etc on separate sprite sheets, and the sheets were 64×128 grids, a lot of which were wasted space. As so:
Sorry I’ve blurred these since they are out of the game and all.
Anyway clearly this is ridiculously wasteful, and we could massively reduce the amount of binds necessary by compressing as much as possible onto a single 1024 square texture.
So we worked on a sprite packing tool, which took a collection of sprite pages, or separate sprites, and packed them into as small a space as possible, creating a text file which contained the name of the sprite (based on the filename and index on the sheet) as well as the offset on the packed texture, as well as offsets required to simulate the transparent space of the original texture (since this was trimmed out in the sprite packer code)
We ended up with this:
Much much better. We’ve gotten every tile used in the map, including particle effects for tiles, blood splats. Everything. All on one 1024 square texture. We can now draw the entire map only doing a single bind! Of course, by the time the demo is released the chances that we’d be able to fit all map tiles onto a single texture is zero, but still.
Of course characters on tiles would still force a bind (and therefore 2, since it’d need to rebind the map texture) since they are stored on a separate packed texture. But you can’t have everything. We’re currently working on ways to mitigate this further. Even so it now runs on my mother’s graphic card challenged laptop pretty much perfectly, whereas before we were getting 5-10 FPS at best. Funky!
Now we’re working on a way to get the tile editor to work out quadrants of the map and generate packed textures for these map regions. This means that even if there are lots of textures used in a specific map cell, the chances are you’re only going to be drawing from one or two of them.
So there you go. Not sure how useful any of this is, but just thought I’d write about how it all went down. Perhaps there’s a much better way and I’m being a thicko. As I said, I’ve never done an iso engine before now.









Pretty awesome. I hope you keep this semi-technical blog post (or even more technical). Thanks.
Yeah I agree with Edswor. It’s really awesome to see how this whole thing comes together!
Well at least you got some sprites to display if the played receives some head injury
Very nice write-up. Can’t wait to see this game.
Texture Atlas FTW
Hey, nice article, I’m very grateful for tip on glBindTexture(), I was starting to have minor problems with performance and it would take me some time to figure it out, many thanks !
As usual, the solution was to make the art pipeline less ‘photoshopy’ and more technical.
(Hope you guys have a good artist that understand these changes… they are hard to find).
Great article, loved it. Please continue writing about development, is very interesting to know how you bypass development issues.
Thaks!
PS: Am I missing something, or in the Mr T – Window example, the garden (along with Mr T’s face) should not be drawn on the right?
Consider this: If a character appears behind a wall, then you want to draw Floor->Character->Wall (the wall of course is transparent, but that doesn’t mean that it’s not there. That is the picture on the left where the garden is the floor, Mr. T is the character, and the window is the transparent wall.
If you have a partially transparent zombie at the edge of your line of sight, and behind that zombie is a wall then you draw in the same order: Floor->Character->Wall, then the floor behind the wall is drawn, the parially transparent zombie is drawn on top of that, then the wall is drawn. Since the wall is behind the zombie, any pixels that would appear in the same area as the zombie are discarded. Thus when you are looking through the parially transparent zombie you see the floor behind the wall instead of the wall. In this case you look at teh picture on the right and the garden is still the floor, but this time Mr. T is the wall and the window is the zombie. The part of Mr. T that we see is the area of the wall around the zombie, and the area of the garden that we see in the upper pane of the window is the floor behind the wall made visible by the zombie(window) being drawn before the wall(Mr. T).
I hope I got all that right, and I hope that helps to clear it up.
Interesting for us who dont know anything about the technical stuff.
Hard too tell from your blurred down pics but lots of those textures look like simple color variations. Those could probably be done with some shader tricks or vertex coloring to save even more texture space.
I was just listening to some of the commentary from Left4Dead and that’s what they did to conserve space and textures n everything. Bare textures and a shader/tint overlay or something to change the colours and make a wide variety of cars. You’d be surprised at what kind of great info there is in those commentaries.
Oy- if you want some advice in isometrics- I can hook you up. Spent the past year obsessing about them working on tile sets- if anything I can hook you up with seamless textures (isometrics) and rework some of the ones your not happy with.
http://prophet-chaos.deviantart.com/ (i have some basic stuff up- I hid the really good ones)
Beekman
Awesome write up. Interesting approach to an isometric engine. Wondered if you had considered using dynamic sized objects (ie a table isn’t necessarily 2 tiles wide but could be somewhere in between)?
It’s good to see other people using iso in their games. I created an iso “engine” for a web-based game a few years back using php and AJAX.
Not sure if you’ve seen this tool or not but it really helps in making graphic tiles.
http://www.inet2inet.com
Game looks good so far, can’t wait to see more of it.
Alternatively, as you loop through your list of drawable objects in your main render thread, you could:
A) defer any that are transparent (you can obviously already detect this)
B) sort that list of deferred objects back to front using the knowledge that the majority of objects aren’t transparent (and thus the list won’t be enormous)
C) draw the deferred list
The performance hit for this should be negligible assuming you don’t have thousands of transparent objects and that the complexity of your sorting algorithm is similar to merge sort (eg, O(n log n)).
A technique that I commonly use is to render all like objects at once (though still deferring transparent objects). Eg, I’d render all tiles, then all walls, then all static scenery (eg, tables, chairs, etc), then all dynamic scenery (eg, trees that blow in the wind), then all characters. Then go back and render all transparent objects. You’d still have to deal with some state changes, but the vast majority of them would be culled out *and* you’d be less reliant on fully packed sprites (since you could switch out textures between those ‘type’ draws).
Thanks for the technical blog. I’m just getting into OpenGL and at this moment learning about textures. The practicalities of writing an engine and what operations are ‘expensive’ and ways around it is really good to hear about. You also make it such an easy read with your writing style. I’m bookmarking this page and hope to come back to read more interesting game development tales.
I unblurred the images and now I am making my own game with them
I am also a dick!
Not sure if he realized this, but all the wall and floor textures can be found in the game folder anyway. So, blurred or unblurred, anyone has full access to the material.
I still wanted to see some kind of object placement on the game, like a shelter and whatnot. Building a house would be cool too. :~
The graphics remind me a tad of the Original ‘The Sims’. Even that sidewalk texture looks familiar.
Problems like this are why I gave up trying to do any sort of 2D iso engine. It’s MUCH easier to just grab any 3D engine out there and set your camera to a 3/4 orthographic view. It gives you the same effect, and as a bonus you only have to model and animate your characters ONE TIME rather than 4 or 8 or whatever, depending on how many angles of movement you need.
Is it creepy that I understood every little technical aspect of this article?
I “did” an iso engine once. Done half of it (about to the part of the stairs in the article).
Never again. It still collects dust in my “Do not touch” folder.
Keep up the good work.
Very interesting take on the solutions.
However, I would have probably been more stubborn in giving up the z-buffer path. After thinking about the z-buffer problem, I came up with this:
An extra entity list is kept for objects that currently have a non-zero alpha component. If nothing but wall were transparent, then everything (all characters) would be drawn before the walls. However, the scenario where characters (zombies) could be transparent complicates this – nonetheless, following the conventions so far the characters with a non-zero alpha is put into this entity list with the walls. So in your scenario of the transparent zombie in front of a wall, the algorithm now looks like this:
nonTransparentEntities.drawWithAZBuffer();
tansparentEntities.drawInADifferentWay();
Now, all non transparent objects are drawn before the transparent ones in the first call with z-buffering, thus making sure they will be seen through the transparent objects like before. Except now, instead of using just z-buffering alone to draw the remaining transparent objects, we use z-buffering coupled with depth sorting making sure the most distant transparent objects are draw (if at all due to z-buffer checks) and the closer transparent objects are drawn after.
In short, the algorithm would handle the problem you had with z-buffering as follows:
Say we have a non transparent character (the player’s character) behind a wall, a transparent zombie, and a transparent wall in front of the player.
The player would be drawn first of course, then the what is left is 2 transparent objects which get sorted by depth (the wall will be drawn first in above case) and it is treated like any other object thus a z-buffer check is done. The wall is rendered over the player, transparent so the PC is still seen. THEN the zombie is drawn.
The depth sorting would have to be done in the code most likely, so I am not too sure how this stacks up in overhead compared to numerous glBindTexture’s.
When all else fails, do all of it! lol.
I just read meeper’s post (I didn’t take the time to read the comments, I should have).
He said it so much better, lol. I wish I could delete posts – mine’s too much of an eyesore compared to his.
@meeper I think the complexity would be even shorter than n log n since you can hit two birds with one stone by doing the depth sort/back to front while iterating through the main object list to find transparent objects i.e the deferment/sorting could be merged in one pass.
Assuming their data is stored as you suggest (and it would make sense for it to be), you’re absolutely right. I generally work with arbitrary 3D geometry where there isn’t a good way to sweep through your data without an early sort.
Hey thanks man for this great insight into programming your engine.
I don´t have no clue about programming such stuff, but as a graphic designer I don´t really have to
Anyways I find you explanations very interesting, thanks
Thanks for the insight to how you’re coding your game up. It’s fascinating to someone like me who is messing about with writing simple games (I’m re-learning after a long break).
Looking forward to your piece on generated textured. I remember messing about with this on the Amiga but I never got as far as writing any games.
Brilliant stuff!
Being someone who wants to become a game developer in the long run, this article was a fascinating read for me. It’s truly insightful, and I’m motivated to add your game to my list of future purchases for this alone.
Something else to remember is that you can use 3D textures with the layers acting as separate texture atlases (no mipmapping though). I’m still not clear on whether the number of layers always has to be a power of 2 (which might waste video memory), but it’s worth looking into.
This sounds like a problem that must have been solved before (isometric graphics engines).
Duplication of effort is definitely something you want to avoid as a small development team.
If you really want to compact the tiles you could change your packing tool to cut each tile in to 8×8 pixel chunks and then have it output a map of the tiles for the engine to read (you could also have it trim tiles that are purely transparent). It would take a little extra coding to read the sprite sheet, but it would give you a lot of extra space on it, allowing you to keep the number of binds very low. Also, if you’re working with a limited palette you can have it trim identical tiles to only a single copy of the tile.
Hey, LOVE this game. Got to 11 days and my boyfriend survived 18
lol. anyway I was wondering, (cause i’ve always wanted to make a game like this) what engine did you use to create Zomboid? I’d love to learn it
They used Java to write the code but the Engine was built by them from Java I believe. Yes you would need to learn Java to ever develop a game like this.
Makes me wonder how they managed to make those old games in c, like Tiberian Sun, RA2 and Fallouts 1&2.
The only question I have – is why arse around with all this when you can achieve the same with bog standard 3d pipeline and an orthographic projection matrix?
It sure is brutal, doing things the right way… or rather figuring out the hard way how they are supposed to be done. But then again, that is the beauty of developing your own engine, there is just so much to be learned, that you will take to heart and with you on your future projects. At this scale it is much more technical than simply managing supermassive BIN’s, and DLL’s, it is about thinking about how you can maximize the efficient flow of info that will be stored therein. Great work on figuring out that you should have all your sprites on one tile… I have been flirting with developing for chip’s as a hobby, and it is pretty mind blowing on what needs to be done to develop an authentic 8bit cart.
Anyhow, I heard about your misfortune recently, and I just wanted to stop by and show my support in wishing you the best. Good luck you guys, and I will surely keep my brain peeled.
The pictures have 404ed… could you please reupload them? Thanks.
Great write up, I’m currently creating my own iso engine and I was pleasantly surprised some one had gone through similar iterations as myself. Will be following! Hope you post some more.
I’m really interested in this guide, but all the pictures are broken links! Can this be fixed?
Fantastic post.Ne’er knew this, thank you for letting me know.
seems that the images don’t show anymore
too bad they were quite useful
nice post ^^
Will this article be repaired? It has been little over a month now.
Just purchased this game, got sucked in and stayed up way too late playing it for several hours, and was eager to read all the development posts on the blog. Disappointed to see that the images are broken; from the comments, it looks like it’s been that way at least a month and a half. It’d be wonderful if you could fix them!
I have some cool stuff to put in the game
1- Multiplayer.
2- Friendly human npc that could follow you, interact, eat, fight, etc.
3- Ability to heal Kate and she would be like idea nº 2.
4- Someone to put this in the game =D
Images are broken
I and my buddies have been reading by means of the fantastic important points on your site and just before lengthy came up with a horrible feeling I in no way expressed respect for the internet weblog owner for those strategies. My young guys were certainly passionate to see all of them and now have unquestionably been utilizing those issues. Numerous thanks for turning out to be nicely thoughtful and also for having particular crucial concerns millions of people are truly needing to be informed on. Our honest regret for not expressing gratitude to you earlier.
The links to your image on this page are not working. If you could get them working that’d be great!
Also I am very interested in more of a technical “How to” about how you guys made this.
If you could create a tutorial, and even charge for it. I would love to see it!
Image links are gone…
Hi, i feel that i noticed you visited my web site so i came to return the choose?.I am trying to to find issues to improve my web site!I guess its adequate to use some of your concepts!!
I second Harry TheKiNG’s observation. Please bring the images back.
p.s. Found this project after listening to the IndieGames.com podcast #20 today (catching up). Fun interview.
404 error on images =(
Hello, there
A good work you doing here 
So then I see these in other products without writing (or worst: writing, that is created by others) I will be sad =..( Or angry =^) Depends of situation 

I think it may be interested to you (developers), but if not – OkAY =D
The iso math 3D to 2D (from objects matrix to display wihout D3D or OGL):
XP = CX + (Y – X)
YP = CY + (((Y + X) / 2) – Z
There is:
- XP & YP = final 2D coordinates;
- CX & CY = center of the screen (depend of the resolution & coordinate sistem, suck as from 0,0 to 320,200, or -100,-100 to 100,100, as you want to do);
- X, Y, Z = object, player, NPS (any object or dot/line coordinates) in 3D matrix.
And I want to warn others: I just offer these formulas to developer, but not to others
P.S. I maybee can help with some math, if it’l be needed*
—————————-
* – Not only PZ developers, but please, don’t bother me with your scool homework =D
Hi PZ, Just wanted to say the podcast was awesome and some really good insight into how you guys work! It is highly appreciated what your doing for this game and the PZ community!! KEEP UP THE GOOD WORK!! I will be buying the game shortly after Uni in next few weeks, which hopefully the version 0.2.0 is out by then! I was going to say i’m dying to get it… but that defeats the object of even playing the game I suppose then lol
I know on the PODCAST the guys mentioned about not to talk about multiplayer on here as it won’t be until another year until it comes out, if at all! But I had a slight brainwave that might help you in the future of developing it. Although I apologise for my ignorance of game development… I have no idea, but throwing ideas at yourselves might allow you to make more sense of it how to go about doing it.
It was mentioned that the multiplayer would probably be done on a small scale of players on maps. So I was thinking about if its possible to create several servers which people can play the game and on the map you have a specific building where you can go and store all your stuff in the boxes in a particular safe room. But when you enter this specific room only you can enter it and no other player can on that game when your playing as you have the key to that room and if you die the stuff in that room is empty (to stop people purposely killing you for your safe house items, unless you leave the door open which is then fair game), except z’s can still enter meaning you can’t just hide, also you can only save when its safe to ‘sleep’ so you can’t just skip the apocalypse. Then when you leave the game the stuff in that room is saved on your computer. Then when you return to play you begin to play from one of those rooms in that particular building in the game with your stuff, but you might be on a different server with different players, just like when your running around on single player, new NPCs but you’ve got your stuff. In terms of playing with friends you could have your own private server and its just a case of the friends sorting out a time they wan’t to play themselves, if their fed up on there they can join a public server until friends arrive.
In terms of when playing your days add up normally, but the time line could depend on the average of player survival days, so if theres 3 of your surviving a month and 3 only 2 weeks, then the timeline will act is is it would in week 3 of single player perhaps or it could just depend on host survival and you choose host server timeline start point or something. And for those wanting to add up the days of survival when there not playing have to store enough food in the store house so you can’t just not play for a week and be well ahead, your time zone would be considerably less. i.e. not playing for a day equates to a day on the game, meaning you don’t have to store Asda in under your bed to survive. This also applies for boredom, etc, when you return the longer you’ve left your player, the worse state he/she (soon) will be in. Perhaps people wishing to wait on a gameplay could do so and have the choice of waiting in game play time (quite a wait, but not much choice) or flicking to another server which is near the waiting time.
Obviously this would be a huge task and I appreciate this will not happen anytime soon, but I just thought of providing some ideas that may solve some problems or you could work on… But like the PODCAST guys say the single player is definitely more important to have a solid foundation on that before multiplayer…. that is number 1 priority over multiplayer by a long shot… in my opinion…
hope this helps and sorry if this frustrates you with another bloody MP comment
Keep up the good work!
Is it just me or do the pics 404?, well, really interesting read anyway, thanks for sharing