Well, now I have sorted all the bugs out of the new computer and am fully in control of it (famous last words) here is the first part of the tutorial.
Before we continue, just to recap for everyone:
The first part of the Final Fantasy game is all about the introduction and setting up the game ready to play.
The second part of the tutorial will deal with map movement and interaction within towns.
The third and last tutorial will deal with the battle screen and menu system.
Also note that even tho the game is complete in its sections, and you can certainly use any of it to make your own game, I will be adding a few little things to the final listing to improve the overall feel and quality of the program, but please don’t wait for me to do that, just dive right in and start playing about with the code.
The obvious thing with using just 2D is that unlike 3D you have to put in a LOT of hours in designing graphics and animations etc, so always bair this in mind when changing anything within this program.
Now... To begin.
PART 1. The Game set-up
As we always do, the first thing is to set up the computer, so:
sync on
sync rate 12
color backdrop 0
hide mouse
The above lines do the following :
sync on....Set the redraw to manual. This means that YOU are responsible to refresh the screen within your program using the SYNC command.
sync rate 12....This sets the redraw rate of the machine to 12 frames per second (FPS)
color backdrop 0.....Colours the background to black.
hide mouse....Hides the mouse from view.
Ok after that, we need to start to load in the media that will be used for the game. I start with the music and sound effects first.
LOAD MUSIC "intro.mid",1
LOAD MUSIC "ff1world.mid",2
LOAD SOUND "close.wav",1
SET SOUND VOLUME 1,100
PLAY MUSIC 1
The music is loaded into a “bank�. In this case we are using Midi music because:
1. Most people have very good music cards nowadays and the Midi normally will sound just fine.
2. It is a LOT smaller than Mp3/Wav/Mod etc files, and this is a downloadable tutorial which needs to be smallish in size.
3. The Midi tends to invoke a certain atmosphere of nostalgia. Which is just right for our FF game style.
After we have loaded the music in, we do the same for the sound effect. Note that the sound bank is 1 and the “intro.mid� is also 1. Don’t worry tho, as the banks are different and are assigned to either MUSIC or to SOUND...so bank 1 of the music will not overwrite bank 1 of the sound or visa versa.
We next set the volume of the sound effect to its loudest, which is 100. This means that you should be able to hear it over the music playing. Finally, we just play the music in bank 1.
Ok...so far so good. Now we load in the credits/title screens.
There are many ways to do this, but in programming there really is no right way to do anything. Whatever you want to do...provided it works, is acceptable. So we will just use the default screen to display the screens as I merely wanted to show a picture..pause..show another picture..etc.
Here is the routine to do it:
load bitmap "dsp2rpg.bmp",0
wait 6000
load bitmap "dblogo.bmp",0
wait 6000
Note that both screens are the same size... 640 by 480.
This is important if you are doing the above as if you load in a big screen and then load in a smaller screen you will still be able to see the outer edge of the first screen underneath the second one. Try it and you will see what I mean.
load bitmap "tl.bmp",0
load bitmap "textintro2.bmp",1
suspend for mouse
wait 1
After the 6 second pause we load in the simple title screen, with a bit of writing on it from me, and then we load in another screen...but this one is not to the default screen (which is screen 0) it is to a “hidden� screen...in this case screen 1.
Whats on it???? Well the hidden screen is being loaded with a screen full of text that we will use later on in the program.
One of the things I see on the forum is newcomers always asking how to put text on top of a sprite...you cant do that as such, but you can grab printed text as a sprite. This is what we are going to do later with the hidden text.
Anyway... We then wait for a mouse button to be clicked and... Yes, you guessed it...We load in the working background for the introduction.
This is a nice water/sky picture:
load bitmap "waterback.bmp",0
However, I want to use the picture not just for background, but to control how the text I am going to scroll will appear/disappear. So I grab a section of the picture (from the top to about half-way) using this command:
GET IMAGE 2,0,0,640,255
That will store the sky part of the picture in an image bank (just like the sound and music banks). The image bank is 2. The 0,0 means the top left co-ords of the screen and the 640,255 is the far bottom right corner co-ords.
Moving ever onwards, we load in all the rest of the graphics:
load image "parchmentfin.bmp",96
load image "alltext1.bmp",97
load image "mouse.bmp",100
load image "hannanoia.bmp",103
load image "garanak.bmp",104
load image "kyacca.bmp",105
load image "marinda.bmp",106
load image "toceda.bmp",107
load image "lishom.bmp",108
load image "xmark.bmp",109
load image "g1.bmp",110
I am not going to explain every single one to you..you have to learn by doing you know,
..but suffice to say that the pictures are loaded in to their own banks..96 to 110.
spx=700:y=500:wo=103:wi=108:six=-200:noc=0:click=0
We now set up a few variables. These are used in the program to control aspects of it, such as picking your team members etc.
sprite 101,0,0,101
See if you can figure out what I’m doing here. Ok...maybe not..
If you look at the sprite command you will see I am placing a sprite (101) on the screen but it does not have a picture/image assigned to it. Its using an EMPTY bank. Why would I want to do that?
Well Dark basic is a great language, but it does have some annoying quirks. One of them is that it has no sprite priority (it does in Dark basic Pro..but not in Classic) so for your mouse sprite to always be ON TOP of all the other sprites you MUST put the sprites on the screen (or off the screen) IN THE ORDER you want them to be displayed.
Sprite 101 is used further down the program as you icon on the world map, but if I just introduced it later on, then the mouse would be underneath it, so this is one way to stop that from happening by using no picture and putting it on screen now.
sprite 97,0,500,97
sprite 1000,0,0,2
These two sprites put (in order):
The scroll text.
The grabbed sky.
On to the screen ready for the next routine.
repeat
sprite 97,30,y,97
dec y
sync
until y<80
This is a repeat/until loop. You could have used a for/next loop (or anything really) but I wanted to use a repeat/until one..So there!
What it does it to move sprite 97 UPWARDS by taking 1 away from the Y variable. This simply scrolls the text upwards but here’s the fun thing..As the text reaches the horizon on the sky it fades (as the horizon is white and so is the text) and then disappears underneath the other sprite. It looks much better than having the text scroll all the way from top to bottom.
delete sprite 97
delete sprite 1000
sync rate 30
When Y is less than 80 the loop ends and we delete both of the sprites.
We also reset the refresh rate to 30 to speed up the game.
I used a low rate at the start so that I did not have to put a delay into the scroll loop. There are problems with using sync rates to control sprite speed, but in this instance for its purpose, it works. I would NOT recommend you do that tho, its better to use a delay in a loop.
y=-480
for t=1 to 60
SPRITE 96,0,y,96
inc y,8
sync
next t
play sound 1
Ok...now we bring the nice scroll down on to the screen which will let you pick your team members.
The same trick of movement is used as I did with the text..but this is from the top of the screen towards the bottom as we add 1 to Y 8 times (Inc=ADD Y,8= add 8 to Y).
repeat
mx=MOUSEX()
my=MOUSEY()
if my>240 then my=240
if mx>600 then mx=600
SPRITE 1,mx,my,100
ucm=MOUSECLICK()
if ucm=1 then gosub clickingon
if lis=1 then gosub lisinfo
if toc=1 then gosub tocinfo
if mar=1 then gosub marinfo
if kya=1 then gosub kyainfo
if gar=1 then gosub garinfo
sync
until noc=2
This little lot is the main loop. Its another repeat/until loop which will terminate when NOC=2 (NOC=Number Of Characters).
So whats it do?
First we make MX and MY = to wherever the mouse pointer is. Even tho the mouse is hidden it still can be tracked. We also make sure that IF the mouse pointer is going to go off the edge of the area I want it to be on, then it cannot. That’s what these two lines mean:
if my>240 then my=240
if mx>600 then mx=600
SPRITE 1,mx,my,100....We put a sprite with a NEW pointer over the top of the hidden pointer.
ucm=MOUSECLICK()....UCM (User Clicking Mouse) is assigned to your mouse buttons.
if ucm=1 then gosub clickingon....If you click the mouse button JUMP to a section of code under a label called “Clickingon�. This is a bit like using old fashioned line numbers, if you remember them?
if lis=1 then gosub lisinfo....If you have clicked on Lishoms icon then the variable LIS will be a 1, so the program jumps to another section called lisinfo.
if toc=1 then gosub tocinfo
if mar=1 then gosub marinfo
if kya=1 then gosub kyainfo
if gar=1 then gosub garinfo
The rest does the same thing as the lis one does.
Sync
Ah...the most important command in Dark basic: SYNC. This will redraw everything on the screen so that you can see things happen. You normally put this at the end of a loop.
Right then, what happens if NOC does equal 2?
The loop ends and you fall through to these routines:
y=-200
for drop=1 to 40
sprite 115,165,y,110
inc y,8
sync
next drop
Go on now..I KNOW you can do this. Guess what this routine does. A clue...think of the text and map routine.
wait 5000
goto maingame
Ok..we now just pause for 5 seconds and then, using a GOTO command (yes there still is a place for a goto you know) we jump to the main game routine, which strangely enough is under a label called “Maingame�
The next things you find heading down the listing are the routines for displaying the hidden text.
We will look at just one of them, as they are all copy’s of the first one.
lisinfo:
SET CURRENT BITMAP 1
GET IMAGE 98,0,0,535,175
sprite 10000,60,240,98
lis=0
return
We set the drawing actions to the hidden screen using the SET CURRENT BITMAP command. This just tells Dark basic that what your going to do next is NOT with the default screen but with the hidden screen 1.
We want to grab some text from it, so we use “GET IMAGE 98,0,0,535,175�, which grabs an area starting from 0,0 to 535,175 and stores it in bank number 98.
We then issue a command to put it on the screen using “sprite 10000,60,240,98�.
We then change lis from a 1 to a 0 using “lis=0� and we return (or jump back) to where we gosubed from using “return�.
And that’s all there is to it folks.
We will be using the hidden screen routine to generate all the text in the adventure game, and while there are other ways to do it, this is one of the easiest ways..IMHO.
The clicking on routine is a little more complex, but not much.
clickingon:
if mx>=107 and mx<=157 and my>=170 and my<=220 and lishom<>2
lis=1:lishom=1:click=1
endif
It looks to see if your mouse co-ords of MX and MY are within a boundary (or zone as its sometimes called) and if it is..AND if you have not already chosen the character for your team (lisom NOT EQUAL TO 2) then it runs the rest of the code within the IF ENDIF statement.
The code just sets up variables to do things with. Lis (if you remember) is used to jump to the description of the character. Lishom is used later in the game to make sure you have the right character with your group and click is used to make sure that you have/have not already picked the character and they are in the group and you cannot re-pick them/re-print info.
If your not clicking on a character icon, but on the select button, then the routine just checks to make sure that you have picked them and that you have not tried to pick them twice... that’s what the “if click=1 and lishom=1� command does.
if mx>=482 and mx<=541 and my>=113 and my<=147
if click=1 and lishom=1
The program then puts a nice “X� across the icon to denote you have picked it, and it also adds 1 (inc noc) to the noc variable. Your only allowed 2 characters to join you, but changing that is easy just by changing the noc value in the first main "repeat/until noc=2" loop.
sprite 110,94,160,109
inc noc
It also changed lissom to 2 to stop you picking him again.
lishom=2
endif
endif
Return
You have to close the first IF statement and then you return to where you gosubed from.
Now there are other ways to pick a group I know, and I will be altering this routine later on when the tutorial is finished, but for now just accept it as it is.
Last but not least is the main game loop.
We start off by just clearing up any sprites and images we have stored. I used the “lazy� way, by setting up a loop and then checking if the image/sprite exists and if it did, then we delete it.
The better way is to run through the things you know you did and remove them...but it was late and I wanted it easy!
maingame:
for t=1 to 115
s=SPRITE EXIST(t)
i=IMAGE EXIST(t)
if s=1 then DELETE SPRITE t
if i=1 then DELETE IMAGE t
next t
delete sprite 10000
Next we stop the first music and start the second music up.
STOP MUSIC 1
PLAY MUSIC 2
Ok.... now lets reset everything back up again for this part of the program.
Don’t be afraid to load and unload graphics etc into a program at opportune times. Its not wrong or “bad programming� to do it..you just have to be careful to do it where it will not effect the running of the game.
load image "mouse.bmp",100
load image "spriteicon.bmp",101
load image "mapmarker.bmp",102
load image "hannanoia.bmp",103
load image "garanak.bmp",104
load image "kyacca.bmp",105
load image "marinda.bmp",106
load image "toceda.bmp",107
load image "lishom.bmp",108
load bitmap "islandmap2.bmp",0
And we now just put our mouse on screen and go in to a simple do/loop.
sprite 101,120,280,101
do
mx=MOUSEX()
my=MOUSEY()
SPRITE 1,mx,my,100
sync
Loop
Fine, so that’s it today. You will be able to download all the graphics used from this link:
http://myweb.tiscali.co.uk/freelance/rpg.exe
Feel free to change then so you can see what happens.
You can download the program exe from this link:
http://myweb.tiscali.co.uk/freelance/MangaRPG1.zip
Stay tuned for the second part of this tutorial...which hopefully will not take forever to put up..lol..
(I promise to put it up for no later than next Friday).
sync on
sync rate 12
color backdrop 0
hide mouse
ink 0,1
LOAD MUSIC "intro.mid",1
LOAD MUSIC "ff1world.mid",2
LOAD SOUND "close.wav",1
SET SOUND VOLUME 1,100
PLAY MUSIC 1
load bitmap "dsp2rpg.bmp",0
wait 6000
load bitmap "dblogo.bmp",0
wait 6000
load bitmap "tl.bmp",0
load bitmap "textintro2.bmp",1
suspend for mouse
wait 1
load bitmap "waterback.bmp",0
GET IMAGE 2,0,0,640,255
load image "parchmentfin.bmp",96
load image "alltext1.bmp",97
load image "mouse.bmp",100
load image "hannanoia.bmp",103
load image "garanak.bmp",104
load image "kyacca.bmp",105
load image "marinda.bmp",106
load image "toceda.bmp",107
load image "lishom.bmp",108
load image "xmark.bmp",109
load image "g1.bmp",110
spx=700:y=500:wo=103:wi=108:six=-200:noc=0:click=0
sprite 101,0,0,101
sprite 97,0,500,97
sprite 1000,0,0,2
repeat
sprite 97,30,y,97
dec y
sync
until y<80
delete sprite 97
delete sprite 1000
sync rate 30
y=-480
for t=1 to 60
SPRITE 96,0,y,96
inc y,8
sync
next t
play sound 1
repeat
mx=MOUSEX()
my=MOUSEY()
if my>240 then my=240
if mx>600 then mx=600
SPRITE 1,mx,my,100
ucm=MOUSECLICK()
`clicking left button
if ucm=1 then gosub clickingon
if lis=1 then gosub lisinfo
if toc=1 then gosub tocinfo
if mar=1 then gosub marinfo
if kya=1 then gosub kyainfo
if gar=1 then gosub garinfo
sync
until noc=2
y=-200
for drop=1 to 40
sprite 115,165,y,110
inc y,8
sync
next drop
wait 5000
goto maingame
lisinfo:
SET CURRENT BITMAP 1
GET IMAGE 98,0,0,535,175
sprite 10000,60,240,98
lis=0
return
tocinfo:
SET CURRENT BITMAP 1
GET IMAGE 98,0,177,535,350
sprite 10000,60,240,98
toc=0
return
marinfo:
SET CURRENT BITMAP 1
GET IMAGE 98,0,353,535,546
sprite 10000,60,240,98
mar=0
return
kyainfo:
SET CURRENT BITMAP 1
GET IMAGE 98,0,549,535,740
sprite 10000,60,240,98
kya=0
return
garinfo:
SET CURRENT BITMAP 1
GET IMAGE 98,0,745,535,921
sprite 10000,60,240,98
gar=0
return
clickingon:
if mx>=107 and mx<=157 and my>=170 and my<=220 and lishom<>2
lis=1:lishom=1:click=1
endif
if mx>=200 and mx<=250 and my>=170 and my<=220 and toceda<>2
toc=1:toceda=1:click=2
endif
if mx>=295 and mx<=344 and my>=170 and my<=220 and marinda<>2
mar=1:marinda=1:click=3
endif
if mx>=391 and mx<=440 and my>=170 and my<=220 and kyacca<>2
kya=1:kyacca=1:click=4
endif
if mx>=491 and mx<=540 and my>=170 and my<=220 and garanak<>2
gar=1:garanak=1:click=5
endif
`if select is clicked on.....
if mx>=482 and mx<=541 and my>=113 and my<=147
if click=1 and lishom=1
sprite 110,94,160,109
inc noc
lishom=2
endif
if click=2 and toceda=1
sprite 111,190,160,109
inc noc
toceda=2
endif
if click=3 and marinda=1
sprite 112,280,160,109
inc noc
marinda=2
endif
if click=4 and kyacca=1
sprite 113,380,160,109
inc noc
kyacca=2
endif
if click=5 and garanak=1
sprite 114,480,160,109
inc noc
garanak=2
endif
endif
return
maingame:
`clean up any sprites and gfx
for t=1 to 115
s=SPRITE EXIST(t)
i=IMAGE EXIST(t)
if s=1 then DELETE SPRITE t
if i=1 then DELETE IMAGE t
next t
delete sprite 10000
STOP MUSIC 1
PLAY MUSIC 2
` OK lets reset everything back up again.
load image "mouse.bmp",100
load image "spriteicon.bmp",101
load image "mapmarker.bmp",102
load image "hannanoia.bmp",103
load image "garanak.bmp",104
load image "kyacca.bmp",105
load image "marinda.bmp",106
load image "toceda.bmp",107
load image "lishom.bmp",108
load bitmap "islandmap2.bmp",0
sprite 101,120,280,101
`main do/loop
do
mx=MOUSEX()
my=MOUSEY()
SPRITE 1,mx,my,100
sync
loop