A scrolling engine is the foundation for most RPGs. There are three types ofscrolling: tile-by-tile, pixel-by-tile-by-pixel-by-tile, and pixel-by-pixel. Tile-by-tile isscrolling by moving the screen one tile over, then drawing the tiles in the empty space. It iscommon in QBasic RPGs because it is so simple, but it looks very choppy. Pixel-by-tile meansscrolling tile-by-tile one pixel at a time, like Dragon Warrior style RPGs. Pixel-by-pixelscrolling is scrolling only one pixel per key press. This is very complicated because it canleave different sections of tiles on the screen. It is what is used in more advanced RPGs likeChrono Trigger. Usually, when people talk about pixel-by-pixel scrolling, they meanpixel-by-tile scrolling.

For this tutorial I will use the following variables:

DIM SHARED xscreensize AS INTEGER 'tiles from your character to edge of screen

DIM SHARED yscreensize AS INTEGER 'tiles from your character to edge of screen

DIM SHARED xmapsize AS INTEGER 'map x-size

DIM SHARED ymapsize AS INTEGER 'map y-size

DIM SHARED x AS INTEGER 'x-coordinate of character

DIM SHARED y AS INTEGER 'y-coordinate of character

DIM SHARED Tiles(0,0) AS INTEGER 'array holding tiles

DIM SHARED Map(0,0) AS INTEGER 'array holding msp

DIM SHARED Char(0) AS INTEGER 'array holding character tile

DIM SHARED Mask(0) AS INTEGER 'array holding character mask

DIM SHARED Undertile(0) AS INTEGER 'array holding tile under character

DIM SHARED Scroll(32001) AS INTEGER 'used to scroll screen

Note: I am only using one character frame and one mask for simplicity.

Now we begin. To reduce to amount of math needed, we will make

xscreen = xscreensize * 2 + 1

yscreen = yscreensize * 2 + 1

These are the total number of tiles display on the screen in eachdirection. You use that equation because it's the number of tiles on bothsides of the character, plus the one the character is on.

I'm not going to explain how to load the map and tiles. You can to that byyourself. Just make sure the tiles are GETted, and the map is stored withthe **y-coordinates** in the first dimesion and the x's in the second.

Before we start scrolling, we need to draw the screen. This is most easilydone by:

x = xscreensize + 1y = yscreensize + 1FOR x1 = 0 TO xscreen - 1

FOR y1 = 0 TO yscreen -1

x2 = x + x1 - xscreensize

y2 = y + y1 - yscreensize

IF x2 < 1 THEN x2 = x2 + xmapsize

IF x2 > xmapsize THEN x2 = x2 - xmapsize

IF y2 < 1 THEN y2 = y2 + ymapsize

IF y2 > ymapsize THEN y2 = y2 - ymapsize

PUT (16 * x1, 16 * y1), Tiles(0, Map(y2, x2)), PSET

NEXT

NEXT

Here's what that means. X and Y are set to be in the top-left corner so thatthey are as close to the corner as possible without any wrap-around. TheFOR...NEXT loops go from left to right and top to bottom across thescreen. The x2 and y2 = lines determine which part of the map toshow. Those euqations are used because x and y are the xscreensize + 1 andyscreensize + 1 tiles from the top-left corner shown. Subtractingx- and y-screensize gives you the first tiles, and adding x1 and y1 give youthe tile shown. The next four lines just check for wrap-around (going fromone edge of the map to the other). If the tile is too far up, down, left, orright to fit on the map, it wraps around to the other side. The PUT lineshows the correct tile in the correct position. 16 * x1 and y1 are usedto tile the tiles correctly, since 16 is the x and y tilesize. Map(y2, x2)is the tile number to use, and Tiles(0, tilenumber) is the actual tile.

Now here's the actual scrolling engine:

DO

GET(16 * xscreensize, 16 * yscreensize)-(16 * xscreensize + 15, 16 * yscreensize + 15), Undertile

PUT(16 * xscreensize, 16 * yscreensize), Mask, AND

PUT(16 * xscreensize, 16 * yscreensize), Char, OR

This GETs the tile under the character and shows the character using amasking technique. 16 * x- and y-screensize is used because it's the x- andy-screensize row and column,and 16 is the tilesize.

DO

a$ = INKEY$

LOOP UNTIL a$ <> ""

Waits for a keypress...

IF a$ = CHR$(27) THEN END

CHR$(27) is Esc.

PUT(16 * xscreensize, 16 * yscreensize), Undertile, PSET

Shows what's under the character.

IF a$ = CHR$(0) + "H" THEN

CHR$(0) + "H" is the up arrow.

y = y - 1

IF y < 1 THEN y = y + ymapsize

Changes the y coord and checks for wrap-around.

GET (0, 0)-(16 * xscreen - 1, 16 * yscreen - 17), scroll

PUT (0, 16), scroll, PSET

GETs the whole screen, except the bottom row into the array and moves it downone tile. 16 * xscreen - 1 is used because there are xscreen columns,starting at 0 (so from 0 to xscreen-1). Adding 15 (because the tilesize is16, so it goes for 15 tiles plus the one it starts at) to 16 * (xscreen - 1)is the same as 16 * xscreen - 1. The y part is the same, except you excludeone tile, so you subtract 16 more.

y2 = y - yscreensize

IF y2 < 1 THEN y2 = y2 + ymapsize

FOR x1 = 0 TO xscreen - 1

x2 = x + x1 - xscreensize

IF x2 < 1 THEN x2 = x2 + xmapsize

IF x2 > xmapsize THEN x2 = x2 - xmapsize

PUT (16 * x1, 0), Tiles(0, Map(y2, x2)), PSET

NEXT

END IF

This is just like the original screen-drawing, but with only one row of tilesbegin shown. And that's it for one direction. The rest are the same, with afew different numbers.

IF a$ = CHR$(0) + "P" THEN

y = y + 1

IF y > ymapsize THEN y = y - ymapsize

GET (0, 16)-(16 * xscreen - 1, 16 * yscreen - 1), scroll

PUT (0, 0), scroll, PSET

y2 = y + yscreensize

IF y2 > ymapsize THEN y2 = y2 - ymapsize

FOR x1 = 0 TO xscreen - 1

x2 = x + x1 - xscreensize

IF x2 < 1 THEN x2 = x2 + xmapsize

IF x2 > xmapsize THEN x2 = x2 - xmapsize

PUT (16 * x1, 16 * yscreen - 16),Tiles(0, Map(y2, x2)),PSET

NEXT

END IF

Down. The only differences are that y increases, it GET everything but the

IF a$ = CHR$(0) + "K" THEN

x = x - 1

IF x < 1 THEN x = x + xmapsize

GET (0, 0)-(16 * xscreen - 17, 16 * yscreen - 1), scroll

PUT (16, 0), scroll, PSET

x2 = x - xscreensize

IF x2 < 1 THEN x2 = x2 + xmapsize

FOR y1 = 0 TO yscreen - 1

y2 = y + y1 - yscreensize

IF y2 < 1 THEN y2 = y2 + ymapsize

IF y2 > ymapsize THEN y2 = y2 - ymapsize

PUT (0, 16 * y1), Tiles(0, Map(y2, x2)), PSET

NEXT

END IF

Left. This one's different because it changes x instead of y. But,everything is the same as moving up, except the math is switched between xand y.

IF a$ = CHR$(0) + "M" THEN

x = x + 1

IF x > xmapsize THEN x = x - xmapsize

GET (16, 0)-(16 * xscreen - 1, 16 * yscreen - 1), scroll

PUT (0, 0), scroll, PSET

x2 = x + xscreensize

IF x2 > xmapsize THEN x2 = x2 - xmapsize

FOR y1 = 0 TO yscreen - 1

y2 = y + y1 - yscreensize

IF y2 < 1 THEN y2 = y2 + ymapsize

IF y2 > ymapsize THEN y2 = y2 - ymapsize

PUT (16*xscreen-16,16*y1),Tiles(0,Map(y2,x+xscreensize)),PSET

NEXT

END IF

Right. Same as down, but switching x and y.

LOOP

Remember, this is the simplist form of tile-by-tile scrolling. I did notinclude things like entering buildings, detecting whether you can move intoyour new location (you shouldn't be able to walk into walls), battles, orthings that happen when you don't move, like moving water or NPCs. All ofthese things should be put in an RPG.