8
\$\begingroup\$

I have an isometric map over which I place various images. Most images will fit over a single tile, but some images are slightly larger. For example, I have a bed of size 2x3 tiles.

This creates a problem when drawing my objects to the screen as I get some tiles erroneously overlapping other tiles.

The two solutions that I know of are either splitting the image into 1x1 tile segments or implementing my own draw order algorithm, for example by assigning each image a number. The image with number 1 is drawn first, then 2, 3 etc.

Does anyone have advice on what I should do?

It seems to me like splitting an isometric image is very non obvious. How do you decide which parts of the image are 'in' a particular tile? I can't afford to split up all of my images manually either.

The draw order algorithm seems like a nicer choice but I am not sure if it's going to be easy to implement. I can't solve, in my head, how to deal with situations whereby you change the index of one image, which causes a knock on effect to many other images. If anyone has an resources/tutorials on this I would be most grateful.

\$\endgroup\$

3 Answers 3

4
\$\begingroup\$

Divide your objects into 1×1×1 cubes, assigning to each cube a picture of the parts of the object that would physically be in that cube.

This is easy if you're starting with actual 3D objects and rendering them down to 2D. If you're drawing your objects directly in 2D (or if you have existing art that you need to split), it takes some manual effort. Fortunately, the split doesn't need to be exact, as long as you make sure that none of the image parts assigned to a given cube spill outside the hexagonal area that a solid 1×1×1 cube at that position would cover. It may help to make an overlay showing the outlines of each cube as an extra layer in your graphics editor.

Then you just assign a priority to each cube as p = x + y + z (assuming that all three coordinates increase towards the camera) and render the cubes in ascending order by priority.


Here's a quick example based on this image from Wikimedia Commons (by Phasmatinox / Allefant, used under the CC-By-SA 3.0 license):

        Isometric projection of an extended object divided into cubes

The chest of drawers in the picture takes up two tiles, and I've drawn the boundaries of those tiles (the red hexagons) on top of it. The parts of the image that lie inside each hexagon should be assigned to the corresponding tile; the part where the hexagons overlap can be assigned to either tile (or even to both, if you like), since the choice won't affect the end result.

Note that you may need to elaborate on this simple algorithm if you can have multiple objects in one tile, walls/floors between tiles, or objects (such as people) moving smoothly between tiles. Walls and floors are pretty simple to handle: they can be drawn at any point after the content of the tile they're in front of (from the camera viewpoint) and before the tile they're behind. This is also a useful rule of thumb for objects moving between tiles; treat them as you would a wall between those tiles.

As for multiple objects in a tile, sometimes those are pretty simple: for instance, if you had a book lying on top of the chest in the picture, it should obviously be drawn after the surface it lies on. However, things can get more complicated if you, say, have objects that people can sit on. For example, if a person was sitting on a bench, facing away from the camera, then the person's body should be drawn after the bench but their legs (which are behind the bench from the camera) need to be drawn before it. One solution, in this case, would be to split the legs of a sitting person into a separate component with its own position (either in the adjacent tile, or between the tiles).

\$\endgroup\$
3
\$\begingroup\$

What you need is called a painter's algorithm.

You want to draw the furthest tile first, including any doodads or characters on it.

Then draw the next closest, and repeat until finished.

Your objects that span more than one tile must have an anchor/origin point declared. This is the grid cell that when drawn, will result in your larger object also being drawn. The origin point is chosen so that it is drawn after all cells the object bleeds into are drawn first.

Based on your question, your origin point will be the tile that is closest to the camera. (If you are using square, rather than diamond-shaped tiles, either the bottom-left or bottom-right tile should be chosen.)

Example code for a square-grid. Alter the loop direction for your diamond-grid.

for(int y = 0; y < GridHeight; ++y) {
    for(int x = GridWidth - 1; x > -1; --x) {
        MapCell cell = getMapCell(x,y);
        DrawTerrain(cell);
        if(cell.IsDoodadOrigin){
            DrawDoodad(cell);
        }
        if(cell.IsCharacterOrigin){
            DrawCharacter(cell);
        }
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ I'm not seeing how this can work? Imagine a 2x3 bed surrounded completely by boxes. When iterating through the cells, by the time you reach the 'origin' of the larger object you would have already drawn boxes that should be behind and in front of the bed. \$\endgroup\$
    – Wozza
    Commented Dec 5, 2012 at 23:12
  • \$\begingroup\$ You are correct, this technique will work for square grids. It will also work for diagonal grids that use square doodads/characters. It will not work for the irregular 2x3 shape on a diagonal grid. \$\endgroup\$
    – Jim
    Commented Dec 6, 2012 at 1:27
1
\$\begingroup\$

It may help you to partition your objects by type or by altitude. For example, landscape (floors, walls) should be drawn before objects (beds). Also, because of the isometric perspective, lower-altitude tiles should be drawn before higher-altitude ones.

Also, if you go with the index-numbering (Z-ordering, really), I recommend using gaps between numbers -- don't make your floors 1 and your bed 2. Use something like floors = 10 and beds = 20 or 100 or something else, so you can "insert" stuff in the middle without domino-incrementing everything else.

\$\endgroup\$
3
  • \$\begingroup\$ I plan on doing what you suggest in the first paragraph. The problem that I'm having is that the objects of a similar type are overlapping incorrectly. e.g. my bed overlaps the bed-side table. I was suggesting that I give each instance of an image a different number though, not giving all beds the number 20, for example? \$\endgroup\$ Commented Dec 5, 2012 at 2:11
  • \$\begingroup\$ It depends. What if you have two beds next to each other? One way people often get around this is to add objects in the order they should be drawn, but I don't know if that will help you. \$\endgroup\$
    – ashes999
    Commented Dec 5, 2012 at 2:13
  • 1
    \$\begingroup\$ If two beds are next to each other, then bed that has the higher y value should be drawn above the other. If they are the same y coordinate, then the one with the highest x value (assuming top of the map is (0,0). \$\endgroup\$ Commented Dec 5, 2012 at 2:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .