VBfx / Tile tutorial / Z-buffer

Introduction

Drawing the units just in the order they are in the array results in many display errors. To solve this problem we have to add a Z-buffer that sorts the units so they get drawn in the correct order. Since this is a 2D engine Z-sorting happens in Y direction so a unit at 10, 8 is displayed behind a unit at 10, 12.

Z-buffering

Lucky we are that we already have the units map where every unit is registered at. Now since the units map is a tile-based map we can't use if for the Z-buffer but we can use this map to get only the units that are on the screen. We add those indices to a list and then perform a Z-sort on this list so we get the indices in the correct drawing order. When done we can simply draw all units contained in this list.

The code

To keep code clear I moved the code for drawing a unit into a new function called DrawUnit, you can look-up the complete code in the sample project. The only thing that changed was the DrawUnits function, we'll discuss this in code right now. I cutted the function into logical parts:

Public Sub DrawUnits()
    Dim A as Long
    Dim Done as Boolean
    
    Dim X as Long
    Dim Y as Long
    
    Dim Index as Long
    
    Dim UnitListCount as Long
    Dim UnitList() as Long

UnitList will hold the indices to sort. Each index stands for a unit in this list.

    'Calculate start index
    Index = Int( ( Camera.Y / TileSize ) ) * Map.W + Int( ( Camera.X / TileSize ) )
    UnitListCount = -1
    
    'Draw the map
    For Y = 0 To Camera.TilesY
        For X = 0 To Camera.TilesX
            'Check index
            If Index > ( Map.W * Map.H ) Then: Exit For

Instead of exiting the function we just continue after the loops now. This is because there's still code to execute after the loops this time.

            'Get unit index
            If Map.Units( Index ) > 0 Then
                'Allocate memory
                UnitListCount = UnitListCount + 1
                ReDim Preserve UnitList( UnitListCount )
                
                'Add unit index
                UnitList( UnitListCount ) = Map.Units( Index )
            End If

When there's a unit (index > 0) at the current position add that index to the UnitList.

            'Next tile
            Index = Index + 1
        Next
        
        'Get next line start
        Index = Index + Map.W - Camera.TilesX - 1
    Next

Nothing to explain here...

    'Z-sort the list
    While Not Done
        Done = True
        
        For A = 0 To UnitListCount - 1
            'If unit is in front of next unit
            If Unit( UnitList( A ) ).Y > Unit( UnitList( A + 1 ) ).Y Then
                'Swap items
                Index = UnitList( A )
                UnitList( A ) = UnitList( A + 1 )
                UnitList( A + 1 ) = Index
                
                'Check again
                Done = False
            End If
        Next
    Wend

This is called a bubble sort because it's the easiest way of sorting. The code just goes through all list items, compares a certain value and if necessary swaps those items in the list. This is repeated until all items are in the correct order. Quite slow but fast enough for a tile engine and easy to implement.

Here we performed a bubble sort to order the units by their Y property. Note again the deepness is done in Y direction in 2D top-down games!

    'Now draw the sorted list
    For A = 0 To UnitListCount
        DrawUnit UnitList( A )
    Next
End Sub

Now that the list is sorted we can simply draw all the units.

Conclusion

We're done already, now your engine supports a nice little Z-buffer for the units (and only for the units!). Download the sample code and move your unit around others to check if it's working.

Navigation