Sie sind auf Seite 1von 11

DarkBASIC Professional

QuickStart Tutorial 6 Huge Dungeons

DarkBASIC Professional QuickStart Tutorial


All rights reserved. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photo-copying, recording, or by any information storage and retrieval system, without written permission from Dark Basic Software Limited, except for the inclusion of brief quotations in a review. Copyright 2003 by Dark Basic Software Limited

Warning and Disclaimer


This tutorial is designed to provide information about DarkBASIC Professional. Every effort has been made to make this tutorial as complete and as accurate as possible, but no warranty or fitness is implied. The information is provided on an as is basis. The author(s) and Dark Basic Software Limited shall have neither liability nor responsibility to any person or entity with respect to any loss or damage arising from the information contained in this document or from the use of the programs or source code that may accompany it.

Copyright 2003 Dark Basic Software Limited / Thomas Grtler / Color Arts Version 1.0 5th Feb 2003 Page 1 of 11

DarkBASIC Professional

QuickStart Tutorial 6 Huge Dungeons

Huge Dungeons
Creating huge dungeons/mazes in DarkBASIC Professional
Who hasnt ever dreamed about creating your own Role Playing Game? In this tutorial well cover building one of the most important aspects of any RPG a nice huge dungeon to explore!

Making the Map


There are many methods available that you can use to build your original map, however the method were going to use is one found at http://roguelikedevelopment.org (original author: Mike Anderson). To start with we need a map data file. You can create one of these with Notepad or the tool included with this tutorial (Dungeon Creator). The map format is very straight forward and consists of ASCII characters representing various parts of your dungeon (doors, walls, stairs, etc). Here you can see an example of the map data:
........#:::::::::::#.###:##:#......##########.....#:#:#.#:::::# ........#:::::::::::#...#:##:#..###.#:::##:::#.....###:#.#:::::# ........#######D#########:##:#..#:####:####:##########:######D## #############:::::::::::#:##:#..#::::::::::::::::::::::::::::::# #:::::::::::#:::::::::::#:####..#:#############D#####:#####D#### #:::::::::::#:::::::::::#:#.....###....#:::::::::::##:#..#:::::# #:::::::::::#:::::::::::#:#....#######.#:::::::::::##:#..#:::::# #:::::::::::#:::::::::::#:#....#:::::###:::::::::::##:#..#:::::# #:::::::::::#:::::::::::#:######:::::#:#:::::::::::####..#:::::# #:::::::::::#:::::::::::D:##:::D:::::D:D:::::::::::#.....#:::::# #:::::::::::D:::::::::::#:######:::::#:#:::::::::::###...####D## #::::::::O::#:::::::::::#:#....#:::::###:::::::::::#:#......#:#. #:::::::::::###S#########:#....#######.#:::::::::::D:#......#:#. #:::::::::::##:::::######:#........#####:::::::::::#:#......#:#. #:::::::::::##:::::#:##:#:#........#:::D:::::::::::###......###. ##############:::::D:##:::#........#####:::::::::::#............ .............#:::::#:##:#:#.....###.#######D########............ .............#:::::######:#.....#:#.#:::::::::::#.......#######. ........############....#:#.....#:#.#:::::::::::#########:::::#. ........#:::#...........#:#.....#:#.#:::::::::::#:::::::#:::::#.

This section of our ASCII File contains all the values of the map. The # character denotes a wall the : is the floor and periods/full stops are unused or blank space. This map format has a nice advantage for when we start to optimize our code later because we dont have to show all the objects of the world only the ones which are used.

Stairs
Before we can start walking around in our dungeon we need a few other things first. The ability to go up and down levels is important so well add 2 new characters to our ASCII map above, a O and a U for up and down stairs respectively. As you can start to see Copyright 2003 Dark Basic Software Limited / Thomas Grtler / Color Arts Version 1.0 5th Feb 2003 Page 2 of 11

DarkBASIC Professional

QuickStart Tutorial 6 Huge Dungeons

you could use different characters to signify any element you wish (monsters starting locations, wells, traps, etc). To put this into practise here is some code to initialise DarkBASIC with:
set display mode 800,600,16 sync on sync rate 0 hide mouse backcolor=rgb(0,0,0) backdrop on color backdrop backcolor cls

That is our initialization over with all we are doing is setting a resolution, making the program run as fast as possible (sync rate 0), hiding the mouse and colouring the background. We have put our background colour into a separate variable (backcolor) so we can change it easily later and also use it for the fog effect. Although we recommend that you always use the resolution settings found in the IDE rather than using set display mode in your programs this command has been left in for backward compatibility. The final CLS in the code is just to solve a problem with flickering and GeForce cards.
DBV1 to DBPRO

Define Values
The next part of our program will define the size of the map. In this example we are using a 512x512 dimension map which will show you a really huge dungeon! We set the dimensions for the map array so it is possible to keep the whole map in memory at once in this code we should how to use a string array for learning purposes:
mapsize=512 dim map$(mapsize,mapsize) maxcubes=16 cubesize=200 collisionstep=int(cubesize/10)

It is perfectly possible to use smaller maps but we wanted this demonstration to be more impressive you could also use a dungeon larger than 512 for a truly big level. The maxcubes variable contains the row/column number of the viewable objects around the player. In our case its set to 16 you can imagine this as a small 16x16 unit map surrounding the player at any one time: Copyright 2003 Dark Basic Software Limited / Thomas Grtler / Color Arts Version 1.0 5th Feb 2003 Page 3 of 11

DarkBASIC Professional
................ .............### .............#:: .............#:: .............#:: ...###########:: ...#:::::::::::: ...#:::::::::::: ...#::::S :::::: ...#:::::::::::: ...#:::::::::::: ...#:::::::::::: ...#:::::::::::: ...#:::::::::::: ...#######:::::: ..........#::::: ..........###D## ................ ................ ................

QuickStart Tutorial 6 Huge Dungeons

The player is located in the middle of this mini-map. The units around the player are the ones well have to display onscreen. That means that in this example we have to show 256 objects at once (16x16). However we stated earlier the units in the map displayed as a period/full stop are blank and therefore do not need to be shown so we will hide them. This hiding will speed up our program and the display speed because we wont have to draw 3072 faces each frame. DarkBASIC has another tool in its arsenal when it comes to getting more speed out of large scenes back face culling. This is an optimisation command which will perform the complicated task of sorting out all of the faces which cant actually be seen by the player (i.e. walls behind them). The value cubesize will set the size (in 3D units) of the wall blocks. The final variable collisionstep holds a special value we will use later when we create a simple math based collision system.

Enter the Darkness


Dungeons are dank and dark places, full of hidden traps and treasures. We need to get the player into the right mood and atmosphere so lets set up some environment values:
fog fog fog set on color backcolor distance (int(maxcubes)*cubesize) camera range 1,(maxcubes*cubesize)

Here weve set the fog and the camera viewing distance to be calculated from the values entered before.

Reading in the Map data file


Copyright 2003 Dark Basic Software Limited / Thomas Grtler / Color Arts Version 1.0 5th Feb 2003 Page 4 of 11

DarkBASIC Professional

QuickStart Tutorial 6 Huge Dungeons

We already know that the data for our dungeon is stored in ASCII format and that you can create this file yourself with Notepad or the supplied utility. What we need to do now however is actually load that data file and extract the values from it into an array. The array has been defined already as map$(mapsize, mapsize) which means we have created an array in memory which is mapsize * mapsize big. That is enough for the complete map data in our text file. Our mapfile should be an ASCII file without carriage return or line feed characters (click Save as ASCII map in Dungeon Creator to do this). One you understand how this system works it is very easy to change the loader so it can handle all sorts of ASCII files. The loading routine is a function. We can use a function here because Arrays in DarkBASIC are treated as global (i.e. they can be accessed from the main program or from functions). It also keeps our code neat and organised.
function loadmap(filename$,size) open to read 1,filename$ for y=1 to size for x=1 to size read byte 1,tmp map$(x,y)=chr$(tmp) next x next y close file 1 endfunction

The function expects two parameters. The first is the name of the map data file (filename$) and the second is the size of the map in units (this is the mapsize value from before). First we open the file for reading and then we read the whole file in byte by byte. This byte (its a numeric value between 0 and 255) is then converted to a character using the CHR$ command. When everything has finished what we end up with is the corresponding character in our array. When it completes the whole map data will be in memory. With the function complete we can now load our map with the command:
loadmap(dungeon.map, mapsize)

From ASCII to 3D
With the map data now held in memory we can set about turning it into a 3D scene. First we need to load up some textures for use on the floor, ceiling and walls:
load image "wall2.jpg",1 load image "ground.jpg",2 load image "wall.jpg",3

Copyright 2003 Dark Basic Software Limited / Thomas Grtler / Color Arts Version 1.0 5th Feb 2003 Page 5 of 11

DarkBASIC Professional

QuickStart Tutorial 6 Huge Dungeons

With the textures loaded we can create the 3D objects themselves using the primitives that are part of DarkBASIC cubes for the walls and plain objects for the floor and ceiling:
` Wall for i=1 to maxcubes*maxcubes make object cube 100+i,cubesize texture object 100+i,1 next i ` Floor for i=1 to maxcubes*maxcubes make object plain 10000+i,cubesize,cubesize rotate object 10000+i,90,0,0 texture object 10000+i,2 next i ` Ceiling for i=1 to maxcubes*maxcubes make object plain 20000+i,cubesize,cubesize rotate object 20000+i,270,0,0 texture object 20000+i,3 next i

This will literally create enough cubes and plains for our entire map. Now its time for a little more dungeon atmosphere and some lights:
set ambient light 30 make light 1 make light 2 set point light 1,0,0,0 set spot light 2,45,90 color light 2,RGB(252,216,141) color light 1,RGB(236,182,100) color light 0,RGB(0,0,0)

What we also need is the right starting point within the current map. So we search the map data for the O and calculate the value for the camera position:
for z=1 to mapsize for x=1 to mapsize if map$(x,z)="O" cx=x*cubesize cz=z*cubesize endif next x next z position camera cx,0,cz

Main Loop
Copyright 2003 Dark Basic Software Limited / Thomas Grtler / Color Arts Version 1.0 5th Feb 2003 Page 6 of 11

DarkBASIC Professional

QuickStart Tutorial 6 Huge Dungeons

Now we are near our main loop. As we need a small and easy collision system we need another two variables which contain the last camera position.
oldpositionx#=camera position x() oldpositionz#=camera position z()

As we are creating an easy version of a dungeon we dont need to save the last Y coordinate of the camera because we have just one height for everything. In this example we just need the X and Z axis coordinate. Now to the difficult part of this tutorial - our main loop! First here is some pseudo code so youll understand what we are trying to do: DO 1. Move the camera 2. Calculate the current map view 3. Check for wall collision 4. Render the current map 5. Animate lights SYNC LOOP Lets begin with the camera movement. In this example the player uses the mouse to move through the dungeon. A left mouse click will make them go forward and a right one will go backwards. Moving the mouse will rotate the player. The easiest code for this is as follows:
if mouseclick()=1 then move camera maxcubes if mouseclick()=2 then move camera maxcubes*(-1) ry#=wrapvalue(ry#+mousemovex()) rotate camera 0,ry#,0

With this the player can move around (only on a single height but thats what we wanted) Now well try to calculate the current map location (the small 16x16 units part as mentioned previously) Here is the code:
cx#=int(camera position x()/cubesize)-int(maxcubes/2) cz#=int(camera position z()/cubesize)-int(maxcubes/2) tx#=camera position x() tz#=camera position z() zzz=0

Copyright 2003 Dark Basic Software Limited / Thomas Grtler / Color Arts Version 1.0 5th Feb 2003 Page 7 of 11

DarkBASIC Professional

QuickStart Tutorial 6 Huge Dungeons

for zz=1 to maxcubes for xx=1 to maxcubes zzz=zzz+1 curposx=int(cx#)+xx curposz=int(cz#)+zz if curposx<=1 then curposx=1 if curposx>=mapsize then curposx=mapsize if curposz<=1 then curposz=1 if curposz>=mapsize then curposz=mapsize ` Wand if map$(int(curposx),int(curposz))="#" or map$(int(curposx),int(curposz))="S" show object 100+zzz position object 100+zzz,curposx*cubesize,0.0,curposz*cubesize else hide object 100+zzz endif ` Boden if map$(int(curposx),int(curposz))=":" or map$(int(curposx),int(curposz))="D" or map$(int(curposx),int(curposz))="S" or map$(int(curposx),int(curposz))="T" show object 10000+zzz position object 10000+zzz,curposx*cubesize,(cubesize/2)*(1),curposz*cubesize else hide object 10000+zzz endif ` Decke if map$(int(curposx),int(curposz))=":" or map$(int(curposx),int(curposz))="D" or map$(int(curposx),int(curposz))="S" or map$(int(curposx),int(curposz))="T" show object 20000+zzz position object 20000+zzz,curposx*cubesize,(cubesize/2),curposz*cubesize else hide object 20000+zzz endif next xx# next yy# oldpositionx#=camera position x() oldpositionz#=camera position z()

Wow! Thats quite a lot of code but we will explain it for you. The code calculates the current coordinates of the player, the current camera position and the units in the map array where we located. To get the right values we must divide the current camera position through the cubesize and then we decrement this value with the half of the value from the current viewable map (maxcubes).

Copyright 2003 Dark Basic Software Limited / Thomas Grtler / Color Arts Version 1.0 5th Feb 2003 Page 8 of 11

DarkBASIC Professional

QuickStart Tutorial 6 Huge Dungeons

This value is exactly the middle of the small map (16x16) the player is in. We have to test that these map values are not out of the array bounds (not <0 and not >512). The next two loops, xx# and yy# calculate the current scene with all objects which are in the small map (16x16) around the player. We check the map$ array and if we find e.g. a # character then we know to show a cube there else we hide it. As we know the x and y coordinates of the cubes its easy to get their positions in the viewable small map.
position object 100+zzz,curposx*cubesize,0.0,curposz*cubesize

The objects position is x*cubesize,0,z*cubesize. We save the current camera coordinates so we can set it back if there is a collision. Ah yes collision! Well need a simple math collision system. To get this in we change the wall showing code a little bit to the following:
` Wall if map$(int(curposx),int(curposz))="#" or map$(int(curposx),int(curposz))="S" show object 100+zzz position object 100+zzz,curposx*cubesize,0.0,curposz*cubesize ` Collision detection if map$(int(curposx),int(curposz))="#" if tx#>=((curposx*cubesize)-(cubesize/2))-collisionstep and tx#<=((curposx*cubesize)+(cubesize/2))+collisionstep and tz#>=((curposz*cubesize)-(cubesize/2))-collisionstep and tz#<=((curposz*cubesize)+(cubesize/2))+collisionstep position camera oldpositionx#,camera position y(),oldpositionz# oldpositionx#=camera position x() oldpositionz#=camera position z() endif endif else hide object 100+zzz endif

Again, this looks quite complicated but its pretty easy to understand. As we only use a single height we can think of a from the top down viewed 2D map (as seen in the example at the beginning). We create a simple test if the players x and z position is within a square (we use squares here because the walls are simple cubes.) If thats true then we change the camera position to its old value (otherwise youd walk through the walls!). This is just a check if the player is in a certain area or not. To get a better collision we have defined our collisionstep variable and its time to use it - we add this value to all sides of our square so the test square are is a bit bigger then the cube. This has the end result of much better camera collision because were stopping a bit before the wall and not slap bang against it (so close we can put our nose on it!). This Copyright 2003 Dark Basic Software Limited / Thomas Grtler / Color Arts Version 1.0 5th Feb 2003 Page 9 of 11

DarkBASIC Professional

QuickStart Tutorial 6 Huge Dungeons

simply looks and plays better. If you want to see the basic collision without the bounding box then change collisionstep to zero. Last but not least we add some effects to our lights.
position light 1,camera position x(),camera position y(),camera position z() position light 2,camera position x(),camera position y(),camera position z() color light 1,RGB(200+int(rnd(50)-25),120,60) rotate light 2,camera angle x(),camera angle y(),camera angle z()

This gives us the effect of a flickering torch with a flashlight before the player. That was the main loop. So not as difficult as you perhaps thought eh?

Here a small screenshot how itll look running:

Hint! Check out the directories included with the tutorial code and also the Dungeon Creator Tool. To create Maps with it just click save as ascii map and you should also have a look at the size of the map so you define the right one.

Copyright 2003 Dark Basic Software Limited / Thomas Grtler / Color Arts Version 1.0 5th Feb 2003 Page 10 of 11

DarkBASIC Professional
Suggestions

QuickStart Tutorial 6 Huge Dungeons

In order to use less memory why not try using an integer/byte array to save the map into. You will have to deal with ASCII translation of the values but it will take up less RAM. Add in some error checking for example if the map file exists or not. Try adding in some higher and lower floors and stairs leading from one to the other. Why not replace the basic math collision with some sliding collision? Add a radar map (which could be grabbed from the Map Tool) Add some enemies! Use different ASCII characters to denote different wall textures.

Copyright 2003 Dark Basic Software Limited / Thomas Grtler / Color Arts Version 1.0 5th Feb 2003 Page 11 of 11