Warning

You're browsing the old v2.x documentation. This version is no longer maintained. Click here to go the v3.x documentation.

# Step 3.2.3: Drawing or erasing a piece

To be able move a piece on the screen, we need a routine that draws it and another one that erases it off of the screen. But since these two operations are very similar, we can code them into a single procedure. I'll explain how.

The following operations are involved in drawing a shape:

• Iterate through all bits in the shape
• Calculate Screen RAM and Color RAM address for each bit that is set
• If the address is in the visible area:
• `POKE` an inverse space to the screen address if we're drawing, a normal space if we're erasing
• `POKE` the appropriate color code to the color address if we're drawing

The only task that's relatively difficult is calculating the RAM addresses where we want to `POKE`. Traditionally we would do this by multiplying the row count with 40 and adding the column count, but as you've seen earlier, multiplication is an expensive operation that we cannot afford. For this reason we will be using lookup tables: we will look up the start address of the row where we want to draw. To get the final address, we'll first add the piece's X position, then add an offset that corresponds the position of the block within the shape: Here is the function that we will call for drawing or erasing:

```REM -- Draw or erase the current shape on screen at the given position
REM -- draw! > 0 means draw, draw! = 0 means erase
PROC draw_shape(shape, x!, y!, color!, draw!)
REM -- This is the memory address where we can start drawing
REM -- Everything before is invisible
CONST VISIBLE_AREA_START = 1199
REM -- Iterate through all bits in the shape
FOR bit_pos! = 0 TO 15
REM -- Calculate where to draw
REM -- Only draw if it's in the visible area
REM -- If bit in shape is set
IF shape & LSHIFT(CAST(1), bit_pos!) <> 0 THEN
IF draw! = 0 THEN char! = 32 ELSE char! = 160
REM -- Draw char
REM -- Set color
REM -- Add the distance between screen RAM and Color RAM
REM -- To get color address without offsets calculating again
ENDIF
ENDIF
NEXT
REM -- The address in Screen RAM for each row on stage
DATA screen_address[] = 1036, 1076, 1116, 1156, 1196, 1236, 1276, 1316, 1356, 1396, 1436, 1476, ~
1516, 1556, 1596, 1636, 1676, 1716, 1756, 1796, 1836, 1876, 1916, 1956, 1996
REM -- For each bit in the shape there is a matching offset where the
REM -- character should be drawn relative to the top left of the shape.
REM -- This offset, added to the screen address will give us where to
REM -- plot a character.
REM -- Note that we're going backwards as Bit #0 is the bottom right position
DATA block_offset![] = 123, 122, 121, 120, 83, 82, 81, 80, 43, 42, 41, 40, 3, 2, 1, 0
ENDPROC```

Did you notice the `IF … ENDIF` block? It's a convenient alternative to the classic `IF … THEN` statement if you want to avoid writing a very long line. Read more here.

The other thing above that might be new for you is the `CAST()` function. It is used to convert a value from one type to another. This is called explicit type conversion. But why do we have to cast the number 1? The answer lies in the way XC=BASIC works when it compiles a numeric literal. If the literal is between 0 and 255, it will treat it as a byte. Now, `LSHIFT` (without the `!`) expects an integer as its first argument, so we need to cast the number to an integer first.

There are more operations above that work on different types, take this line for example:

`addr = screen_addr + block_offset![bit_pos!]`

Because `screen_addr` is an integer and `block_offset!` is a byte, the compiler will auto-cast the smaller type (byte) to the larger one (integer). This is called implicit type conversion.

Well done, we can now draw a piece on screen! We can reuse the same routine to draw the preview window, that is, the next piece:

```REM -- Draw the piece preview
REM -- Effectively uses the draw_shape routine above
PROC draw_preview
REM -- Clear the preview area
FOR i! = 0 TO 4 : TEXTAT 33, 19 + i!, "    " : NEXT
REM -- Draw the shape in the appropriate color
CALL draw_shape(\nxt_shape, 21, 19, \colors![\nxt_shape_no!], 1)
ENDPROC```

Fantastic! There are only a few routines left. Follow me to the next page where we'll code what happens when a piece is locked.