VBfx / Tile tutorial / Step 2

Draw function

As in the basic tutorial I'll show you the whole code first and discuss each part later. So let's have a look at the new Draw function:

Public Sub Draw()
    Dim X as Long
    Dim Y as Long
    
    Dim Index as Long
    Dim TileIndex as Long
    
    Dim TempX as Single
    Dim TempY as Single
    
    With Map
        'Get map position
        TempX = ( Camera.X / TileSize )
        TempY = ( Camera.Y / TileSize )
        
        'Calculate index of this positon
        Index = Int( TempY ) * .w + Int( TempX )
        
        'Calculate smooth scrolling
        TempX = TempX - Int( TempX )
        TempY = TempY - Int( TempY )
        
        '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 Sub
                
                'Get tile index
                TileIndex = .Data( Index )
                
                'Draw tile
                BitBlt Camera.FrontDC, _
                    ( X - TempX ) * TileSize, ( Y - TempY ) * TileSize, _
                    TileSize, TileSize, _
                    Bitmap( Tile( TileIndex ).Bitmap ).Picture.DC, _
                    Tile( TileIndex ).ActFrame * TileSize, 0, _
                    vbSrcCopy
                
                'Next tile
                Index = Index + 1
            Next
            
            'Get next line start
            Index = Index + .w - Camera.TilesX - 1
        Next
    End With
End Sub

You can see lots of math now and the function has grown a little. Well you know, don't be scared it's just code.

In detail

Public Sub Draw()
    Dim X as Long
    Dim Y as Long
    
    Dim Index as Long
    Dim TileIndex as Long
    
    Dim TempX as Single
    Dim TempY as Single

The newly declared values TempX and TempY will be used to get the tile-based position first and later they will represent the pixel-offset the camera has (to the next exact tile position). We'll get right to this.

    With Map
        'Get map position
        TempX = ( Camera.X / TileSize )
        TempY = ( Camera.Y / TileSize )

Since the camera position is in pixels now we have to divide it by the TileSize to get the tile-based position. Note that this returns floating-point numbers, we'll need this in the next line:

        'Calculate index of this positon
        Index = Int( TempY ) * .w + Int( TempX )

By rounding the position we get the tile-based position in the map. Example: The camera position is (34, 20) in pixel, this is near (32, 16) where the next exact tile coordinates are. TempX would be 2.125 and TileY would be 1.25. Now take the integer values and you get (2, 1) which is exactly the next valid map position. The result we transform from 2D coordinates to the 1D index position and that's where we have to start drawing from.

        'Calculate offset
        TempX = TempX - Int( TempX )
        TempY = TempY - Int( TempY )

Now that we have the index position we don't care about the map position anymore so we subtract it from the original TempX and TempY. The remaining part is everything after the point, so 0.125 and 0.25 in our example. Note that these are still tile-based positions and we have to multiplicate them by the TileSize to get back the offset in pixels!

        '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 Sub
                
                'Get tile index
                TileIndex = .Data( Index )

Until here everything stayed as it was before. Nope. The loops now go from 0 to Camera.TilesX and Camera.TilesY, before they went from 0 to (Camera.TilesX - 1) and (Camera.TilesY - 1). So why did that change? Imagine moving the whole display 8 pixel (half a tile) to the left. The last draw function exactly filled up the screen, so there would be 8 untouched pixels at the very right of the screen. Therefore we have to draw 1 extra line in both directions, X and Y, to still fill the whole screen. This is also where the index check comes handy, without it we'd produce a overflow whenever the camera reaches the very bottom of the map (because of the non-existing position where both extra lines are crossing).

                'Draw tile
                BitBlt Camera.FrontDC, _
                    ( X - TempX ) * TileSize, ( Y - TempY ) * TileSize, _
TileSize, TileSize, _ Bitmap( Tile( TileIndex ).Bitmap ).Picture.DC, _ Tile( TileIndex ).ActFrame * TileSize, 0, _ vbSrcCopy

This is already the last part that changes, as usual I marked the changed line for you. What we do here is subtracting the offset from the current (tile-based) position and multiplicate the result by the TileSize to get this position in pixels. Hope you're getting familiar with these transformations.

                'Next tile
                Index = Index + 1
            Next
            
            'Get next line start
            Index = Index + .w - Camera.TilesX - 1
        Next
    End With
End Sub

Conclusion

Well that's it, the function now handles pixel-based camera positions! Feel free to extend the other tutorials with smooth scrolling if you like, shouldn't bee too hard now. As always you can download the sample project here:

Navigation