------------------------------------------------------------------------------------------------------
RPGs in Qbasic Tutorial
Issue #2: May, 1997

These tutorials can be found at:

http://www.geocities.com/SiliconValley/Pines/1732/tut.htm

They may be distributed unmodifed, as long as no fee is charged for
their distribution.
The author assumes no responsibility for the use of this tutorial.
------------------------------------------------------------------------------------------------------

THE 2D TILE BASED ENGINE
--------------------------------------------->>>>>

2.0 Overview
------------------------------->>
        
        This issue has some of the good stuff! We will be discussing how to
create a 2d tile-based engine for RPGs (role playing games).  Some Qbasic
source code will be included.  Anyways, let's get to it!

2.1 What is a tile-based engine?
------------------------------->>
        
        If you are familliar with tile-based engines and 2d graphics then you
can skip this section.  It is just an overview for those who are new to RPG
programming or those with little experience.
        Basically, a tile-based engine is usually an overhead view (or bird's
eye view) of the areas which the characters will traverse through.  In a
typical RPG, this includes towns, forests, mountains, dungeons, etc.  It is
called a tile-based engine because all objects are located in 'tiles' on the
map, including characters.  When the player moves, they move from the tile
which they are standing on, to the next tile, and this is how they move
about.  A tile engine can be simple or complicated, it all depends on the RPG
and the skills of the programmer(s).  Some examples of tile-based games would
be the Dragon Warrior(tm) series, the Phantasy Star(tm) series and the very
popular Final Fantasy(tm) series.  All of these games use tile maps to move
the characters around.
        Since 3d gaming has become the latest craze, tile based games are not
as popular as they used to be, however, if it is executed well, a tile-based
game can still be very good, and fun to play.

2.2 Getting Started.  How do I begin?
------------------------------->>

        Programming a basic tile based engine, is fairly simple.  The first
thing you want to do is create a variable to hold your map, and notate what
kind of terrain each number in this map will represent:

Here is an example:
        0 = Grass
        1 = Forest
        2 = Desert
        3 = Dirt path
        4 = Bridge
        5 = Water
        6 = Rock/Mountain
        7 = Wall

        Now, this is very simple.  Notice that only seven tiles are used,
this will make the map update really quick, so we can use simple ways to
make the map scroll.  You might also notice that the first 5 tiles (0 - 4)
are walkable tiles (maning the character can move through these) while the
last three (5 - 7) are impassable tiles (meaning the character cannot move
through these).  This kind of notation makes it much easier to program a
'walk' routine which will figure out if the tile the player wishes to move to
is walkable or not.
        
2.3 Setting up the 2d engine.
------------------------------->>
        
        Now, we will set up the engine:

<<----- Qbasic code.  Cut starting with the next line...
DIM SHARED Map%(0 TO 15, 0 TO 9)        ' This is the 2d array which will be
                                        ' used to hold the map data.

FOR Y = 0 TO 9                          ' This little routine reads the DATA
  FOR X = 0 TO 15                       ' into the map array.  We will use
    READ Map%(X, Y)                     ' this DATA to draw the map and test
  NEXT X                                ' where the player can and can't
NEXT Y                                  ' move.

' Below is the data for a boring little level which I have created.  You can
' change it around in any way you want.
DATA 5,7,7,7,7,7,7,6,6,7,7,7,7,7,7,5  
DATA 5,1,1,0,0,0,0,3,3,0,0,0,0,1,1,5  
DATA 5,5,5,5,5,5,5,4,4,5,5,5,5,5,5,5  
DATA 6,6,6,6,0,0,0,3,3,0,0,0,1,6,6,6 
DATA 6,6,1,1,1,1,0,3,3,0,1,1,1,1,6,6 
DATA 2,6,6,1,1,1,1,3,3,0,1,1,1,1,6,6 
DATA 2,6,6,1,1,1,1,3,3,1,1,1,1,1,1,6 
DATA 2,2,6,6,1,1,1,3,3,1,1,1,1,1,0,5  
DATA 2,2,2,6,6,1,1,3,3,1,1,1,0,0,5,5  
DATA 2,2,6,6,6,5,5,5,5,5,5,5,5,5,5,5
>>----- End cutting with the line above.

        Okay.  Now that we have set up the engine, we can begin to create
the graphics which we will use for the tiles as well as a routine to draw
the graphics on the screen.

2.4 Graphics.
------------------------------->>

        There are many ways to draw graphics.  But if you are a beginning
programmer, the easiest way is to use Qbasic's graphics primitives (ie LINE,
CIRCLE, PSET) to draw them to the screen, GET them, and save them to arrays.
Here's how this is done:
        Be aware, this step is not neccesary if you are capable of producing
graphics in different ways.  This is just a simple step for beginners.  You
will still nead to load your graphics into the arrays however.

<<----- Qbasic code.  Cut starting with the next line...
SCREEN 13                               ' We will be using screen mode 13h
                                        ' which has a resolution of 320x200
                                        ' and can display up to 256 colours.

DIM SHARED Grass%(210)                  ' These are the arrays we need to
DIM SHARED Forest%(210)                 ' dimension in order to hold all of
DIM SHARED Desert%(210)                 ' our graphics.
DIM SHARED Dirt%(210)
DIM SHARED Bridge%(210)
DIM SHARED Water%(210)
DIM SHARED Rock%(210)
DIM SHARED Wall%(210)

LINE (0, 0)-(19, 19), 2, BF             ' This is our grass tile.
LINE (5, 5)-(3, 3), 120
LINE (5, 5)-(7, 3), 120
LINE (15, 15)-(13, 13), 120
LINE (15, 15)-(17, 13), 120

GET (0, 0)-(19, 19), Grass%             ' This puts what we have just drawn
                                        ' into the Grass% array.

LINE (0, 0)-(19, 19), 0, BF             ' This command clears what we have
                                        ' just drawn so that we may draw our
                                        ' next tile.

LINE (0, 0)-(19, 19), 120, BF           ' This is our forest tile.
LINE (0, 10)-(10, 5), 2
LINE (10, 5)-(20, 10), 2

GET (0, 0)-(19, 19), Forest%            ' This puts what we have just drawn
                                        ' into the Forest% array.

LINE (0, 0)-(19, 19), 0, BF             ' This command clears what we have
                                        ' just drawn so that we may draw our
                                        ' next tile.

LINE (0, 0)-(19, 19), 43, BF            ' This is our desert tile.
RANDOMIZE TIMER                         ' This is just a simple way of
FOR I = 1 TO 10                         ' drawing 10 random dots on our tile.
  X = INT(RND * 19)
  Y = INT(RND * 19)
  PSET (X, Y), 6
NEXT I

GET (0, 0)-(19, 19), Desert%            ' This puts what we have just drawn
                                        ' into the Desert% array.

LINE (0, 0)-(19, 19), 0, BF             ' This command clears what we have
                                        ' just drawn so that we may draw our
                                        ' next tile.

LINE (0, 0)-(19, 19), 113, BF           ' This is our dirt path tile.
CIRCLE (9, 9), 8, 6
PAINT (9, 9), 6, 6

GET (0, 0)-(19, 19), Dirt%              ' This puts what we have just drawn
                                        ' into the Dirt% array.

LINE (0, 0)-(19, 19), 0, BF             ' This command clears what we have
                                        ' just drawn so that we may draw our
                                        ' next tile.

LINE (0, 0)-(19, 9), 6, BF              ' This is our bridge tile.
LINE (0, 10)-(19, 19), 113, BF

GET (0, 0)-(19, 19), Bridge%            ' This puts what we have just drawn
                                        ' into the Bridge% array.

LINE (0, 0)-(19, 19), 0, BF             ' This command clears what we have
                                        ' just drawn so that we may draw our
                                        ' next tile.

LINE (0, 0)-(19, 19), 105, BF           ' This is our water tile.
LINE (0, 10)-(10, 5), 9
LINE (10, 5)-(20, 10), 9

GET (0, 0)-(19, 19), Water%             ' This puts what we have just drawn
                                        ' into the Water% array.

LINE (0, 0)-(19, 19), 0, BF             ' This command clears what we have
                                        ' just drawn so that we may draw our
                                        ' next tile.

LINE (0, 0)-(19, 19), 2, BF             ' This is our rock/mountain tile.
LINE (1, 17)-(18, 17), 185
LINE (18, 17)-(9, 2), 185
LINE (9, 2)-(1, 17), 185
PAINT (9, 9), 185, 185

GET (0, 0)-(19, 19), Rock%              ' This puts what we have just drawn
                                        ' into the Rock% array.

LINE (0, 0)-(19, 19), 0, BF             ' This command clears what we have
                                        ' just drawn so that we may draw our
                                        ' next tile.

LINE (0, 0)-(19, 9), 23, BF             ' This is our wall tile.
LINE (0, 10)-(19, 19), 25, BF

GET (0, 0)-(19, 19), Wall%              ' This puts what we have just drawn
                                        ' into the Wall% array.

LINE (0, 0)-(19, 19), 0, BF             ' This command clears what we have
                                        ' just drawn.
>>----- End cutting with the line above.

2.5 Putting the graphics on the screen.
------------------------------->>

        Well, now that we have drawn all of the graphics, we must create a
routine to put all of them on the screen according to our map.  Here's how
this is done:
        Note: You may use this routine every time you need to redraw the
whole ma[ screen, since it should do it fairly fast.  This routine can also
be used as a part of a real simple scrolling routine when your map exceeds
the size of the screen.
        Note: You must be in SCREEN 13 before you can put the graphics that
we just drew on the screen.  If you cut and paste all of the code together
in the order it appears, this should be fine.

<<----- Qbasic code.  Cut starting with the next line...
' Basically, this code will check what number is at every position in the
' map and put the right graphic, in the right spot on the screen according
' to what number is associated with what graphic.
FOR Y = 0 TO 9
  FOR X = 0 TO 15
    IF Map%(X, Y) = 0 THEN
        PUT (X * 20, Y * 20), Grass%, PSET
      ELSEIF Map%(X, Y) = 1 THEN
        PUT (X * 20, Y * 20), Forest%, PSET
      ELSEIF Map%(X, Y) = 2 THEN
        PUT (X * 20, Y * 20), Desert%, PSET
      ELSEIF Map%(X, Y) = 3 THEN
        PUT (X * 20, Y * 20), Dirt%, PSET
      ELSEIF Map%(X, Y) = 4 THEN
        PUT (X * 20, Y * 20), Bridge%, PSET
      ELSEIF Map%(X, Y) = 5 THEN
        PUT (X * 20, Y * 20), Water%, PSET
      ELSEIF Map%(X, Y) = 6 THEN
        PUT (X * 20, Y * 20), Rock%, PSET
      ELSEIF Map%(X, Y) = 7 THEN
        PUT (X * 20, Y * 20), Wall%, PSET
    END IF
  NEXT X
NEXT Y
>>----- End cutting with the line above.

2.6 Putting a character on the screen.
------------------------------->>
        
        Well, now we have our map set up, or graphics drawn, and our
graphics put to the screen.  So what do we need now? That's right, the
character! For the purposes of keeping this tutorial simple, I will only
use one graphic for the character, and no animations.  But you should be
able to figure out how things like that work anyway.
        Note: Again, this little section assumes that you are already in
SCREEN 13.  This section works with the rest of the code in this tutorial.

<<----- Qbasic code.  Cut starting with the next line...
DIM SHARED PlayerX%, PlayerY%           ' We must create global variables    
                                        ' for the character's X and Y
                                        ' position, relative to the map.

PlayerX% = 7                            ' We give our player any ol' starting
PlayerY% = 8                            ' position.  Just make sure they are
                                        ' not standing on an impassable tile.

Moved = 1
DO
  SELECT CASE INKEY$
  CASE CHR$(0) + CHR$(77)               ' Code for right arrow key.
    IF Map%(PlayerX% + 1, PlayerY%) < 5 THEN
      GOSUB DrawBackGround
      PlayerX% = PlayerX% + 1
      Moved = 1
    END IF
  CASE CHR$(0) + CHR$(75)               ' Code for left arrow key.
    IF Map%(PlayerX% - 1, PlayerY%) < 5 THEN
      GOSUB DrawBackGround
      PlayerX% = PlayerX% - 1
      Moved = 1
    END IF
  CASE CHR$(0) + CHR$(80)               ' Code for down arrow key.
    IF Map%(PlayerX%, PlayerY% + 1) < 5 THEN
      GOSUB DrawBackGround
      PlayerY% = PlayerY% + 1
      Moved = 1
    END IF
  CASE CHR$(0) + CHR$(72)               ' Code for up arrow key.
    IF Map%(PlayerX%, PlayerY% - 1) < 5 THEN
      GOSUB DrawBackGround
      PlayerY% = PlayerY% - 1
      Moved = 1
    END IF
  CASE CHR$(27)                         ' Code for Esc key.
    Quit = 1
  END SELECT
 
  IF Moved = 1 THEN
    X% = PlayerX% * 20                  ' This little routine draws our
    Y% = PlayerY% * 20                  ' character in the right position
    CIRCLE (X% + 9, Y% + 9), 9, 40      ' on the screen.
    PAINT (X% + 9, Y% + 9), 40, 40
    CIRCLE (X% + 5, Y% + 6), 3, 31
    PAINT (X% + 5, Y% + 6), 31, 31
    CIRCLE (X% + 13, Y% + 6), 3, 31
    PAINT (X% + 13, Y% + 6), 31, 31
    CIRCLE (X% + 5, Y% + 6), 0, 16
    CIRCLE (X% + 13, Y% + 6), 0, 16
    CIRCLE (X% + 4, Y% + 17), 2, 4
    PAINT (X% + 4, Y% + 17), 4, 4
    CIRCLE (X% + 14, Y% + 17), 2, 4
    PAINT (X% + 14, Y% + 17), 4, 4
    CIRCLE (X% + 9, Y% + 9), 2, 16
    PAINT (X% + 9, Y% + 9), 16, 16
    Moved = 0
  END IF
   
LOOP UNTIL Quit = 1

SCREEN 0: WIDTH 80
PRINT "Thank you for trying this demo."
SYSTEM
 
DrawBackGround:
  X = PlayerX%
  Y = PlayerY%
  IF Map%(X, Y) = 0 THEN
      PUT (X * 20, Y * 20), Grass%, PSET
    ELSEIF Map%(X, Y) = 1 THEN
      PUT (X * 20, Y * 20), Forest%, PSET
    ELSEIF Map%(X, Y) = 2 THEN
      PUT (X * 20, Y * 20), Desert%, PSET
    ELSEIF Map%(X, Y) = 3 THEN
      PUT (X * 20, Y * 20), Dirt%, PSET
    ELSEIF Map%(X, Y) = 4 THEN
      PUT (X * 20, Y * 20), Bridge%, PSET
    ELSEIF Map%(X, Y) = 5 THEN
      PUT (X * 20, Y * 20), Water%, PSET
    ELSEIF Map%(X, Y) = 6 THEN
      PUT (X * 20, Y * 20), Rock%, PSET
    ELSEIF Map%(X, Y) = 7 THEN
      PUT (X * 20, Y * 20), Wall%, PSET
  END IF
  RETURN
>>----- End cutting with the line above.

2.7 End Notes
------------------------------->>

        Well, that's about it for now.  Remember, what I've shown you here is
just a very basic demo.  But even with this one, you can create a really good
RPG, all you really need to do is draw some better graphics, and create more
maps so that the player can walk from map to map. (Hint, when the player goes
past the screen on the map, put the enxt map into the array and use the
routine to draw it to the screen)  Next month, look for an enemy encounter
engine tutorial.  It should go well with this 2d engine.

-----------------------------------------------------------------------------------------------------------------

Next month:
Enemy encounter tutorial, with Qbasic source!

Author: DarkDread

Thanks: Well, none really, except to all those Qbasic coders out there who keep
it alive!
------------------------------------------------------------------------------------------------------------------


    Source: geocities.com/gasoline86