VBfx / Tile tutorial / Step 4

Drawing units

Since we have both, a units map and a units array, we can decide which one to use for drawing. Let's start out with the easier one, drawing from the array. Later on we'll switch to the map, however both techniques are good to know. Drawing is always the slowest thing in your engine so you should avoid drawing objects that aren't even on the screen. However the following DrawUnits function is for test purpose only so I left out that check.

Draw function

The draw function does nothing more than going through all units and draw them at their position. Since the unit coordinates are in pixels already we can simpy subtract the camera position to get the final screen coordinates of each unit. Why subtract? When moving the camera down you see the units (and the map) moving up. You can think of the camera being the drawing offset for everything. Well there's only one thing we have to watch out for:

When drawing a picture we'd go from Unit.X and Unit.Y but this would set the origin to the top-left corner of the picture. In most games the origin is at bottom-center where the unit stands on the map. In the sample code I used OffsetX and OffsetY set to .W / 2 and .H to correct the origin's position. In your game you might want to use individual offsets for each unit instead. Note that this does not affect any position at all, it's only a display correction. By increasing the Y-offset you could therefore make the unit jump without affecting it's position.

In the following code I marked two lines we'll discuss right afterwards:

Public Sub Draw()
    Dim A as Long
    Dim OffsetX as Long
    Dim OffsetY as Long
    Dim DrawX as Long
    Dim DrawY as Long
    For A = 1 To UnitCount
        With Unit( A )
            'Get offset position (bottom-center)
            OffsetX = .W / 2 - TileSize / 2
            OffsetY = .H - TileSize / 2
            'Get final draw position
            DrawX = .X - OffsetX - Camera.X
            DrawY = .Y - OffsetY - Camera.Y
            'Draw mask
            BitBlt Camera.FrontDC, _
                DrawX, DrawY, _
                .W, .H, _
                Bitmap( .Bitmap ).Mask.DC, _
                0, ( .H * .Direction ), _
vbSrcPaint 'Draw picture BitBlt Camera.FrontDC, _ DrawX, DrawY, _ .W, .H, _ Bitmap( .Bitmap ).Picture.DC, _
                0, ( .H * .Direction ), _
vbSrcAnd End With Next End Sub

Code discussion

In the first part the function calculates the offset of the unit. As mentioned before you could use individual offsets for each unit instead. This offset will correct the image position when drawing so the unit position becomes the origin. This is quite useful when performing collision checks because we can just deal with the origin and don't have to care about the unit size. Actually we're handling the units as points but that's not a problem because we're using a collision grid instead of unit-to-unit collision checks.

The second part calculates the final drawing position regarding the offset and camera offset. Both is subtracted from the units real position.

The final BitBlt calls should be clear except the marked lines we'll discuss now.


As mentioned before we're using a 4-directions system. In the unit's picture we therefore have to include images for each direction. A unit picture might look something like this:

Sample unit

The images are in the same order as the directions: up, right, down, left. Now when drawing the picture we just have to draw from the correct row which we get my multiplicating the unit's direction by it's height. If the unit looks down (direction 2) and the unit size is 35 pixel we get 2 x 35 = 70 and that's exactly the offset of the 3rd row. This is quite the same as we did when animating tiles but instead of filling the lines with animation frames we fill the rows with directions. This is so we can combine both techniques later.


As already said the draw function above is for test purpose only. What it does is nothing more than draw all units in the order they were added to the units array. Since we don't do any Z-buffer checks this will result in units drawn in front of other units and such. However this isn't so important because later we'll use the units map for drawing and this will automatically solve the Z-buffer problem so don't care about it yet.