سلام به دوستان. من تازه مي خوام از پايه برنامه نويسي رو شروع كنم و يك آموزش در باره Q basic مي خواستم. اگر تونستيد لطفا يك فايل بذاريد. خيلي ممنون از دوستان عزيز...
Printable View
سلام به دوستان. من تازه مي خوام از پايه برنامه نويسي رو شروع كنم و يك آموزش در باره Q basic مي خواستم. اگر تونستيد لطفا يك فايل بذاريد. خيلي ممنون از دوستان عزيز...
نقل قول:
[HTML]<BODY>
<H3>About the course</H3>This is a short course in simple game design using
QBasic. No prior experience with QBasic is necessary, although I dont go into
detail on how to use the QBasic menu interface.
<P>The principle aim of the course is to stimulate interest in game design. Its
divided in modules to keep you busy for two weeks, although nothing stops you
from doing more than one module per day. The program parts can be copied from
the file and used directly. This way you dont have to type anything!
<P>The two example games can be tailored and expanded upon as an additional
exercise. I will use ASCII characters for graphics and only briefly discuss the
implementation of bit-mapped graphics at the end of the course.
<H3>What to expect from the course</H3>Its for "newbies" to game design. You
might experience this as a course in QBasic as well as games design. Well,
without a thorough understanding of the QBasic commands you wont be able to
write a game, now will you?
<P>The course is not meant to teach you how to write DOOM, only to teach some
basic game design skills.
<H3>Hints?</H3>Use QBasic's built-in HELP function to get more information about
a BASIC command.
<P>Why use QBasic to teach game design? Here are the reasons:
<OL>
<LI>QBasic is bundled with MSDOS 5 and higher so you dont have to fork out
hundreds of dollars to get started.<BR>
<LI>Contrary to most beliefs it is possible to teach good programming
principles with BASIC, especially in QBasic where line numbers and GOTO's
aren't mandatory.<BR>
<LI>BASIC is easy enough to start with and once you've learned the ropes you
can move on to a language more suited to professional game
design.<BR></LI></OL>My teaching methods are unorthodox, but I aim to teach in a
fun way.
<P>
<HR SIZE=5 width="80%">
<H3>Week 1, Day 1</H3>Today you will learn how to make a PACMAN symbol move
across the screen.
<P>Start QBasic and type in the following program: <FONT size=3><XMP>CLS
PRINT "Below is PACMAN himself!"
PRINT "C"
</XMP></FONT>Now RUN the program by pressing ALT-R and then S. Is the graphics a
little unconvincing? Well, we have to start somewhere!
<P>The command CLS clears the screen and we'll use it often.
<P>Lets put PACMAN in the middle of the screen. The command you need is LOCATE.
Type (or edit) and RUN the following: <FONT size=3><XMP>CLS
LOCATE 12,40
PRINT "C"
</XMP></FONT>Easy as pie! <BR>The first value between the brackets indicates the
row, ranging from 1 at the top to 23 at the bottom on the screen. The second
value is the column and ranges from 1 at the left to 80 at the right on the
screen.
<P>Now to make PACMAN move! You could do it this way: <FONT size=3><XMP>LOCATE 12,1
PRINT "C"
LOCATE 12,1
PRINT " " :REM delete the old picture
LOCATE 12,2
PRINT "C" :REM draw a new picture to the right
</XMP></FONT>(REM statements are ignored by the computer and you dont have to
type )<BR>(them in. )<BR>(I will use REM statements to clarify and comment upon
my programming.)<BR>
<P>This method will take forever to program so lets start using variables.
<P>A variable is described has a name and contains a value. This illustrates the
difference between a numeric- and a string variable: <FONT size=3><XMP>contents ---> ¦ 10 ¦ ¦ "twenty" ¦
------ ------------
name ---> apples pears$
(numeric) (string)
</XMP></FONT>The "$" in "pears$" is pronounced "string" and identifies it as a
string variable.<BR>When you PRINT a variable its contents is shown, not its
name. Type (or edit) and RUN: <FONT size=3><XMP>CLS
apples = 10
pears$ = "twenty"
PRINT "Amount of apples are "; apples
PRINT "Amount of pears are "; pears$
</XMP></FONT>Notice how the text between the double quotes is displayed
literally while the variable name is replaced by its contents. The "=" operator
assigns a value to a variable and does it by working from right to left, e.g. in
"apples = 10" the "10" goes into "apples". The ";" causes the computer to
remember where it last PRINTed and the following PRINT will continue at that
position.<BR>PRINT "ABC" will give the same output as PRINT "A"; "B"; "C"
<P>While PACMAN is warming up for his jog, lets make things even easier on
ourselves.<BR>You might have figured that I want to use variables in the
following way: <FONT size=3><XMP>column = 1
LOCATE 12,column :REM This translates to LOCATE 12,1
PRINT "C"
column = column + 1 :REM Lets calculate the value:
:REM column + 1 gives you 1 + 1, in other words 2
LOCATE 12,column :REM This translates to LOCATE 12,2
PRINT "C"
</XMP></FONT>Still lots of repetition! An easier way is to make the computer go
in a "loop", increasing the value of "column" and printing PACMAN.<BR>Type (or
edit) and RUN: <FONT size=3><XMP>CLS
FOR column = 1 TO 80
LOCATE 12,column
PRINT "C"
NEXT column
</XMP></FONT>Hope I haven't put you off programming altogether with that one!
You've implemented as so-called "FOR..NEXT loop" and here's the low-down on it:
The "FOR" line tells the computer that a variable called column will start off
at 1 and then increase in value until it reaches 80. The "NEXT" line increases
column's value with one and makes the program jump back to the "LOCATE" line.
Everything between the "FOR" and the "NEXT" is thus the actual loop and gets
repeated 80 times.
<P>If you still dont understand the concept of the "FOR..NEXT loop" then type
and RUN: <FONT size=3><XMP>CLS
FOR values = 1 TO 10
PRINT values
NEXT values
</XMP></FONT>Hope you've found the experience enlightening!
<P>Clearly also is that everything is happening too fast. PACMAN completes his
trip in the blink of an eye or, depending on how fast your computer is, even
less! The solution is to use the SLEEP command which waits a number of seconds.
Type (or edit) and RUN: <FONT size=3><XMP>CLS
FOR column = 1 TO 80
LOCATE 12,column
PRINT "C"
SLEEP 1
NEXT column
</XMP></FONT>Too slow now! Another way is to use an empty FOR..NEXT loop that
does nothing but kill time. That way you can change the value of the loop untill
it provides an acceptable delay for your computer.
<P>Another problem was that the PACMAN isn't deleted in its old position and you
are left with a whole row of "CCCCCC"s. We'll solve that now. Here's the final
code for the PACMAN 100m sprint: Type (or edit) and RUN! <FONT size=3><XMP>CLS
FOR column = 1 TO 79
LOCATE 12,column
PRINT " C"
FOR nothing = 1 TO 100 :REM This just delays the computer
NEXT nothing
NEXT column
</XMP></FONT>If you didnt see a thing the program is probably still too fast for
your computer, so try changing the limit of the "nothing" loop to 300 or more.
<P>The space before PACMAN cleverly deletes its old position. How? Two
characters are displayed (a " " and a "C") but the position only shift one to
the right. When the two characters are displayed at their new position, the " "
overlaps with the "C" previously displayed and effectively deletes it. That's
all for today!
<P>
<HR SIZE=5 width="80%">
<H3>Week 1, Day 2</H3>Watching PACMAN move is fun, but being in control opens up
endless possibilities.. Enough said! Remember the FOR..NEXT loop? Lets have a
look at a different kind of loop. Type (or edit) and RUN: <FONT size=3><XMP>CLS
value = 1
DO WHILE value < 11
PRINT value :REM This is the loop
value = value + 1
LOOP
</XMP></FONT>This displayed numbers 1 through 10. The program loops while
"value" is less than 11. We will now use the DO..WHILE loop to read the keyboard
and display the characters that you press. However, there's one snag. The
program will loop "forever" unless you stop it! Pressing CTL and BREAK at the
same time will do this. Type (or edit) and RUN: <FONT size=3><XMP>CLS
DO :REM there's no WHILE, so DO forever..
keyed$ = INKEY$ :REM make keyed$ = the key pressed
IF keyed$ <> "" THEN PRINT keyed$ :REM if keyed$ isnt empty display it
LOOP
</XMP></FONT>I bet INKEY$ has you confused!<BR>INKEY$ is a special string
variable. The computer always sets the value of INKEY$ to the key that you
press. While you're not pressing any keys it will contain nothing (nothing is
""). The IF command is very straight forward. IF something is true THEN do
something.. got it? So IF keyed$ is not equal to nothing THEN its value gets
PRINTed. If I didnt include the IF clause then keyed$ would always be PRINTed,
whether it contained a value or not. Try leaving out the IF..THEN part and
you'll see what I mean! Lots and lots of "nothings" fill the screen!
<P>Armed with our new commands we can finally control PACMAN with the keyboard.
Type (or edit) and RUN: <FONT size=3><XMP>CLS
row = 12
column = 40
DO
DO :REM <this loop waits for a key to be pressed
keyed$ = INKEY$
LOOP UNTIL keyed$ <> ""
LOCATE row, column
PRINT " " :REM this erases the "C"
IF keyed$ = "q" THEN row = row - 1
IF keyed$ = "a" THEN row = row + 1
IF keyed$ = "o" THEN column = column - 1
IF keyed$ = "p" THEN column = column + 1
LOCATE row, column
PRINT "C" :REM shows the "C" at the new position
LOOP
</XMP></FONT>Note that you can use your own choice of keys by replacing
"q","a","o" and "p". Using special keys like the cursor keys is another cup of
tea.
<P>If you move PACMAN outside the screen boundaries you'll get an error message.
To prevent this you must add checks to the program. Just replace the IFs with
the following lines and RUN: <FONT size=3><XMP>IF (keyed$ = "q") AND (row > 1) THEN row = row - 1
IF (keyed$ = "a") AND (row < 23) THEN row = row + 1
IF (keyed$ = "o") AND (column > 1) THEN column = column - 1
IF (keyed$ = "p") AND (column < 80) THEN column = column + 1
</XMP></FONT>This should do for today. Hope you enjoyed this as much as I did!
<P>
<HR SIZE=5 width="80%">
<H3>Week 1, Day 3</H3>A playing area is essential to any game so lets design a
maze for our PACMAN.
<P>First I'll have to tell you about arrays. Take a look at this example: <FONT
size=3><XMP>DIM values(3)
values(1) = 5
values(2) = 92
values(3) = 45
</XMP></FONT>Arrays are variables containing multiple elements. Each element is
named after the array followed by a number to specify the position of the
element.<BR>Each element has its own value. Type (or edit) and RUN the following
to see how arrays can save you from a lot of repetitive programming: <FONT
size=3><XMP>CLS
DIM values(10)
FOR count = 1 TO 10
values(count) = count
NEXT count
FOR count = 1 to 10
PRINT values(count)
NEXT count
</XMP></FONT>Remember that "count" ranges from 1 to 10 so the line
"values(count) = count" translates to "values(1) = 1, values(2) = 2, values(3) =
3" etc.
<P>Now lets define our maze. Type (or edit) and RUN: <FONT size=3><XMP>CLS
DIM maze$(6)
maze$(1) = "#########"
maze$(2) = "# # #"
maze$(3) = "# # # # #"
maze$(4) = "# # # #"
maze$(5) = "# # #"
maze$(6) = "#########"
FOR count = 1 to 6
PRINT maze$(count)
NEXT count
</XMP></FONT>Now lets put PACMAN in the maze. Wait - there's nothing that will
keep him from moving over the walls. To solve that problem I'll show you how to
inspect the maze (the contents of maze$).
<P>The command MID$ allows you to look at parts of a string variable. It has the
following format: MID$(name of string, starting position, number of letters).
Lets look at an example: <FONT size=3><XMP>alphabet$ = "ABCDE"
PRINT MID$(alphabet$, 1, 2) :REM displays "AB"
PRINT MID$(alphabet$, 3, 1) :REM displays "C"
</XMP></FONT>Every time PACMAN moves we'll use his position (row and column) to
see if he overlaps a wall in the maze. Type (or edit) and RUN: (you'll have to
press CTRL-BREAK to stop the program) <FONT size=3><XMP>CLS
DIM maze$(6)
maze$(1) = "#########"
maze$(2) = "# # #"
maze$(3) = "# # # # #"
maze$(4) = "# # # #"
maze$(5) = "# # #"
maze$(6) = "#########"
row = 5
column = 3
DO
LOCATE 1, 1
FOR count = 1 to 6
PRINT maze$(count) :REM PRINT the maze
NEXT count
LOCATE row, column
PRINT "C" :REM PRINT PACMAN
DO
keyed$ = INKEY$
LOOP UNTIL keyed$ <> ""
oldRow = row :REM remember old position of PACMAN
oldColumn = column
IF keyed$ = "q" THEN row = row - 1
IF keyed$ = "a" THEN row = row + 1
IF keyed$ = "o" THEN column = column - 1
IF keyed$ = "p" THEN column = column + 1
IF MID$(maze$(row), column, 1) = "#" THEN
row = oldRow :REM move PACMAN back to his
column = oldColumn :REM old position
END IF
LOOP
</XMP></FONT>All that needs mentioning is that I used the "IF..END IF" structure
to allow for more than one action.
<P>If you type in the examples you can save yourself some time by saving the
PACMAN game to disk (press ALT-F then S), because we will re-use the game during
the rest of the week.
<P>Tomorrow we'll add dots and a ghost to the maze!
<P>
<HR SIZE=5 width="80%">
<H3>Week 1, Day 4</H3>Add the dots to the maze by changing the following lines:
<FONT size=3><XMP>maze$(1) = "#########"
maze$(2) = "#...#...#"
maze$(3) = "#.#.#.#.#"
maze$(4) = "#.#...#.#"
maze$(5) = "#...#...#"
maze$(6) = "#########"
</XMP></FONT>As you might have guessed we'll inspect the maze each time PACMAN
moves and keep count of the number of dots he eat. A dot has to be removed when
eaten. When our count reaches 21 (count them!) dots, the game ends.
<P>MID$ can be used to change a string variable as well as inspecting it. Look
at the following example: <FONT size=3><XMP>alphabet$="ABCDE"
MID$(alphabet$, 2, 3) = "XYZ"
PRINT alphabet$ :REM displays "AXYZE"
</XMP></FONT>We'll use MID$ to replace the dots with blanks when PACMAN eats
them. Type (or edit) and RUN: (changes in the program are marked)
<FORM><TEXTAREA cols=70 name=code rows=20 wrap=off>CLS
DIM maze$(6)
maze$(1) = "#########"
maze$(2) = "#...#...#"
maze$(3) = "#.#.#.#.#"
maze$(4) = "#.#...#.#"
maze$(5) = "#...#...#"
maze$(6) = "#########"
row = 5
column = 3
dots = 21 :REM new
DO
LOCATE 1, 1
FOR count = 1 to 6
PRINT maze$(count)
NEXT count
LOCATE row, column
PRINT "C"
:REM new
IF dots = 0 THEN
LOCATE 8, 1 :REM
PRINT "You have won!" :REM
END :REM
END IF :REM
DO
keyed$ = INKEY$
LOOP UNTIL keyed$ <> ""
oldRow = row
oldColumn = column
IF keyed$ = "q" THEN row = row - 1
IF keyed$ = "a" THEN row = row + 1
IF keyed$ = "o" THEN column = column - 1
IF keyed$ = "p" THEN column = column + 1
IF MID$(maze$(row), column, 1) = "#" THEN
row = oldRow
column = oldColumn
END IF
:REM new
IF MID$(maze$(row), column, 1) = "." THEN
MID$(maze$(row), column, 1) = " " :REM
dots = dots - 1 :REM
END IF :REM
LOOP
</TEXTAREA></FORM>(QBasic does not allow me to place a ":REM" next to a IF..THEN
line. ) (So if you suspect a REM is missing, see if its next tot an IF..THEN.)
<P>The reason why we dont do the "IF dots = 0" test directly after inspecting
the maze is because we want to draw PACMAN in his new position before ending the
game.
<P>Here is a better (or clearer) way of inspecting keyed$ and maze$: <FONT
size=3><XMP>REM examine the keys
SELECT CASE keyed$
CASE IS = "q"
row = row - 1
CASE IS = "a"
row = row + 1
CASE IS = "o"
column = column - 1
CASE IS = "p"
column = column + 1
END SELECT
REM examine the maze
SELECT CASE MID$(maze$(row), column, 1)
CASE IS = "#"
row = oldRow
column = oldColumn
CASE IS = "."
MID$(maze$(row), column, 1) = " "
dots = dots - 1
END SELECT
</XMP></FONT>SELECT makes it a lot easier to read the program. Also notice the
way I put spaces before (indent) some words. Another good idea is to use blank
lines to seperate the various parts of your program.
<P>Lets place a ghost in the maze. We'll just display the ghost for now and
detect whether PACMAN collides with it. Tomorrow we can make it move.
<P>Detecting whether there's a collision is a simple matter of comparing
PACMAN's and the ghost's positions (row and column). Type (or edit) and RUN:
<FORM><TEXTAREA cols=70 name=code rows=20 wrap=off>CLS
DIM maze$(6)
maze$(1) = "#########"
maze$(2) = "#...#...#"
maze$(3) = "#.#.#.#.#"
maze$(4) = "#.#...#.#"
maze$(5) = "#...#...#"
maze$(6) = "#########"
row = 5
column = 3
ghostRow = 2 :REM new
ghostColumn = 7 :REM
dots = 21
DO
LOCATE 1, 1
FOR count = 1 to 6
PRINT maze$(count)
NEXT count
LOCATE row, column
PRINT "C"
LOCATE ghostRow, ghostColumn :REM new
PRINT "G" :REM
IF dots = 0 THEN
LOCATE 8, 1
PRINT "You have won!"
END
END IF
:REM new
IF ((row = ghostRow) AND (column = ghostColumn)) THEN
LOCATE 8, 1 :REM
PRINT "You've been caught!" :REM
END :REM
END IF :REM
DO
keyed$ = INKEY$
LOOP UNTIL keyed$ <> ""
oldRow = row
oldColumn = column
REM examine the keys
SELECT CASE keyed$
CASE IS = "q"
row = row - 1
CASE IS = "a"
row = row + 1
CASE IS = "o"
column = column - 1
CASE IS = "p"
column = column + 1
END SELECT
REM examine the maze
SELECT CASE MID$(maze$(row), column, 1)
CASE IS = "#"
row = oldRow
column = oldColumn
CASE IS = "."
MID$(maze$(row), column, 1) = " "
dots = dots - 1
END SELECT
LOOP
</TEXTAREA></FORM>Phew! I need a rest after that! Remember to save the program
for tomorrow.
<P>
<HR SIZE=5 width="80%">
<H3>Week 1, Day 5</H3>Lets give the ghost some "artificial intelligence".
<P>As you might have suspected we will compare his positions with PACMAN's and
move him one position nearer. Allowing the ghost to move diagonally will give it
an unfair advantage so ghostRow and ghostColumn will not change at the same
time. Of course the ghost will also have to be blocked by the walls of the maze.
We dont have to check for dots because the ghost dont eat them.
<P>So what are we waiting for? Type (or edit) and RUN!
<FORM><TEXTAREA cols=70 name=code rows=20 wrap=off>CLS
DIM maze$(6)
maze$(1) = "#########"
maze$(2) = "#...#...#"
maze$(3) = "#.#.#.#.#"
maze$(4) = "#.#...#.#"
maze$(5) = "#...#...#"
maze$(6) = "#########"
row = 5
column = 3
ghostRow = 2
ghostColumn = 7
dots = 21
DO
LOCATE 1, 1
FOR count = 1 to 6
PRINT maze$(count)
NEXT count
LOCATE row, column
PRINT "C"
LOCATE ghostRow, ghostColumn
PRINT "G"
IF dots = 0 THEN
LOCATE 8, 1
PRINT "You have won!"
END
END IF
IF ((row = ghostRow) AND (column = ghostColumn)) THEN
LOCATE 8, 1
PRINT "You've been caught!"
END
END IF
DO
keyed$ = INKEY$
LOOP UNTIL keyed$ <> ""
oldRow = row
oldColumn = column
REM examine the keys
SELECT CASE keyed$
CASE IS = "q"
row = row - 1
CASE IS = "a"
row = row + 1
CASE IS = "o"
column = column - 1
CASE IS = "p"
column = column + 1
END SELECT
REM examine the maze
SELECT CASE MID$(maze$(row), column, 1)
CASE IS = "#"
row = oldRow
column = oldColumn
CASE IS = "."
MID$(maze$(row), column, 1) = " "
dots = dots - 1
END SELECT
REM move ghost closer to PACMAN :REM <Ä¿ everything from this point
:REM ³ onwards is new
oldRow = ghostRow
SELECT CASE ghostRow
CASE < row
ghostRow = ghostRow + 1
CASE > row
ghostRow = ghostRow - 1
END SELECT
IF MID$(maze$(ghostRow), ghostColumn, 1) = "#" THEN ghostRow = oldRow
IF ghostRow = oldRow THEN
oldColumn = ghostColumn
SELECT CASE ghostColumn
CASE < column
ghostColumn = ghostColumn + 1
CASE > column
ghostColumn = ghostColumn - 1
END SELECT
IF MID$(maze$(ghostRow), ghostColumn, 1) = "#" THEN ghostColumn = oldColumn
END IF
LOOP
</TEXTAREA></FORM>Notice that I test whether ghostRow has stayed the same ( =
oldRow) before testing for ghostColumn. This prevents diagonal movement for the
ghost. Another problem is that the ghost waits for you to make a move before
moving himself.<BR>The loop that waits for a key to be pressed is the culprit.
Now we will have to put a delay somewhere in the program because the ghost will
move at blinding speed! Replace the following lines in the program and RUN it:
<FONT size=3><XMP>DO
keyed$ = INKEY$
LOOP UNTIL keyed$ <> ""
with:
keyed$ = INKEY$
REM: kill time
FOR nothing = 1 TO 500
NEXT nothing
</XMP></FONT>If the game is still too fast then change the limit of "nothing" to
1000 or more.
<P>The game is still too difficult because the ghost is too intelligent - it
follows you at every possible opportunity. To add some randomness to its pattern
we will use the command RND. The value of RND is never the same (for all
practical purposes) but is always a value between 0 and 1.<BR>The condition "IF
RND < 0.1 " is true roughly 10% of the time. Here is the entire listing with
the changes added: (Type (or edit) and RUN)
<FORM><TEXTAREA cols=70 name=code rows=20 wrap=off>CLS
DIM maze$(6)
maze$(1) = "#########"
maze$(2) = "#...#...#"
maze$(3) = "#.#.#.#.#"
maze$(4) = "#.#...#.#"
maze$(5) = "#...#...#"
maze$(6) = "#########"
row = 5
column = 3
ghostRow = 2
ghostColumn = 7
dots = 21
DO
LOCATE 1, 1
FOR count = 1 to 6
PRINT maze$(count)
NEXT count
LOCATE row, column
PRINT "C"
LOCATE ghostRow, ghostColumn
PRINT "G"
IF dots = 0 THEN
LOCATE 8, 1
PRINT "You have won!"
END
END IF
IF ((row = ghostRow) AND (column = ghostColumn)) THEN
LOCATE 8, 1
PRINT "You've been caught!"
END
END IF
keyed$ = INKEY$
FOR nothing = 1 TO 500 :REM change if your computer is faster
NEXT nothing
oldRow = row
oldColumn = column
REM examine the keys
SELECT CASE keyed$
CASE IS = "q"
row = row - 1
CASE IS = "a"
row = row + 1
CASE IS = "o"
column = column - 1
CASE IS = "p"
column = column + 1
END SELECT
REM examine the maze
SELECT CASE MID$(maze$(row), column, 1)
CASE IS = "#"
row = oldRow
column = oldColumn
CASE IS = "."
MID$(maze$(row), column, 1) = " "
dots = dots - 1
END SELECT
:REM new
IF RND < 0.1 THEN
:REM
REM move ghost closer to PACMAN
oldRow = ghostRow
SELECT CASE ghostRow
CASE < row
ghostRow = ghostRow + 1
CASE > row
ghostRow = ghostRow - 1
END SELECT
IF MID$(maze$(ghostRow), ghostColumn, 1) = "#" THEN ghostRow = oldRow
IF ghostRow = oldRow THEN
oldColumn = ghostColumn
SELECT CASE ghostColumn
CASE < column
ghostColumn = ghostColumn + 1
CASE > column
ghostColumn = ghostColumn - 1
END SELECT
IF MID$(maze$(ghostRow), ghostColumn, 1) = "#" THEN ghostColumn = oldColumn
END IF
END IF :REM <ÄÄÄ new
LOOP
</TEXTAREA></FORM>Another way to slow down the game is to use a variable "wait"
and add 1 to it every time the program loops. Only when "wait" = 20 the ghost is
allowed to move.<BR>Remember to reset "wait" to 0 after moving, or its value
will be 21, 22, etc. and never again 20!<BR>If you use this method you must
remove the FOR..NEXT loop that kills time.
<P>Next week we'll do an RPG!
<P>
<HR SIZE=5 width="80%">
<H3>Week 2, Day 1</H3>Our RPG will be simple, requiring you to navigate a maze
and find the exit. To make things more interesting the maze will be populated
with creatures that attack you.<BR>Defeat them and you will be rewarded in gold
coins. Food, weapons and other useful items will be present in some rooms. Only
one room has the exit but you must pay a toll of 100 gold pieces to use it.
<P>Lets begin by defining the maze and letting the player walk through it.
(Entering "q" during play will stop the program.) Type (or edit) and RUN:
<FORM><TEXTAREA cols=70 name=code rows=20 wrap=off>CLS
row = 5
column = 5
moveErr$ = "You cannot move in that direction!"
LOCATE 14,1
PRINT "Commands: n - north"
PRINT " s - south"
PRINT " e - east"
PRINT " w - west"
PRINT " q - quit"
DO
LOCATE 1, 1
PRINT "Your position:"; row; column
LOCATE 8, 1
INPUT "What now"; reply$
LOCATE 10, 1
PRINT SPACE$(79)
SELECT CASE reply$
CASE IS = "n"
IF row = 1 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
row = row - 1
LOCATE 10, 1
PRINT "You go north."
END IF
CASE IS = "s"
IF row = 10 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
row = row + 1
LOCATE 10, 1
PRINT "You go south."
END IF
CASE IS = "w"
IF column = 1 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
column = column - 1
LOCATE 10, 1
PRINT "You go west."
END IF
CASE IS = "e"
IF column = 10 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
column = column + 1
LOCATE 10, 1
PRINT "You go east."
END IF
CASE IS = "q"
LOCATE 10, 1
PRINT "Bye!"
END
END SELECT
LOOP
</TEXTAREA></FORM>You'll notice that the maze is 10 by 10 rooms in size. I you
try to move outside its boundaries you are stopped and an error message appears
(I stored it in variable "moveErr$" so there's less typing).
<P>The command INPUT prompts the user for a value and stores it in a variable
(reply$). As a bonus you can display some text at the same time ("What now").
<P>SPACE$ is a function that provides spaces; SPACE$(2) gives you " ". What the
program does at that point is to overwrite any error messages that resulted from
the previous user input.
<P>"INT(RND * 10) + 1" gives a whole number ranging from 1 to 10. How does it
work?<BR>INT gives the integer value of a variable, e.g. INT(1.9) gives 1.
Because RND gives a value between 0 and 1, RND * 10 will give a value between 0
and 10. And because INT(0.99) = 0 and INT(9.99) = 9, it is necessary to add 1 to
the result.
<P>Now to add an exit to the maze:
<FORM><TEXTAREA cols=70 name=code rows=20 wrap=off>CLS
row = 5
column = 5
moveErr$ = "You cannot move in that direction!"
exitRow = INT(RND * 10) + 1 :REM new
exitColumn = INT(RND * 10) + 1 :REM
gold = 0 :REM
LOCATE 14, 1
PRINT "Commands: n - north"
PRINT " s - south"
PRINT " e - east"
PRINT " w - west"
PRINT " x - use exit" :REM new
PRINT " q - quit"
DO
LOCATE 1, 1
PRINT "Your position:"; row; column
:REM new
IF ((row = exitRow) AND (column = exitColumn)) THEN
LOCATE 2, 1 :REM
PRINT "You are at the exit!" :REM
ELSE :REM
LOCATE 2, 1 :REM
PRINT SPACE$(79) :REM
END IF :REM
LOCATE 8, 1
INPUT "What now"; reply$
LOCATE 10, 1
PRINT SPACE$(79)
SELECT CASE reply$
CASE IS = "n"
IF row = 1 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
row = row - 1
LOCATE 10, 1
PRINT "You go north."
END IF
CASE IS = "s"
IF row = 10 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
row = row + 1
LOCATE 10, 1
PRINT "You go south."
END IF
CASE IS = "w"
IF column = 1 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
column = column - 1
LOCATE 10, 1
PRINT "You go west."
END IF
CASE IS = "e"
IF column = 10 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
column = column + 1
LOCATE 10, 1
PRINT "You go east."
END IF
CASE IS = "x" :REM new
IF ((row = exitRow) AND (column = exitColumn)) THEN
:REM
IF gold < 100 THEN
LOCATE 10, 1 :REM
PRINT "You dont have enough gold!" :REM
ELSE :REM
LOCATE 10, 1 :REM
PRINT "You have escaped! Well done!" :REM
END :REM
END IF :REM
END IF :REM
CASE IS = "q"
LOCATE 10, 1
PRINT "Bye!"
END
END SELECT
LOOP
</TEXTAREA></FORM>Thought you could escape? Maybe tomorrow when we add monsters
and gold!
<P>
<HR SIZE=5 width="80%">
<H3>Week 2, Day 2</H3>To make things interesting we'll use RND to scatter a
variety of monsters throughout the maze. The amount of gold present in a room
will depend on how difficult the monster is to beat. Type (or edit) and RUN:
<FORM><TEXTAREA cols=70 name=code rows=20 wrap=off>CLS
DIM monster(10, 10) :REM new
FOR count1 = 1 TO 10 :REM
FOR count2 = 1 TO 10 :REM
monster(count1, count2) = INT(RND * 11) :REM
NEXT count2 :REM
NEXT count1 :REM
row = 5
column = 5
moveErr$ = "You cannot move in that direction!"
exitRow = INT(RND * 10) + 1
exitColumn = INT(RND * 10) + 1
gold = 0
DIM monster$(10) :REM new
RESTORE monsterData :REM
FOR count = 1 TO 10 :REM
READ monster$(count) :REM
NEXT count :REM
LOCATE 14, 1
PRINT "Commands: n - north"
PRINT " s - south"
PRINT " e - east"
PRINT " w - west"
PRINT " x - use exit"
PRINT " q - quit"
DO
LOCATE 1, 1
PRINT "Your position:"; row; column
IF ((row = exitRow) AND (column = exitColumn)) THEN
LOCATE 2, 1
PRINT "You are at the exit!"
ELSE
LOCATE 2, 1
PRINT SPACE$(79)
END IF
LOCATE 3, 1 :REM new
PRINT "Monster: "; :REM
monsterType = monster(row, column) :REM
IF monsterType = 0 THEN
PRINT "nothing " :REM
ELSE :REM
monsterName$ = MID$(monster$(monsterType), 1, 10) :REM
PRINT monsterName$ :REM
END IF :REM
LOCATE 8, 1
INPUT "What now"; reply$
LOCATE 10, 1
PRINT SPACE$(79)
SELECT CASE reply$
CASE IS = "n"
IF row = 1 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
row = row - 1
LOCATE 10, 1
PRINT "You go north."
END IF
CASE IS = "s"
IF row = 10 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
row = row + 1
LOCATE 10, 1
PRINT "You go south."
END IF
CASE IS = "w"
IF column = 1 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
column = column - 1
LOCATE 10, 1
PRINT "You go west."
END IF
CASE IS = "e"
IF column = 10 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
column = column + 1
LOCATE 10, 1
PRINT "You go east."
END IF
CASE IS = "x"
IF ((row = exitRow) AND (column = exitColumn)) THEN
IF gold < 100 THEN
LOCATE 10, 1
PRINT "You dont have enough gold!"
ELSE
LOCATE 10, 1
PRINT "You have escaped! Well done!"
END
END IF
END IF
CASE IS = "q"
LOCATE 10, 1
PRINT "Bye!"
END
END SELECT
LOOP
monsterData: :REM new
DATA "blind bat " :REM
DATA "rat " :REM
DATA "snake " :REM
DATA "goblin " :REM
DATA "troll " :REM
DATA "bear " :REM
DATA "lion " :REM
DATA "sabretooth" :REM
DATA "elephant " :REM
DATA "dragon " :REM
</TEXTAREA></FORM>I decided to allocate a number to each room to identify the
type of monster in the room.<BR>To do this I needed 10 x 10 numbers. If we keep
in mind that our player's location is stored as a row and a column value, its
easy to see why I decided to to use a similar method of storing the monster
values.<BR>Just by using row and column ( monster(row, column) ) you get the
monster value at the player's location.
<P>As you can see at the top of the program, I gave each location a monster
value ranging from 0 to 10 (remember that INT(RND * 11) never gives 11). Why not
1 to 10?<BR>The 0 will serve as an indicator that there is no monster at that
location.
<P>What's RESTORE and READ?<BR>The READ command looks for DATA statements in
your program and reads their values (e.g. the names of the monsters). It starts
at the first DATA statement unless you use RESTORE to point it to a specific
part of the program. RESTORE points to a LABEL (e.g. monsterData). You can put
LABELS anywhere in your program, just remember to follow it with a colon.
<P>Why READ the monster names when you can use: monster$(1) = "blind bat ",
monster$(2) = "rat ", etc? Its just easier to find the data if its grouped
together. You can then use a FOR..NEXT loop to set the values rather than typing
monster(x)="abcd" every time.
<P>One last thing about READ: it remembers the position where it last read a
value , so you have to use RESTORE if you want to read from the top again.
<P>Notice how I use the monster number (monsterType) to display its name from a
monster$. So if monsterType = 1 then monster$(monsterType) = "blind bat " will
be displayed.
<P>This should be enough reading for one day!
<P>
<HR SIZE=5 width="80%">
<H3>Week 2, Day 3</H3>What good are monsters if they dont put up a fight? I'll
rectify that if you type and RUN:
<FORM><TEXTAREA cols=70 name=code rows=20 wrap=off>CLS
DIM monster(10, 10)
FOR count1 = 1 TO 10
FOR count2 = 1 TO 10
monster(count1, count2) = INT(RND * 11)
NEXT count2
NEXT count1
row = 5
column = 5
moveErr$ = "You cannot move in that direction!"
pressKey$ = "Press any key to continue." :REM new
exitRow = INT(RND * 10) + 1
exitColumn = INT(RND * 10) + 1
gold = 0
health = 20 :REM new
weapon = 1 :REM
DIM monster$(10)
RESTORE monsterData
FOR count = 1 TO 10
READ monster$(count)
NEXT count
LOCATE 14, 1
PRINT "Commands: n - north"
PRINT " s - south"
PRINT " e - east"
PRINT " w - west"
PRINT " a - attack" :REM new
PRINT " x - use exit"
PRINT " q - quit"
DO
LOCATE 1, 1
PRINT "Your position:"; row; column
LOCATE 1, 25 :REM new
PRINT "Gold:"; gold; " Health:"; health :REM
IF ((row = exitRow) AND (column = exitColumn)) THEN
LOCATE 2, 1
PRINT "You are at the exit!"
ELSE
LOCATE 2, 1
PRINT SPACE$(79)
END IF
LOCATE 3, 1
PRINT "Monster: ";
monsterType = monster(row, column)
IF monsterType = 0 THEN
PRINT "nothing "
ELSE
monsterName$ = MID$(monster$(monsterType), 1, 10)
PRINT monsterName$
monsterAttack = VAL(MID$(monster$(monsterType), 11, 1)) :REM new
monsterHealth = VAL(MID$(monster$(monsterType), 12, 1)) :REM
monsterGold = monsterType * INT(RND * 6) :REM
END IF
LOCATE 8, 1
INPUT "What now"; reply$
LOCATE 10, 1
PRINT SPACE$(79)
PRINT SPACE$(79)
PRINT SPACE$(79)
SELECT CASE reply$
CASE IS = "n"
IF row = 1 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
row = row - 1
LOCATE 10, 1
PRINT "You go north."
END IF
CASE IS = "s"
IF row = 10 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
row = row + 1
LOCATE 10, 1
PRINT "You go south."
END IF
CASE IS = "w"
IF column = 1 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
column = column - 1
LOCATE 10, 1
PRINT "You go west."
END IF
CASE IS = "e"
IF column = 10 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
column = column + 1
LOCATE 10, 1
PRINT "You go east."
END IF
CASE IS = "x"
IF ((row = exitRow) AND (column = exitColumn)) THEN
IF gold < 100 THEN
LOCATE 10, 1
PRINT "You dont have enough gold!"
ELSE
LOCATE 10, 1
PRINT "You have escaped! Well done!"
END
END IF
END IF
CASE IS = "a" :REM new
IF monsterType = 0 THEN
LOCATE 10, 1 :REM
PRINT "There's nothing to attack!" :REM
ELSE :REM
DO WHILE ((monsterHealth > 0) AND (health > 0)) :REM
LOCATE 10, 1 :REM
PRINT SPACE$(79) :REM
PRINT SPACE$(79) :REM
PRINT SPACE$(79) :REM
LOCATE 10, 1 :REM
attack = weapon + INT(RND * 9) :REM
SELECT CASE attack :REM
CASE IS = monsterAttack :REM
PRINT "No one wins this round." :REM
CASE IS > monsterAttack :REM
PRINT "You deal the "; monsterName$; " a blow!":REM
monsterHealth = monsterHealth - 1 :REM
CASE IS < monsterAttack :REM
PRINT "You have been wounded!" :REM
health = health - 1 :REM
END SELECT :REM
PRINT pressKey$ :REM
SLEEP :REM
LOOP :REM
LOCATE 10, 1 :REM
IF health > 0 THEN
PRINT "You won the fight!" :REM
PRINT "You found "; monsterGold; " pieces of gold!" :REM
gold = gold + monsterGold :REM
monsterType = 0 :REM
monster(row, column) = 0 :REM
PRINT pressKey$ :REM
SLEEP :REM
ELSE :REM
PRINT "The "; monsterName$; " killed you!" :REM
PRINT "Game over!" :REM
END :REM
END IF :REM
END IF :REM
CASE IS = "q"
LOCATE 10, 1
PRINT "Bye!"
END
END SELECT
LOOP
monsterData:
DATA "blind bat 21" :REM changed
DATA "rat 11" :REM
DATA "snake 31" :REM
DATA "goblin 23" :REM
DATA "troll 44" :REM
DATA "bear 55" :REM
DATA "lion 54" :REM
DATA "sabretooth65" :REM
DATA "elephant 78" :REM
DATA "dragon 98" :REM
</TEXTAREA></FORM>Starting from the top:<BR>The variable "health" starts of at
20 but 1 gets subtracted from it each time a monster hits you.<BR>If it reaches
0 you've had it.<BR>The variable "weapon" gets added to your attack score:
weapon + INT(RND * 9). So the attack score will range from 1 to 9. (INT(RND * 9)
gives 0 to 8)
<P>MonsterAttack: A monster's attack score is stored as the second last
character in a monster$.<BR>VAL takes a string and converts it to a decimal
value, so VAL("10") gives 10. Trying something like VAL("ABC") will cause a
runtime error.
<P>MonsterHealth: The last character READ into a monster$ is the monster's
health. Each time you wound it, it loses a point of health and dies when it
loses all its points.
<P>MonsterGold: I chose to add a random factor to the amount of gold found, but
by multiplying with monsterAttack you should still find more gold after
defeating tougher monsters.
<P>Notice that fighting takes place and continues until one side runs out of
health.<BR>So when this loop terminates we know that if your health > 0 then
the monster's health must have run out. If the monster loses then monsterType is
set to 0 so that you cannot fight it again.<BR>Monsters(row, column) = 0 changes
the location's monster to "nothing", so when you enter this location again there
will be no monsters.
<P>Can you remember that the SLEEP command is used to pause the program for a
number of seconds?<BR>SLEEP on its own waits indefinitely or until a key is
pressed. I've used it to wait for a keypress. You can use DO: LOOP UNTIL INKEY$
<> "" instead of SLEEP.
<P>Thats all for now!
<P>
<HR SIZE=5 width="80%">
<H3>Week 2, Day 4</H3>Lets scatter some useful items like food and weapons
throughout the maze. To balance things we'll add a few traps..
<FORM><TEXTAREA cols=70 name=code rows=20 wrap=off>CLS
RANDOMIZE TIMER :REM new
DIM monster(10, 10)
FOR count1 = 1 TO 10
FOR count2 = 1 TO 10
monster(count1, count2) = INT(RND * 11)
NEXT count2
NEXT count1
DIM item(10, 10) :REM new
FOR count1 = 1 TO 10 :REM
FOR count2 = 1 TO 10 :REM
IF RND < .2 THEN :REM
item(count1, count2) = INT(RND * 9) + 1 :REM
ELSE :REM
item(count1, count2) = 0 :REM
END IF :REM
NEXT count2 :REM
NEXT count1 :REM
row = 5
column = 5
moveErr$ = "You cannot move in that direction!"
pressKey$ = "Press any key to continue."
exitRow = INT(RND * 10) + 1
exitColumn = INT(RND * 10) + 1
gold = 0
health = 20
weapon = 1
DIM monster$(10)
RESTORE monsterData
FOR count = 1 TO 10
READ monster$(count)
NEXT count
DIM item$(9) :REM new
RESTORE itemData :REM
FOR count = 1 TO 9 :REM
READ item$(count) :REM
NEXT count :REM
LOCATE 14, 1
PRINT "Commands: n - north"
PRINT " s - south"
PRINT " e - east"
PRINT " w - west"
PRINT " a - attack"
PRINT " t - take item" :REM new
PRINT " x - use exit"
PRINT " q - quit"
LOCATE 14, 40 :REM new
PRINT CHR$(201); STRING$(10, CHR$(205)); CHR$(187) :REM
LOCATE 15, 40 :REM
PRINT CHR$(186); SPACE$(10); CHR$(186) :REM
LOCATE 16, 40 :REM
PRINT CHR$(200); STRING$(10, CHR$(205)); CHR$(188) :REM
LOCATE 17, 44 :REM
PRINT "ITEM" :REM
DO
LOCATE 1, 1
PRINT "Your position:"; row; column
LOCATE 1, 25
PRINT "Gold:"; gold; " Health:"; health; " Weapon:"; weapon :REM <ÄÄchanged
IF ((row = exitRow) AND (column = exitColumn)) THEN
LOCATE 2, 1
PRINT "You are at the exit!"
ELSE
LOCATE 2, 1
PRINT SPACE$(79)
END IF
LOCATE 3, 1
PRINT "Monster: ";
monsterType = monster(row, column)
IF monsterType = 0 THEN
PRINT "nothing "
ELSE
monsterName$ = MID$(monster$(monsterType), 1, 10)
PRINT monsterName$
monsterAttack = VAL(MID$(monster$(monsterType), 11, 1))
MonsterHealth = VAL(MID$(monster$(monsterType), 12, 1))
MonsterGold = monsterType * INT(RND * 6)
END IF
itemType (or edit) = item(row, column) :REM new
IF itemType (or edit) = 0 THEN :REM
LOCATE 15, 41 :REM
PRINT "nothing " :REM
ELSE :REM
itemName$ = LEFT$(item$(itemType (or edit)), 10) :REM
itemClass$ = MID$(item$(itemType (or edit)), 11, 1) :REM
itemValue = VAL(RIGHT$(item$(itemType (or edit)), 1)) :REM
LOCATE 15, 41 :REM
PRINT itemName$ :REM
IF itemClass$ = "T" THEN :REM
LOCATE 10, 1 :REM
PRINT "The "; RTRIM$(itemName$); " damages you for "; itemValue; " points!"
health = health - itemValue :REM
item(row, column) = 0 :REM
itemType (or edit) = 0 :REM
IF health <= 0 THEN :REM
PRINT "You die!" :REM
PRINT "Game over!" :REM
END :REM
END IF :REM
END IF :REM
END IF :REM
LOCATE 8, 1
INPUT "What now"; reply$
LOCATE 10, 1
PRINT SPACE$(79)
PRINT SPACE$(79)
PRINT SPACE$(79)
SELECT CASE reply$
CASE IS = "n"
IF row = 1 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
row = row - 1
LOCATE 10, 1
PRINT "You go north."
END IF
CASE IS = "s"
IF row = 10 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
row = row + 1
LOCATE 10, 1
PRINT "You go south."
END IF
CASE IS = "w"
IF column = 1 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
column = column - 1
LOCATE 10, 1
PRINT "You go west."
END IF
CASE IS = "e"
IF column = 10 THEN
LOCATE 10, 1
PRINT moveErr$
ELSE
column = column + 1
LOCATE 10, 1
PRINT "You go east."
END IF
CASE IS = "x"
IF ((row = exitRow) AND (column = exitColumn)) THEN
IF gold < 100 THEN
LOCATE 10, 1
PRINT "You dont have enough gold!"
ELSE
LOCATE 10, 1
PRINT "You have escaped! Well done!"
END
END IF
END IF
CASE IS = "a"
IF monsterType = 0 THEN
LOCATE 10, 1
PRINT "There's nothing to attack!"
ELSE
DO WHILE ((MonsterHealth > 0) AND (health > 0))
LOCATE 10, 1
PRINT SPACE$(79)
PRINT SPACE$(79)
PRINT SPACE$(79)
LOCATE 10, 1
attack = weapon + INT(RND * 9)
SELECT CASE attack
CASE IS = monsterAttack
PRINT "No one wins this round."
CASE IS > monsterAttack
:REM changed
PRINT "You deal the "; RTRIM$(monsterName$); " a blow!"
:REM
MonsterHealth = MonsterHealth - 1
CASE IS < monsterAttack
PRINT "You have been wounded!"
health = health - 1
END SELECT
PRINT pressKey$
SLEEP
LOOP
LOCATE 10, 1
IF health > 0 THEN
PRINT "You won the fight!"; SPACE$(20)
PRINT "You found "; MonsterGold; " pieces of gold!"
gold = gold + MonsterGold
monsterType = 0
monster(row, column) = 0
PRINT pressKey$
SLEEP
ELSE
:REM changed
PRINT "The "; RTRIM$(monsterName$); " killed you!"; SPACE$(20)
:REM
PRINT "Game over!"; SPACE$(20)
END
END IF
END IF
CASE IS = "t" :REM
IF itemType (or edit) = 0 THEN
LOCATE 10, 1 :REM
PRINT "Nothing to take!" :REM
PRINT pressKey$ :REM
SLEEP :REM
ELSE :REM
SELECT CASE itemClass$ :REM
CASE IS = "F" :REM
LOCATE 10, 1 :REM
PRINT "You eat the "; RTRIM$(itemName$); "." :REM
IF health = 20 THEN :REM
PRINT "You had no wounds, so the food is wasted." :REM
ELSE :REM
health = health + itemValue :REM
PRINT "You gain "; itemValue; " health points." :REM
END IF :REM
CASE IS = "W" :REM
LOCATE 10, 1 :REM
IF weapon >= itemValue THEN :REM
PRINT "You have a similar or better weapon." :REM
ELSE :REM
PRINT "You pick up a "; RTRIM$(itemName$); " !" :REM
weapon = itemValue :REM
PRINT "Your weapon rating is now "; weapon; "." :REM
END IF :REM
END SELECT :REM
PRINT pressKey$ :REM
SLEEP :REM
item(row, column) = 0 :REM
itemType (or edit) = 0
END IF :REM
CASE IS = "q"
LOCATE 10, 1
PRINT "Bye!"
END
END SELECT
LOOP
monsterData:
DATA "blind bat 21"
DATA "rat 11"
DATA "snake 31"
DATA "goblin 23"
DATA "troll 44"
DATA "bear 55"
DATA "lion 54"
DATA "sabretooth65"
DATA "elephant 78"
DATA "dragon 98"
itemData: :REM new
DATA "apple F1" :REM
DATA "bread F2" :REM
DATA "chicken F3" :REM
DATA "dagger W2" :REM
DATA "sword W3" :REM
DATA "halberd W4" :REM
DATA "smoke T1" :REM
DATA "noose trapT2" :REM
DATA "pit trap T3" :REM
</TEXTAREA></FORM>Starting from the top:<BR>You have probably noticed that,
although RND gives random effects, you keep getting the same set of random
values! This is because the computer uses a base value (called a "seed") to
start calculating RND.
<P>RANDOMIZE sets the "seed" to a new value so the RNDs will be different. The
value of TIMER is the amount of seconds since midnight. Because this value keeps
changing we use it as a "seed" in the expression RANDOMIZE TIMER.
<P>Items are addressed by using the array item(10, 10), allowing for one item
per room in the maze. There's only a 20% chance of a room having an item (RND
< .2) and then the item is identified by a number ranging from 1 to 9. More
data on the 9 different item types is READ into item$.
<P>CHR$ is used to convert an ASCII value into a character. So instead of doing
PRINT "A", we can use PRINT CHR$(65), 65 being its ASCII value.<BR>By using CHR$
we can access some nice characters for graphical purposes. To view these
characters in QBasic: Press SHIFT-F1. Choose the "Contents" box, then choose the
"ASCII character codes" box. The character with ASCII value 2 would make a nice
PACMAN.
<P>Each "item" has a name, class and value. The class shows whether its food
("F"), a weapon ("W"), or a trap("T"). The value is used differently for each
class: <FONT size=3><XMP>class: food Value: number of health points gained by player
weapon new "weapon" value for player
trap number of health points player will lose
</XMP></FONT>LEFT$(a$, 10) is the same as MID$(a$, 1, 10), in other words it
just starts at the first position in the string. RIGHT$("ABCDE", 3) gives "CDE",
in other words it takes the rightmost 3 characters.<BR>You can use MID$ instead
of LEFT$ and RIGHT$, but its possible to save time by using them.
<P>The "trap" item immediately damages the player upon entering the room. The
trap is then disabled by removing it from the array (item(row, column) = 0)
<P>RTRIM$("ABC ") gives "ABC", in other words it removes the spaces on the
right. LTRIM$ work in the same way, but removes spaces from the left.
<P>I added some interesting checks for when a player takes an item. If he takes
food and he has no wounds (health = 20), the food goes to waste. If he tries to
take a weapon thats rated worse or the same as his present weapon, he is
stopped.
<P>This concludes our RPG.<BR>Tomorrow I'll illustrate a few commands for
generating graphics.
<P>
<HR SIZE=5 width="80%">
<H3>Week 2, Day 5</H3>I'll demonstrate manipulation of a simple graphic by
putting the screen in graphics mode (its usually in text mode), drawing the
graphic, grabbing it from the screen and storing it in an array, displaying it
again from the array while shifting its position from the left to the right of
the screen. (I have a long breath!)<BR>Here goes:
<FORM><TEXTAREA cols=70 name=code rows=20 wrap=off>REM SCREEN mode number
REM 1 = CGA 320x200, 4 colors Graphics mode
SCREEN 1
REM COLOR palette number, background color
REM 0 -> black, green, red, brown 0 to 15
REM 1 -> black, cyan, magenta, white
REM color = 0 1 2 3
COLOR 0, 1
xDim = 16: REM The width of the image in pixels
yDim = 16: REM The height of the imgae in pixels
REM Use this formula for calculating the size of the array needed to store
REM the image. The size is measured in bytes.
size = 4 + INT(((xDim + 1) * 2 + 7) / 8) * (yDim + 1)
DIM pic(size / 2) AS INTEGER: REM An INTEGER is two bytes in size
REM Draw a block 14x14 pixels in size and fill it.
REM LINE (startX, startY)-(endX, endY), color, BF=block fill
REM The entire screen starts at (0, 0) and ends at (319, 199)
LINE (1, 1)-(14, 14), 1, BF
REM Get a 16x16 image from the screen and store it in the array pic.
GET (0, 0)-(15, 15), pic
CLS
FOR count = 0 TO 320 - 16
REM Put the image on the screen. PSET makes it overwrite the previous image.
PUT (count, 90), pic, PSET
REM Slow down the computer. Make the value bigger if its still too fast.
FOR nothing = 1 TO 100
NEXT nothing
NEXT count
END
</TEXTAREA></FORM>The REMs explain nearly everything.<BR>Experiment with colors
by choosing one of the two sets (four colors in each set) by modifying the COLOR
statement. Then choose between the four available colors by modifying the LINE
statement.
<P>Why did I draw a 14x14 image but stored it as a 16x16 image? That way the
stored image is surrounded by a "frame" of black dots. When moving the image
around, the black "frame" deletes the previous (old) image.<BR>So I'm displaying
the image in its new position and deleting the old image at the same time!
<P>You could make more interesting images by using the PSET command which places
dots on the screen. Type (or edit) and RUN:
<FORM><TEXTAREA cols=70 name=code rows=20 wrap=off>SCREEN 1
COLOR 0, 1
xDim = 8
yDim = 8
size = 4 + INT(((xDim + 1) * 2 + 7) / 8) * (yDim + 1)
DIM pic(size / 2) AS INTEGER
RESTORE pacmanPic
FOR row = 1 TO yDim
FOR column = 1 TO xDim
READ picData
PSET (column, row), picData
NEXT column
NEXT row
GET (0, 0)-(xDim - 1, yDim - 1), pic
CLS
FOR count = 0 TO 320 - 16
PUT (count, 90), pic, PSET
FOR nothing = 1 TO 100
NEXT nothing
NEXT count
END
pacmanPic:
DATA 0,0,0,0,0,0,0,0
DATA 0,0,1,1,1,1,0,0
DATA 0,1,1,1,2,1,1,0
DATA 0,1,1,0,0,0,0,0
DATA 0,1,1,0,0,0,0,0
DATA 0,1,1,1,1,1,1,0
DATA 0,0,1,1,1,1,0,0
DATA 0,0,0,0,0,0,0,0
</TEXTAREA></FORM>Storing the pixels as DATA beats doing every one with the PSET
command! Try changing the picture DATA using the values 0 to 3.
<P>Just by changing yDim and xDim and the DATA you can now design and display a
bigger or smaller picture.
<P>
<HR SIZE=5 width="80%">
<H3>Thats all folks!</H3>Hope you enjoyed the course - I can honestly say that I
enjoyed writing it.
<P>If you have any comments or questions you can E-mail me at my Internet
address: avw@mickey.iaccess.za
<P>or you can reach me by snail-mail:
<P>A. van Wyk <BR>105 Sidvale Court<BR>Parow <BR>7500 <BR>Western Cape <BR>South
Africa <BR>
<P>If you have found the course useful and would like to see further modules,
just let me know!<BR>Time allowing and if there is sufficient interest, I will
expand on the course.
<P>Cheers for now,<BR>Andre </P></BODY>[/HTML]
ممنون. جالب بود