QB Express
Issue #25 ~ October 31, 2007
"A magazine by the QB community, for the QB community!"
In This Issue
Editors
- Pete Berg
- Imortis Inglorian
- MystikShadows
Contributors
- Deleter
- redcrab
- Lachie Dazdarian
- notthecheatr
- Dean Menezes
- Codemss (RubyNL)
- Mentat
- Pritchard
- Michael D.
- sir_mud
- Regular Columns
- Articles & Editorials
- Tutorials
From The Editor's Desk
Written by Pete
HAPPY HALLOWEEN!
Welcome to a spook-tacular, spine-tingling Halloween issue of QB Express!
Okay, granted, the issue really has nothing to do with Halloween other than this opening letter and it's just a coincidence that this issue is coming out on October 31st (since I was too busy to release it earlier)...but HEY, why not celebrate if we have the chance?
In honor of this special day, I would like to bring your attention to one of the forgotten gems of the QBasic community, that 1994 horror adventure hit, Haunted Halloween by Jason Jackson.
It's an epic and scary adventure, all right. Here's the setup:
IT IS HALLOWEEN 1994, AND YOU AND A FRIEND HAVE BEEN INVITED TO A HALLOWEEN PARTY. WHILE DRIVING DOWN A ROAD AN ANIMAL JUMPS IN FRONT OF YOUR CAR. YOU SWIRVE TO AVOID HITTING IT. IN THE PROCESS YOU GET TWO FLAT TIRES. YOU LOOK IN YOUR TRUNK ONLY TO FIND ONE SPARE TIRE. YOU SEE A HOUSE IN THE DISTANCE, AND DECIDE TO GO GET HELP WHILE YOUR FRIEND STAYS IN THE CAR.
And what follows is, as you can tell by the screenshot below, probably the scariest adventure you will ever face in your life!

Download Haunted Halloween here: HH22.bas
On a side note, I believe I neglected to tell you the full title of this game: Haunted Halloween - How to Abuse the GOTO Statement. If you're looking for the perfect teaching primer on how to create spaghetti code, this would be it! Be sure to check it out, definitely worth a look.
Anyway, lots of good stuff this month...but you already knew that. Enjoy QB Express #25!
-Pete
A big thanks goes to Imortis Inglorian for doing just about everything this month except for write a few lame little bits like this one, heheh.
Submit To QB Express
You all know the drill. This magazine can't exist without people SUBMITTING articles, editorials, tutorials, reviews, news and feedback. This is not just a solo effort by me... it's a group effort by people throughout the QB community. If you have anything to submit, or have time to write something, DO IT!
If you want to write about something, but can't think of a topic, or need inspiration, check out the "Official QB Express Article Requests" thread! There have been quite a few articles requested -- and even if none of them strikes your fancy, we can help you come up with something that you would like to write about. If you're interested in getting your own monthly column or just want to write an article or two, by all means, do it! Anything that is submitted will be included!
I also want feedback and letters to the editor regarding this magazine. I want suggestions and critiques. What do you like? What don't you like? What could be done better? Let me know!
All submissions and feedback can be sent to qbexpress@gmail.com. You can also PM me on the Pete's QB Site or QBasic News message forums. If QB Express is going to continue to be so good, YOU need to contribute!
-Pete
Letters
Letter From Lachie Dazdarian
The usual congratulations on the last issue are in order. I
can't compliment you much on the News Briefs as I compiled a great
deal of it, so reading it wasn't interesting as usual. I was also
tad annoyed you missed to include my latest version of News Briefs
which included news on ciw1973's compo (really nicely compiled) and
dozen of nitpicks on other news. And they were sent few days before
you released issue #24. Oh, well.
Anyway, really nice content in the last issue.
Qlympics results were interesting to read. I was somewhat annoyed
with few winners, but that again is the result of few poor nomination
choices by my opinion. ZeroG is really far from the best action game
for that period of time. I mean, I can't even try to compare it with
TerraScape. But it seems a great deal of people simply WANTS to ignore
TerraScape for some reason. But if not TerraScape, Squealer TNT was a
much better choice too. Call me moaner, but I just don’t get this.
Also, I think most were too trigger-happy with Lynn's Legacy giving
it few undeserved awards. I'm mainly referring here to sound, where
The Quest For Opa Opa convincingly features the best work.
YAGL is another poor choice. A library that was soon abandoned after
first half-baked release, a library in which nobody coded anything notable
or complete, and a library that is basically a front-end for OpenGL.
Other choices are fine by me and I don't have anything to complain there. Yes.
Now I know I'm repeating myself, but this job should really be left to a panel of
judges who, if can't be objective, at least will play/test/read all the nominated
entries.
To continue.
It was really nice to see another game design related tutorial in the magazine.
Very nicely written article Joe King, and thank you for that.
RubyNL’s tutorials were a rather refreshing addition to the magazine, especially
in the style they were written. To bad they were for QB. :P
Also, interesting to see Pritchard’s articles in QBE, wouldn’t you say so?
I didn’t get FBHacker Series tutorial. It seems like a joke to me, but the author
appears to be more serious that he should. It’s just that sort of content I wish
people would think twice before submitting.
Anyway, good luck with this and next issues.
See you around.
Lachie Dazdarian - The Maker Of Stuff
Thanks for the feedback, Lachie! As for your assessment of the Qlympics results, I agree with you on many points. The best nominee (in my opinion) didn't always win, and Lynn's Legacy probably got a few too many awards. But then again, we awarded everything democratically, by a popular vote, and so the results showed us how the community as a whole feels - not just a few "elite" judges.
There's certainly a lot of value to a popular, democratic process. Then again, I personally prefer having a panel of considerate judges, because it usually results in every nominee getting a fair shake, and the best of the best, even if it's less popular, getting recognized. I bet most of the voters hadn't played even half of the games on the ballot, and thus voted for the ones they knew, based on name alone (Lynn's Legacy, The Griffon Legend), and some really quality titles missed out as a result.
In film, it's the difference between the People's Choice Awards and the Oscars. Which do we take more seriously as a culture? The democratically-awarded trophies that go to whichever movie had the best marketing campaign, or the awards carefully considered by a panel of industry experts? The people don't always make the best choice.
-Pete
Letter from MystikShadows
What a read this one was. It always amazes me to see just
how much creative power there is in all that contribute. Just
look at all the stuff there was for us to read this issue? I
mean wow. Two thumbs up to everyone involved. 24 issues now,
and a 25 that pomises to be yet another classic. QB Express is
breaking alot of records and getting the expectations of it's
users to a higher level with all the great contents. I think
the contributors are definitaly attempting to respond to that
higher expectation in a great way. As I said before, we're all
growing, we're all doing different thinng (me taking on a game
project like Color Triple Yahtzee! is a good example of that
hehe). with these new directions comes new needs, new research,
new subject that need to be talked about, discussed, taught
(in he form of new tutorials) in subjects that just weren't
talked about before. As we can all see here, this is being
covered bery nicely by the contributors, all of them.
First, the QLympics, You know, it seems alot happened since the
start of this great idea. including the one year hiatus of QB Express.
To me, I think thtat was the part of the problem. Alot happens in a
years, and the suggestions and submissions are probably what left
QLympics fans on the drop some. Next time this event happens I think
there will be alot of new things there that weren't even considerd
before. I'm glad I got the runner up I I wonder how that's gonna
fit next year :-). But I should have more stuff in my arsenal by
then hehe. I think though that there's alot of lessons that got
learn during this current QLympics that will just make next year's
event much better than this year. In the submissions that were
made and voted for however, I think all the top winners and runner
ups (including me hehe) got their well deserved recognition. I think
it ended up beign a pretty good event even if certain things weren't
there. :-).
How about that news section? I like to think I cover the grounds
pretty good as far as keeping myself up to date on what's going on but
there's alot of thinsg I didn't know about in that news section. Alot
of great stuff, great projects, I think i'll need to work harder to
"really" keep myself up to date, or just wait for the next issue since
it's all being covered so nicely. The cartoons are great once again.
I still get a smirk from looking at diffeecult's high level programming
cartoon, I really like his humor hehe. The other cartoons were as expected,
as funny as they can, great originality, awesome stuff. And you know, when
you think about it, none of this is really surprising to see considering
where we all stand today.
One of the project news that caught my eyes is definitaly VISG GUI builder
mrhx definitaly seems to be on the right track for this. I think it's
really gonna help FB make it's mark as a true windows languages when tools
like this take alot out of Windows API coding just to get an application
off the ground. I hope this one is pushed far, it's a great idea, much
needed. Though maybe it's windows only, atleast, using the API like that,
it will make very streamlined windows applications compared to using things
likes wxWidgets on windows. So I think it's a great concept that should be
taken as far as they can.
I gotta hand to lachie, it's no wonder he has the FB Game website and such,
it's amazing how much detail he puts into all his reviews and the review on
lodestar was no exception. He has a knack for taking the good and useful
information about a game to create his review from and really knows how to
present this information to the readers. I've seen other good ones, but
Lachie really takes it home. Two thumbs up for his work. I know I appreciate
it, and I'm sure i'm not the only one. Looking forward to reading more of his
reviews. And while I'm on the lachie subject, I really liked his highscore
tutorial. I think there hsould be more tutorials that talk about these side
features that help make a game more complete, things like that highscore
feature, maybe tips and tricks or simple reviews of what people like to see
in a game. How important is the ending for example, when you loose and when
you win. How to score during the game play, who bonuses are so motivating
to try to get, and a whole bunch of other side subjects like that I think
can be quite a successful set of articles especially for newcomers to the
game development scene (like me lol).
RubyNL, I have to say it's a rather new name for me, atleast I never noticed
it too much before. But I think the time based motion & collision detection
tutorial is gonna help me, and many others remember the name well. what a
great tutorial. Great way to explain everything covered in the totorial,
not affraid to use graphics and images to make the points being covered. I
think RubyNL is gonna become quite the name if tutorials like that are
being submitted continuously. I enjoyed it from start to finish. Very well
done. Of course, the swirl effect tutorial was an interesting read too.
Yes, I wan to read more from RubyNL.
Mentat's Wireframe, I can't finish this letter before talking about that.
I was first introduced to wireframe graphics back in the late 70s with a
language called MIRA. Back then, MIRA was THE language for 3D Graphics, in
fact it was the only language for 3D graphics aside using assembler and C.
Anyway, Since then, I've read more than one book / aritcle on wireframe
graphics, and I think I can say that mentat's way of explaining it finally
kicked in for me. I learned alot from relsoft's series of course, but
there's something about mentat's way of putting it so to speak that just
made sense to the way I read I guess. :-). Great work there too.
Dean Menezes' Searching Algorithm binary tree was one of the more informative
tutorials I've read. Another fella that seems to have the knack for presenting
the theory in such a way that it becomes a natural process to absorb the knowledge
he has to sure. Systematic, from start to finish, each item either describing or
announcing what's up ahead, seems like just a great wayt o go about teaching a subject,
any subject. I definitaly want to read more from Dean, so crack your fingers and get
writing Dean ;-).
FBHacker Series: I think has got to be the most original means of teaching
programming I've ever seen. You basically learn as you play the role of a
hacker. I've been there when this idea saw birth back then. And still today,
I can't think of a more original and enticing way to learn programming. When
done, I don't have a single doubt that FB Hacker is gonna be one for the books.
It's a great concept that has all the look, feel and potential to be a real
breakthrough way to teach the subject at hand. Awesome work so far and well,
can't wait to see where it will all go.
The FBGfx buffer tutorial by Pritchard was pretty good. For one thing, the
Image datatype is a new thing to me, I didn't know about it till I read his
tutorial. I think this is a great way to allow to use and manipulate imnages.
So not only did I learn something new about FB, but I think Pritchard's described
how to use it pretty well. As the whole world knows I'm not much into graphics
(atleast not yet, lol). But yeah, tutorials like this one is what's getting me
more into the subject. So it was an interesting read for me.
Finally Stylin's XCP series is very interesting. I like where the idea came from
and so far, I really like what he is including in the series so far. It will be a great
source of information for anyone (newcomer or not) I think everyone will have something
to learn about from this series. I'm not sure what's up a head, what he wants to talk
about next, but I for one can't wait to read about it. Great idea and great work so far.
In a general way, all I can say is that it's really great seing how every article that
make up each issue is so varied but useful to all of us I think. It just goes with the way
we're all learning and where we're going with this knowledge. I can't wait to see what
the line up is gonna be in the next issue but I bet it's gonna be a perfect reflexion of
where things are abnd where we're ALL going, as it uisually been, in every issue, so far.
Great work to all and I talk to you all next month.
MystikShadows
Stephane Richard
Thanks for all the praise of last months issue. I was rather happy with it myself.
One note about FBHacker though, and this addresses Lachie's letter as well.
The originator of FBHacker, Shawn Hartnell, had not meant for all of them to be
published all at once. Just a case of me an Pete having a lack of communication.
The Original Idea was to post one at a time, and then in the next issue, post a
short tutorial like solution to the last one, plus a new one. Sort of like
a crossword puzzle.
I am truely sorry to Shawn Hartnell for my slip up on this one, and I am also
sorry to readers who may have totaly missed the point of FBHacker as a result.
Oh well. There is always the future, right?
-Imortis Inglorian (Luther Ramsey)
Letter from notthecheatr
Hey Pete, notthecheatr writing this since you said you hadn't
gotten any letters yet. Glad that another issue of QB Express is hitting the
net, though it's a shame people haven't been submitting as much yet. I hope QBE
continues to thrive, as it is (at least for me) one major benefit of the community - I've
never seen any net magazine which I enjoyed as thoroughly as this one.
I'm not sure what all is going into this issue, but I'll just talk about some
of the interesting things I've seen on the forum lately that may or may
not go into this issue. If I start to ramble, just press page down a few
times and I'll return to reality ;-)
One of my favourite things this month was all the graphics demos and
things by KristopherWindsor. He posted a bunch of them in a single thread,
some simple but some plenty interesting, then posted a really great
tutorial about how one of them works- I hope that tutorial makes it into
the magazine.
There is of course my tutorial, written for fun because I've been playing around
with particles all week and I figured if I'm going to write a particle engine, I might
as well write some tutorials alongside it so everyone can see how it's done... or how
NOT to do it, anyways :P
freeLOLcode by sir_mud has easily PWNed everyone with it's greatness, and I
suspect FreeBasic will be entirely replaced by LOLcode in the future... well maybe
not, heh.
Best of all has got to be the products of various people answering to the pointless
challenges of a certain QBasic fanatic whose purpose in life is apparently to ridicule
FreeBasic (and most of what he types is fud anyways, to quote v1ctor). As a result
of his charges, PCopy has now been implemented in FreeBasic, and much more
compatible to QBasic and useful than any other Basic language, and a
printing library has been written to make printing in Windows easier. Once again
FreeBasic stands up to the charges and more!
And of course we're starting to see playable demos for a number of games
(Pacenstein, a couple of RTS's, a space shooter) which indicates that we're going to
have some finished games coming up pretty soon... so I'd say the FB community is
alive and well, in spite of any failure on the part of people to submit to this months
QBE ;-) Don't worry, next month will probably be bigger, badder, and better than
usual, to make up for all this.
So anyways, I guess I'll finish my half-crazed ramblings... have a good month! I
await QBE 25 with bated breath! (I dunno, it's a literary cliche... I read a lot, yes
I know I'm a geek.)
I find it very cool that most of the people that read QB Express consider it one of their favorite magazines. Sure, we have pretty low readership in the grand scheme of things, but one of the most active reader bases anywhere. Here, the readers *are* the writers, and I'd say the majority of people who read QB Express every month and wait for it with "bated breath" have also contributed to the magazine.
Thanks to the Internet, we've really been able to innovate how media is produced, consumed and viewed -- and I think that's a very cool thing. Now, every month, rather than spending a half hour or an hour reading a magazine produced by a professional editorial staff that's well disconnected from the readers, we spend that time reading QB Express -- which might be a little rough around the edges and is certainly not professional by any means -- but it feels so much more direct and personal. This is "our" magazine, whereas I consider magazines created in the traditional way to be "theirs." And it's happening in all forms of media. How many of you spend more time watching YouTube videos than network television or big blockbuster movies? Sure, these viral videos are of shoddy quality, have blatantly low production values, and lack polish -- but they belong to us, the people. And it's something big companies will never quite understand.
-Pete
Have a letter for the editor? Send all your rants, raves, ideas, comments and questions to qbexpress@gmail.com.
News Briefs
Site News
- Imortis opened his personal webpage
-
Imortis, a community regular and QB Express co-editor, opened his personal website.
The site is planned to feature his tutorials, articles and programs, and he already
made a first update.
Visit the website on this link: http://www.zendurl.com/imortis/
News Brief by Lachie
Dazdarian
Project News
- MiniCalc FreeBASIC
-
Kristopher Windsor released a FreeBASIC version of his old MiniCalc program
(including many upgrades). MiniCalc is a console mode, command line based
calculator.
For a download visit this forum post.
News Brief by Lachie
Dazdarian
- FBWinPrint - A FreeBASIC Windows Printing Library
-
vdecampo released a FreeBASIC printing library. According to his words, it allows
the creation of a PrinterObject which helps in dealing with printing to the printer.
It also has some ancillary features like quick access to common dialogs like
open/save/printer/pagesetup/fonts/colors.
The current version is 0.12. For more information visit
this forum thread.
News Brief by Lachie
Dazdarian
- TOAOGS - Generic Game Server written in and for FreeBASIC
-
sir_mud released a generic game server in FB with a goal to greatly simplify
the process of making online/local network multiplayer games. The project is
currently in development, but there is a stable version available.
Visit the official project page for more information:
http://hmcsoft.org/p/toaogs.php
News Brief by Lachie
Dazdarian
- MP3 ReNamer by Rattrapmax6
-
Rattrapmax6 posted an MP3 batch renamer September 5th; it iterates
through all the MP3s in a directory and renames them to match their internal information tags. Though there are other programs that do this in Windows,
it was written specifically to provide that functionality for linux. His project
thread is here,
and the program was first uploaded to file-pasta (link may be broken).
News Brief by notthecheatr
- Prichard's FreeBASIC Torrents project
-
A know community member Pritchard started an interesting project whose goal
is for the community to share FB packages via batch torrents. The packages
are planned to contain FreeBASIC itself and FreeBASIC programs (utilities and
games), tutorials, code snippets and similar.
So far he released his first FB torrent entitled FBPackage Issue #1,
divided in several separate sections to download.
The project is still changing and developing, so visit
this forum
topic and support the project by seeding this package and posting suggestions.
News Brief by Lachie
Dazdarian
- PNGcustomfont ver.1.1
-
notthecheatr released another FreeBASIC font library, but this one is
the most complete one in FreeBASIC yet, featuring many fonts packed for
the library, plenty of examples, and a huge manual and a tutorial.
Library features, listed by notthecheatr:
- Support for 8-bit or 32-bit mode
- Loading of BMP or PNG fonts with many options
- Drawing with alpha channel or trans
- A QB-like cursor system with plenty of bells and whistles
- Clipping
- Buffered drawing
- Efficient memory usage
- Variable-width characters
- Font information is stored in an external file, not within the
image as in Draw String.
For more information look at his forum post, or
download the library here.
News Brief by Lachie
Dazdarian
- FreeLOLCode
-
sir_mud has released a library that allows FreeBasic to compile LOLcode.
LOLcode is something of a joke language, but it's powerful and fun. The forum post is here.
- CSGP : Cute Short Game Project : Announce of version 2.0
-
Yes after Over 18 months of existance... it's time for CSGP to grow
up!
Firstly by its new look , check it at http://csgp.suret.net
you can compare (for fun) with the old look ;P at
http://csgp.suret.net/indexv1.html
Secondly by its rules ... You know these strange utopic rules.
They still there but, with small changes
- Accept OpenGL as a natural FB gfx lib. (no CSGP title yet, but
...)
- Accept any FB compatible Sound Library
- Still refuse any resource files (bitmap or sound or others)
except if the program itself generate the files (ex : the embeded
level editor of CSGP Lander)
- Any GFX resolution... prefer low res, but since lander (vectorial
gfx
game) high res is better.
so to resume the new rule set version is:
- All; in 1 freeBASIC source file : one .BAS file that contains code
+
resource
- No extra library dependency : Only native FB libs except for sound
library
- Linux, Windows and as much as DOS compatible: no OS specific
API.
- no ASM / INP /OUT platform specific usage: no low level access
- .BAS file as short as possible: Comments are not counted ;) but the
idea is to have small executable
- As small s possible footprint memory usage : never waste
memory
- and of course have fun with it !
So now start a second step in the CSGP life
Enjoy and have fun !
News Brief by redcrab
Competition News
- ciw1973's competition results
-
On August 25th ciw1973 posted results on his more that succesfull
FreeBASIC game competition. The most noted competition rule was that
"pre-drawn graphics" were not allowed.
There were totally 8 entries, out of which 5 can be rendered as
complete.
ciw1973 was kind enough to award the two runners up (Mighy Line and
Zonaxtic!) with $50, together with $200 for the winner
(Catloaf 2600) as announced earlier.
The competition results, listed by final scores:
Congratulations go to Joe King for winning in a surprisingly tough
competition, and to ciw1973 for making the entire event such a success.
Check the competitions results thread here.
I think I can speak for most and say that we are impatiently waiting
for the next compo by ciw1973.
News Brief by Lachie
Dazdarian
If you have news to report, email it to us at QBExpress@gmail.com!
Gallery
Written by Imortis Inglorian
Every issue QB Express features a preview and exciting new screenshots from an upcoming QB/FB game. If you would like your game featured, send in some screenshots!
Asteroids Inspired Game
download link: Here
Notes from the author, speedlemon:
I'd like to mention that I tested it on 3 computers, and there
was a noticeable difference in the rate at which the enemies grew. In the
worst case, the game is unbeatable (still playable). Keep this in mind while
playing. However, the game, when played correctly, usually took me around
900 kills before I was able to all. In other words, you might think that
it is unbeatable, but the times that I beat it, it took me a good 5 minutes
or so (and the 5 minutes will be boring....) on design:
well, on this game, there wasn't one. I just started making it. That will explain the poor gameplay, etc.
I didn't make the graphics for this game-- You may or may not recognize them from Angband.
I took the time to play this little gem, and I must say that it's really
quite fun for it's simplicity. Aside from a few speed tweaks that need to be done and
some custom graphics, I'd say it's worthy of a play. If nothing else it will show you what
allegro can do.
More information can be found here.
The multi-faceted nature of games: the Dream, the Design, and the Reality:
Or how to stop hating your game and give it the attention it deserves
By Deleter
Now, I’m probably not the best person to be writing this article, as I
haven’t finished much of anything. On top of that I am planning to draw
analogies to real life things that I don’t any experience with, but to
present them as if I knew what I was talking about. If you are still here
then good, you’ve probably read my other stuff and are already used to the
fact that this is always true whether or not I say it. So onto the actual
article…
…So now, what is this three part description of a game, and why do you care?
Well the first part is obvious: The Dream. Everyone has them, many of them, in
fact sometimes it feels like there are too many of them, as everyone and his
nine-fingered sister has their own set of ideas for games. Dreams are the things
that make you go through the grueling process of coding and debugging. Dreams are
in short your games soul. They are the thing that all games start out as. And as
they are the most numerous, they are also the most fragile. Countless game ideas,
great ones included have been discarded on the side of the road, left to die.
Of course, some might view this as mercy compared to the necessary process of the
next step. It can be such a rigorous process, that some dreams are viciously ripped
apart by it and their creators are mentally scarred for life. This is the creation
of the Design. See, in their natural state dreams are like the random scraps that
hotdogs are made out of, though a lot more desirable. In fact that’s a horrible
analogy, but in any case the point is, dreams are not fit for consumption. They
need to be translated from the dream world to our world. This is the process of
designing. The important thing to consider is how you do it. Just plopping down
your dream into text will bring it somewhat into reality, but often this is a bad
way of doing it and leads to problems down the road. Now that’s not to say you
shouldn’t write down your ideas, it’s a good idea to start by doing that. But if
you really want to do it justice, you should do a lot more.
First of all, what is even more important than the idea is the idea of the idea,
your dream’s soul that is. What the heck do I mean? Well basically, if your dream
was murdered, what part of it would you remember? What is its essence? What is the
central part that all other parts of it point to? If you sat down in an interrogation
room with your dream and asked it who it really was, what would it tell you? If you
can answer any of these questions, the answer is your games soul. Finding it can really
be a pain, and sometimes your dream won’t make it out of that interrogation room. But
if the two of you come out alive, you are on your way to making something great.
So now that you have your game’s soul firmly in your grip, what now? Now you brainstorm,
find every possible element and part of your dream that complements its soul, and refine
the elements you had already thought of. Basically, build up your game idea, refine
your game idea, make your game’s soul shine. Now this process never ends throughout
your game’s life cycle, but the more you do in the beginning, the less refactoring
and reprogramming you are going to have to do, which is a plus. Once you are fairly
confident in what you have, make your design document. This is taking your concepts
and ideas, and bringing them into code/modeling/hard-core designing world. Write
some specifications for things, some implementation ideas, etc. There are much better
and more detailed guides for this process elsewhere so I won’t bog you down with a
mediocre one.
So now comes the real work. Yeah, you thought everything up to this point was hard?
Well give up now if you aren’t ready for a hundred-fold of everything you’ve done up
to this point. Still here? Good, games need dedication and perhaps a bit of
foolhardiness. If you are reading this you probably have some of the latter at least,
since you saw my name and still kept going. Now this isn’t a technical article, again
there are plenty of those, and even if they all suck that’s not what this is and if
that’s what you want then annoy me enough and I might consider writing something in
that vein, well that or adding you to my spam filter list. Instead I am going to try
and discourage you from writing your game. Not intentionally mind you, there are far
too few indie games as it is, but simply as a side effect of giving it straight as
it is.
Basically, making games is like having children. If you can’t help but love it, while
at the same time knowing every one of its flaws, while having it treat you like shit,
and still give it your all and more, then your game stands a chance. You may think
that sounds stupid or is wrong, or that I have no clue what I am talking about as I
have never had any children, and while that second point may be true, the first one
is not. You have to love your game and be dedicated to it if it’s going to make it to
completion. Laugh if you want, but I will only laugh back when your game becomes
nothing but lost bits after you erase it on your hard drive.
So again you are forced to do what you really don’t want to. You must know your game
in and out. Don’t lie to yourself about what sucks, know it. If you can, make it
better, but first thing always know everything about your game. No one should be able
to point out a flaw that you aren’t already aware of. Now I’m not talking about
programming bugs. I’m talking about design and implementation issues. The loading screen
is annoying, the so and so sound pisses people off, the reload counter is too long for
this, but can’t be any shorter because of this. This feature has been done better
already in other games, etc. The tricky part is admitting all these faults to yourself,
and still loving what you have. Know the good parts as well. Know how innovative your
control system is, know how good the explosions reward the player, know how well your
enemy designs stick in your player’s mind. Every change you make know what it makes
and what it breaks.
Now that you have it, use this knowledge to the best of your abilities. Balance elements
against each other until your game is as optimized as possible. Sometimes you will realize
that a certain feature has to be cut, or another one added for the good of several others.
It’s ok to do this now, though the sooner the better as it will mean less re-doing of stuff.
If you don’t like your game, know what you don’t like and make it better. And get outside
opinions, always get outside opinions. I have always found in the act of creation that my
own idea of my works is often skewed. I’ve liked what others haven’t, and found that things
I didn’t care for as much were generally enjoyed. As far as releasing is concerned what can
I say. You will never feel like your game is really ready, but at some point you just have
to come to terms with reality and release it. Fix up the bugs later if needed, make tweaks
whatever. But get it out there. Near the end of a project sometimes things get slow and this
can really invigorate you. I’m not saying to release an unready source, but talk with people
who have helped you and see what they think.
And with that I will leave you. I’ve already said more than I should and more than you care
to read I’m sure. Thanks if you’ve made it this far, you’ve been a great audience. Shoot any
comments to deleter8_at_gmail.com. Just don’t forget to love your game despite its flaws, if
you can do this and keep going, the world will thank you for the product you release. Good
luck and happy dreaming, designing, and realizing.
Accessibility and File Names
By notthecheatr
So you've written your first really cool program - or your
first tutorial - or your first web page. Got all those images
linked in, or perhaps you have some external .BI files included
in your program - you're going to release it on the web for all
to see. Generally you'd put these things into a ZIP, RAR, or 7z
archive (or tar.gz, or just tar, or even bz2... the list is
endless). Now presumably you want to include everyone - not
just people who use Windows. But there's a little secret most
Windows users don't know about Linux, and that is that filenames
in Linux are case-sensitive. What does that mean? That means that
"ABC", "abc", and "aBc" are ALL DIFFERENT. In Windows, this is no
problem. In DOS, no problem. In Linux, BIG problem - for when the
archive is extracted, the contents will make no sense, whether as
HTML with images or a program with external files.
Why do I bring it up? Lately there have been complaints that people
will use the wrong case. The file will be named "example.png" but in
the HTML or BAS file it's referenced as "Example.PNG" - or something
similar. Once again, this works just fine in Windows. It does NOT work in
Linux. For this reason, I stress the importance of using consistent case
throughout any project you use. In fact, unless capitalizing some letter in
the filename adds any extra meaning (usually it doesn't), I recommend you
don't use capital letters at all. In DOS, capital letters were pretty much
standard - probably to make case-insensitivity easier - but in linux, you can
have any case - but then you are case-sensitive, and you need to make sure you
get the right case. If you want to maintain DOS-similarity, you'll probably
have all letters capital and no letters lower-case. The important thing is
consistency, it really doesn't matter how you do it just so long as you do
it the same everywhere.
Of course, there is something a Linux user might be tempted to do that
wouldn't go over well in Windows - the Linux user might put several
different files with the same name but in different case in the same directory.
I can't imagine WHY anyone would do this, and I have never SEEN anyone do it, but
it is after all a possibility, and obviously this would cause major problems to
the innocent Windows user who attempts to extract the contents of that archive.
In summary: Name all files in a directory uniquely, and keep the case
consistent. This way your program, article, or web page will be accessible
to users on all platforms. Are we all agreed? Good.
User Oriented Programming
Written by Stéphane Richard (MystikShadows)
INTRODUCTION:
When you are cerating your applications or games it's very easy to drift off from the one important fact you should
never drift away from. Let's rule out your own personal projects that you make for yourself and yourself only. What's left? The projects (applications, tools, utilities or games) that
you make for other people to use or play with. Believe it or not, this can make the impact of your program that much different to the users
of it's users. User considerations thorughout your program is a way of showing that you put the extra effort in your
program to make it as easy to use or play for the user as possible.
This will be the main focus of this article. User Oriented Programming essentially means that whatever part of the program that needs something from the user needs to consider certain things. This can depend on more than one thing. But in general there's always a way to improve how your programs interact with the user.
We'll look at what can need user interaction, what's good to give back to the user, what's overkill and such things so that when you make your programs you can make sure to consider what you need to make using your program as pleasant as possible to the user. So let's get right to it.
USER PRESENTATION:
This is usually the first view that users get of your program. Attention to detail from the very start can make or break the success of your programs. This is regardless of it's it's a GUI application or a Text based application you still need to take care to present your application the right way to the user.
How can you tell how things should be presented? There's moer than one criteria to help you determine this. Let's take a look at them.
- What Type Of Program Is Being Presented:
If you're program is a game, it's important to give the user the impression that it's a game as soon as possible. A user shouldn't start your program and get the wrong impression from it. Same thing goes for business applications as well. If you are creating a spreadsheet application, it's good that the user sees that it's a spreadsheet application from the very first screen he'll see appear. The best way to get an
idea of how to present your program is to take a look at how other programs (much like yours) are presented. For example, if You open Microsoft Excel, when the program appears, you're in an empty spreadsheet document, you can see what you can do next pretty much fromt he very start. Same thing for Microsoft Word. Basically, you need to take the main function of your program as the guideline to what the user is going
to be seeing and allowed to do (more on this later).
- What Part Of The Program Is Being Presented:
This is where you decide what happens first and what happens next. Typically, in a game, you'd present the main gaming menu (maybe after a title page) from where the player can create his profile, start a game, view the highscores, etc. In a business application there's a couple more things to consider. When you start any Microsoft Office application, you are essentially taken to a new empty document/database/spreadsheet/presentation. This makes sense because each of these
applications deal with one thing only. In Excel, you'll be doing spreadsheets, that's all. On the other hand, if you take an accounting or business management package and start that, you'll typically be taken into somekind of menu because you'll usually have more than possible thing that you can do. For example, create customers, create invoices, manage your inventory and the likes. So you need to consider what your program has to offer to it's user. Are you managing more than one independant item in your program? Questions like this one can really help
determine what the user sees first.
- What is Important To See First In That Part Of The Program:
Let's use a billing system to best illustrate this. There's more than one available and when you open those modules up, you can be taken to two possible things. The first is an empty invoice waiting to be filled. Or, you can be taken to a list of existing invoices. Both are good methods, some creators simply though thta creating an invoice as soon as possible was important while others believed that seeing your invoices (and searching for them) was more important. Is one better than the other? I think in this case both can be very userful to have. Eventually you just need to reach a decision and follow up on it.
Once you worked out these starting issues, it doesn't stop there. I guess you can say that user oriented programming is kinda like error management, it's a big job to integrate after your program is done so it's a good idea to start your programming project with these items in mind right from the start so that the work can be integrated into the regular programming tasks and hence not seem as big as it is. The general rule of thumb to remember for these projects is: "The easier you make it for the user, the harder you make it on you, the programmer.". Knowing this, since you already know you have big job ahead of you, you might
as well break it down into small manageable parts throughout the project rather than putting it all in at the end of the project. You'll thank yourself later. Now what are the next steps? The very next step is all about where thinsg should be and how the user can access the features of your program.
USER NAVIGATIONS:
Once the user starts your program, it's very important that he doesn't have to look too long to find out what he's supposed to
do. One of the key things to remember is that everything should be acessible while at the same time not being hidden within to many levels if menus or sequences of actions fromt he user.
The main reason for that is that not many users like to have to remember six sequences of keys before they can perform an action. Since this is an article
on user based programming we'll be putting the user first here. Hence, if you want to know what the user might want to do, where he might expect things to be and the likes, there's more than one tool
to get that information. Let's take a look at some of the more common ones.
- You Are Your First Source Of Information:
Yes, that's where it all starts. You're a user of some application or another. You have your own expectations and wants when you open an application or game.
Hence when you create a game or program that will be used by others you need to take the time to use it yourself. IF you find a certain feature is way to difficult to reach or has to many steps to it chances are your users
are going to think the same thing. If you don't have a feature and wish you did put it, again, other users are probably going to want that feature too. So what you want as a user is the first
step to making a programs other will want to use.
- Pools And Surveys:
Of course, no one expects you to know everything that everyone might possibly want in your program. IF you happen to have a website or have access to a website it might be a great idea to create a survey (or more than one) about your program.
Ask the questions that you have doubts about and always leave a space to let the ones filling in the survey tell you what they think of the feature and why it must/should be there. Hence alot of the questions you might ask that offer a set of choice
in them might benefit from having an "Other" selection with a text box to let the user enter what they mean by other. The idea of the surveys to get answers to your questions fromt he perspective of the potential users so what they want is important as
it will tell you if you're on the right track or not. This means that the earlier you know what the users think and want, the fater you can change your program to accomodate that.
You can go on rtelated forums and ask questions there too without creatign a survey per se as well. Just make sure the forum is relevant to your project somehow to get at least a minimum of interest on the part of the memebers.
- How Do The Other Programs Do It:
If you know of a program that does a similar feature (or atleast a program that is aimed at the same industry or tupe of user you are aiming for) if you cna see how they do it, it might e a first vital hint as to how you should present your own feature.
IT gives you an idea of how high up in the priority list the feature is considered for one thing. There's a common accepted standard that says the easier it is ti reach a feature the more important it must be. Sure it depends ont he program you're looking at but all in all
you can learn alot from another program. Including if a feature should be there or not. If you don't see a feature in a similar program, maybe they have a good reason not to have it there. This can play both ways, maybe they didn't think of that feature at all which ends
up giving your project an edge if the feature is that important. So taking the time to look at other proejcts might prove more beneficial than you might think.
Of course, you can also ask friends, co workers, and other people live, in person or by telephone if you want. When it comes to gettign the answers you need for the success of your project I think there's no limit to what you can do without being considered a spammer. The earlier you can do this in your programming effort the less work it becomes to
take this new found knowledge and implement it in your own project. So then, assuming you did all this and you now have all the features you want to put in your program you need to define where they go and why. Here again you have more than one possible means of presenting the features. Let's take a look at the two most widespread ways of organizing an
application.
- The Method Based Approach:
This essential means that things are presented in the order they are to be executed. You have to create an invoice before you can print it, you might need to edit that invoice before printing it too which would give a
menu that has the New Invoice, Modify Invoice, Print Invoice in that order to mimic the way things need to execute themselves in. This is a typical scenario in alot of business applications. it's a logical way of presenting the features
that users of a specific domain are accustomed to since a lot (if not most) of the programs they user are based on this concept of sequence of steps. But oday, it is not the only way to go about things. Which brings the next item in this list.
- Using The Right Metaphore:
Yes, a metaphore, many programs can benefit form one of these. For example, Windows that most of your use to day is beilt around a metaphore. In the case of Windows it's a desktop metaphore. They try to mimic how you do things on the top of your desk. Today it's hard to imagine Windows working any other way. This concept of using a metaphore can be
one of the best things for your projects because it's becoming a growing want of the users. They don't want to use your program, they want to experience it so to speak. Taking the time to see if a metaphore can and should be used can prove one of the best
decisions you make for the success of your project.
So then, at this point you0 have your list of features, you hopefully made a choice as to which of the two methods above you will use for your project. All this should also give you a good base idea of the structure of your menus and overall user interface so far. Typically, everything that follows here is based on whether you used the Method Based Approach or the Metaphore Approach to your project. So what come snext
will be explained under both methods whenever it's necessary. The next step is to start implementing the features themselves, and yes, the method used will help define alot of what the data entry screens will look like and how they will behave, same thing for how reports will get generated (or how the sub sequent game screens would/should appear. What else is tehre to consider? Funny how I used consider here because
the next step is exactly that, User Considerations. But before we get into that let's take a little time to define what the users really are.
TYPES OF USERS:
Throughout your project development you need to remember that all in all, there are two distinct types of users you'll be coding your project for. In each of these groups there are sub groups that determine alot of things for you. But all in all everyone can be classified under the following two groups.
- The Mouse Users:
These are the people that don't believe a computer is complete without a pointing device. They are typically people that believe that
if you can't do it with the mouse, you can't do it at all. And yes, they exist out there. The main thing to consider for these users is to
make use of the mouse on atleast every important feature of your program while keeping things on par with the method used (method or metaphore) then
your mouse users can do what they need to and won't complain too much if a specific feature can't be done with the mouse (such as data entry screens but that too can be mouse oriented to a certain point.
- The Keyboard Users:
Of course these users don't care much for a mouse. Everything has to be done with keyboard and keyboard shortcuts. They love the function keys and well, every other key they see on a typical keyboard. They do not however like to relearn everything. So although the keyboard is
a must for all the features, it's important to keep things consisten trhoughout the project, as in, if one module uses F2 to open a file, any module in that program that need to open a file should also use F2. I believe that with just a bit of common sense you can create a very useable keyboard standard.
I may have exagerated my descriptions of these users, but the point of this article is to accomodate both extremes of the user base you might have to deal with. The bottom line, if your program works with the mouse or keyboard you can get that many more users just because of that one considerations. People like to work they way they work and
trying to impose a give way to them won't make them to fond of your prorgam. Is there certain projects or specific task that just acn'e be accomplished witht he keyboard or the mouse? Depending on the project I have to answer yes to that question. More often than none however you can and should accomodate for the keyboard and the mouse by default. And in the unlikely event that something needs to be done with only one of these input devices, state it clearly on the screen "this operation must be performed with the keyboard" so that the user doesn't need to try to do it with the mouse if he can't. (see the user feedback section below for more of these user feedback tricks.
And now let's take a look at what other considerations you can do for the users.
USER CONSIDERATIONS:
Are you thinking something like "Hey, did I do enough of that so far?" the answer is no. Let's not hide the facts, you're probably doing this project not just for others to use, you probably want to use it yourself too. Hence you might have your way of doing things and you'd like to see them in there right? At least some of them right? So where do you draw the line? The answer is you don't. But it doesn't mean you can't accomodate yourself
too in this. Back in your surveys, you could suggest your method of doing it, and seeing if people agree with them or not. Leave them as suggestions however, not as set in stone methods of operations. IF you like it that way, chances or so will others. Who knows, you might be lucky enough that the way you want everything to work is ok with your potential users so it's not a bad idea to suggest your ways as at least some of your potential users
might not have an idea of hwo to use the feature and might think your way seems logical and good.
I already mentioned some considerations throughout this article so far. Things like keeying the features as directly and quicly accessible as possible to minimize keyboard or mouse actions is one of them. Another one I mentioned is to keep things consistent (such as the F2 key always being used to open files and documents). These are very important things to consider. There is more hwoever. Let's take data entry into considerations. Data entry screens are of course the most user specific programs to write. Data Entry typically implies that something will get saved to somekind of file and hence the data provided by the user is very important. Users are human however, they do make mistakes
and as such there are more than one trick to help make lower (or sometimes even eliminate) human errors. They have a great deal to do with the controls you use on the forms in most cases. So let's see what role these controls play in the data entry process. This of course can be used in Text Based user itnerfaces and in Graphical user Interfaces alike.
- A Regular Text Box:
This is often used for to many purposes. There is no validation per se here. The user is allowed to enter pretty much whatever he wants into this type of coutrol. This could be used for fields suck as name, notes, and other information. For most other types of fields one of the following is probably a much more recommended way of entering values.
- Masked Text Box:
Even back in the days of DBase and Clipper (back in the 80s) this type of control has always been used to help minimize human error. Masked Input Boxes are created to allow only certain keys to be pressed and if there's a certain visual representation that need to be abided by, the Masked Text Box can be used fort that purposes too. Things like Zip Code, Postal Code (canadian zip codes), telephone numbers, Social Security numbers, credit card numbers and things like that can definitaly benifit from a Masked Text Box.
- Check Boxes and Radio Buttons:
These are controls that typically have 2 values, they are either selected or not, In the case of check boxes, each checkbox can be selected or not. Useful for quick options that can all be selected or not. Radio bottons are different from CheckBoxes because they only allow one of the list of radio buttons to be selected. If you have a list of fixed values from which only one can apply at one time, Radio Buttons are the type of control to use (provided not too many of them are needed.
- The Combo Box:
This is represented by a text box and a list of selectable items that can be brought down to allow to pick one of the available options. They can be play the role of Radio Buttons when you have a long list of possible options where only one needs to be selected.
- The Scroll Bar:
If you have a field that can only have a certain range of numerical values (for example a volume control for a MIDI player you are making) a scroll bar is a great visual way to allow the users to enter a value instead of keying it in directly.
There are more controls but typically the play the role of one of these. Things like Date Drop Down which are a Masked Text Box with a buttom on the right side to make a calendar appear to allow to select a date. And others. Basically, since these controls can be used it becomes impossible to enter a wrong value into the system thus eliminating human error (or at the very least keeping human error to a strict minimum. After that is in place, you can of course add data validation to the whole screen. For example, if certain fields must be entered (known as mandatory fields) you can do a check before exiting the form or saving the data to make sure that these fields really do have values in them and warn the user if they are missing. The combination of these two elements will make sure that what gets saved is valid.
And if there's valid data to begin with, chances are, valid data will come out of the system. So when data is a high priority element of your project, these techniques can really help you make sure that you get only good and valid data to begin with, to process, and most likely valid results from them (if you're making a report or something). There's one more form of user oriented programming I want to cover in this article and that is, of course, user feedback.
USER FEEDBACK:
Did you ever call the support department of a company, any company, got left there for a few minutes or a 1/2 hour without no one telling you what's going on? How does it feel? Did you know that your program, unless you make it do things otherwise, will treat your users exactly that way? In a sentence, this is what user feedback is all about, not leaving the user in the dark. Making sure he/she knows what's about to happen (especially of a complex process is about to occur). Letting them know how things are going, let them know if their choice was executed successfully or if a problem occured. user feedback has been implemented before, you can probably learn a whole lot about what type of feedback you need to include just by looking at other programs. User feedback is a very important aspect of any projects that will be used
by other users (this includes games and applications).
There are many things that can happen in a program. Some require more or less feedback to the user, This is were common sense and a bit of background knowledge is needed to determine where and when to give the user feedback. Here are some of the major situations where I believe user feedback becomes almost crucial.
- When Something Is About To Be Deleted Or Overwriten:
Whether it's a record in a database, a file or anything that already exists it's important to let the user know what he's about to do and give him a chance to cancel or confirm the operation. a message like "you're about to delete something" isn't good enough either, you need to give him more information like what exactly is about to be overwritten or deleted so that he/she is well informed to make his/her decision to overwrite or delete the item in question.
- When Something Is Going To Take Some Time:
Needles to say that if a process can take several minutes to complete it goes without saying that the user will want to know about it before the process occurs. In these cases I find it important to do the following. First, let the user confirm that he wishes to start the process. If he chooses to execute the process, given a progress of what's happening, a progress bar is a great way to do this so he can see quickly how much longer it's going to take. And a message at the stating that the
process finised successfully or what errors occured if any.
- When The User Is Expected To Do Something During A Process:
If the program needs the user to do something (enter values such as criteria for a search or a range of records to consider for a report, he should know so right away so he can provided the expected information and get the process started. like the above point a progress bar (if it's a lengthy process) and a message stating if things were successful or not and why come highly recommended. It's really all about making sure the user knows three things. 1. What's about to happen, 2. What is happening, 3. What happened. By folliwng these wherever an important thing is about to occur, it will help your program be that much more successful to the eyes of your user as they will not be left in the dark. Likewise, giving the right information will help them help you if they call you with one of these problems.
User feedback is a must, it's really the best thing to remember from this article. To determine what needs to be done where, put yourself in the shoes of your users. Try out everything before you publish your program. Once again, if there are places where you would have liked to know about something before executing a certain part of your project, chances are, yoru users will probably expect that too. So taking the time to see what's happening where and how important it is to you to know about them is a great first step to making sure user feedback is adequate throughout your project.
<.p>
Another important thing is that if one of the feedback means that the user can't perform his selected action to let him know, if at all possible, why he can't perform it. Maybe there's no paper int he printer, maybe the record he's working with is locked by some else in the syustem and he has to wait for that user to be done with that specific record, maybe the system resources are inssufficient for the needs of the application. No matter what the reason, lettign the user know will also help him make sure he can perform the action which is, let's face it, the main reason why he's using your application in the first place. So when you can know the reason why, don't be affraid to share it witht he user, he'll only appreciate your application more because of this little consideration.
AND IN CONCLUSION:
As you might have noticed, most of User Oriented Programming items I mentioned here involved more common sense than business knowledge per se. As a final note, I'd like to talk about business knowledge itself. In one speciial form. If your program is an accounting system, it's important that the terminology you use reflect the terminology used by your users (in this case, accountants). Just that fact, keeping the terminology domain specific like that, can often give the impact you need to make your program stand out from the rest as far as user consideration goes.
Hence you need to learn enough about the domain your project is created for in order to use the right terminology that your users, in that field, will expect to see. It's a small form of respect if you will, for the knowledge your users have and are accustomed to work with. It doesn't take that much time to learn the right terminology, and does make a big difference in the impact of your project. So it's a quick and valuable tool for your creations.
I could probably write a whole book on just this subject alone, there's so many considerations involved when creating an applciation for your users. I hope this article opened up your eyes and your mind for your future projects. However, it's very possible that I've left something out, or didn't detail a specific aspect enough. IF you want more details you can email me (email is below my signature below). And talk to me about it, if there's enough grey areas I will create a 2nd part to this article that will cover them. This subject is important in all your projects that you want others to use so let me know if there's somethign you'd want to know more about that has been mentioned here. Until next time, happy reading and coding.
MystikShadows
Stéphane Richard
mystikshadows@gmail.com
Fun with Recursion
Written by Dean Menezes
What is recursion? Well, according to Wolfram
Mathworld (http://mathworld.wolfram.com/), recursion
is
"A recursive process is one in which objects are
defined in terms of other objects of the same type.
..."
What does this mean?
Well, let's look at this recursive factorial function:
FUNCTION Factorial (i)
IF i=0 THEN
Factorial=1
ELSE
Factorial=n*Factorial(n-1)
END IF
END FUNCTION
Basically, recursion is when a function or subroutine
calls itself. There is also mutual recursion:
FUNCTION ODD (X)
IF X = 0 THEN ODD = 0 ELSE ODD = EVEN(X - 1)
END FUNCTION
FUNCTION EVEN (X)
IF X = 0 THEN EVEN = -1 ELSE EVEN = ODD(X - 1)
END FUNCTION
Use of recursion in an algorithm has both advantages
and disadvantages. The main advantage is usually
simplicity. The main disadvantage is often that the
algorithm may require large amounts of memory if the
depth of the recursion is very large.
EXERCISES:
1. Write a subroutine using Recursion to print numbers
from n to 0.
Answer:
SUB NtoZero(n)
PRINT n
IF n>0 THEN CALL NtoZero(n-1)
END SUB
2. Write a sub using Recursion to print numbers from 0
to n.
Answer:
SUB ZeroToN(n)
CALL XtoY(0, n)
END SUB
SUB XtoY (x, y)
PRINT x
IF x < y THEN CALL XtoY(x+1, y)
END SUB
3. Write a function using Recursion to reverse a
string.
Answer:
FUNCTION Reverse$(X$)
IF x$="" THEN
Reverse$=""
ELSE
Reverse$=LEFT$(X$, 1)+Reverse(RIGHT$(X$, LEN(X$)-1))
END IF
END FUNCTION
RECURSION PART II
By Dean Menezes
In the previous section, I gave an introduction to
recursion and had you do some short exercises. In
this section, I will show some more applications of
recursion.
Euclid's algorithm is a recursive algorithm for
computing the GCF.
See if you can write a function that does this now.
OK, if you can't, that's fine. Now read this
description:
"Given two natural numbers a and b, not both equal to
zero: check if b is zero; if yes, a is the gcd. If
not, repeat the process using, respectively, b, and
the remainder after dividing a by b. The remainder
after dividing a by b is usually written as a mod b."
Now write the function based on the description.
Answer:
FUNCTION GCD(A, B)
IF B=0 THEN EUCLID=A: EXIT FUNCTION
EUCLID=GCD(B, A MOD B)
END FUNCTION
Tower of Hanoi:
The objective of the game is to move the entire stack
to another peg, obeying the following rules:
- Only one disk may be moved at a time.
- Each move consists of taking the upper disk from
one of the pegs and sliding it onto another peg,
on top of the other disks that may already be
present on that peg.
- No disk may be placed on top of a smaller disk.
Try to find out an algorithm for solving this tower on
your own.
Answer:
The algorithm for moving h disc from peg f to peg t,
with peg r being the remaining peg is:
- If h>1 then first use this procedure to move
the h-1 smaller disks from peg t to peg r.
- Now the largest disk, i.e. disk h-1 can be
moved from peg f to peg t.
- If h>1 then again use this procedure to move
the h-1 smaller disks from peg r to peg t.
Now, modify this existing code to put QBASIC code for
this algorithm into SUB MOVEPILE. MOVEDISC is a sub
to move a disc from peg START to peg FINISH.
DECLARE SUB INSTRUCT ()
DECLARE SUB AUTO ()
DECLARE SUB PLAYGAME ()
DECLARE SUB MOVEPILE (N%, START%, FINISH%)
DECLARE SUB MOVEDISC (START%, FINISH%)
DECLARE SUB SHOWDISCS ()
DEFINT A-Z
CONST NUMDISCS = 8
DIM SHARED TOWERS(0 TO 2, 1 TO NUMDISCS), TOP(0 TO 2), NUMMOVES AS LONG
CLS
TOP(0) = NUMDISCS: TOP(1) = 0: TOP(2) = 0
FOR I = 1 TO NUMDISCS
TOWERS(0, I) = 9 - I
NEXT
LOCATE 1, 26
PRINT CHR$(218); STRING$(14, CHR$(196)); CHR$(191)
LOCATE 2, 26
PRINT CHR$(179); "TOWER OF HANOI"; CHR$(179)
LOCATE 3, 26
PRINT CHR$(192); STRING$(14, CHR$(196)); CHR$(217)
PRINT STRING$(80, CHR$(196))
PRINT
PRINT "1: AUTO"
PRINT "2: HUMAN"
PRINT STRING$(20, CHR$(196))
WHILE CHOICE$ <> "1" AND CHOICE$ <> "2"
INPUT "CHOOSE ONE: ", CHOICE$
CHOICE$ = LTRIM$(RTRIM$(CHOICE$))
WEND
IF CHOICE$ = "1" THEN CALL AUTO ELSE CALL PLAYGAME
SUB AUTO
CALL SHOWDISCS
CALL MOVEPILE(8, 0, 2)
END SUB
SUB INSTRUCT
PRINT "The TOWER OF HANOI is a mathematical game or puzzle. It consists"
PRINT "of three pegs and a number of discs which can slide onto any peg."
PRINT "The puzzle starts with the discs stacked in order of size on one peg."
PRINT
PRINT "The object of the game is to move the entire stack onto another peg,"
PRINT "obeying the following rules:"
PRINT TAB(2); CHR$(248); " Only one disc may be moved at a time."
PRINT TAB(2); CHR$(248); " Each move consists of taking the upper disc from"
PRINT TAB(4); "one peg and sliding it onto another peg, on top of any discs"
PRINT TAB(4); "that may already be on that peg."
PRINT TAB(2); CHR$(248); " No disc may be placed on top of another disc."
PRINT "PRESS ANY KEY TO CONTINUE..."
NULL$ = INPUT$(1)
END SUB
SUB MOVEDISC (START, FINISH)
DIM T AS SINGLE
TOWERS(FINISH, TOP(FINISH) + 1) = TOWERS(START, TOP(START))
TOP(FINISH) = TOP(FINISH) + 1
TOWERS(START, TOP(START)) = 0
TOP(START) = TOP(START) - 1
NUMMOVES = NUMMOVES + 1
CALL SHOWDISCS
T = TIMER
WHILE TIMER - T < .2:
IF INKEY$ = CHR$(27) THEN END
WEND
END SUB
SUB MOVEPILE (N, START, FINISH)
' Insert your code here
END SUB
SUB PLAYGAME
DO
INPUT "WOULD YOU LIKE INSTRUCTIONS"; NULL$
NULL$ = UCASE$(LEFT$(LTRIM$(NULL$), 1))
IF NULL$ = "Y" THEN CALL INSTRUCT: EXIT DO
IF NULL$ = "N" THEN EXIT DO
LOOP
CALL SHOWDISCS
DO
LOCATE 1, 1
COLOR 7
PRINT "TYPE NUMBER OF START PEG FOLLOWED BY NUMBER OF END PEG"
PRINT "LEFT = 1", "MIDDLE = 2", "RIGHT=3"
DO
KEY$ = INKEY$
SELECT CASE KEY$
CASE CHR$(27)
END
CASE "1"
START = 0
EXIT DO
CASE "2"
START = 1
EXIT DO
CASE "3"
START = 2
EXIT DO
END SELECT
LOOP
DO
KEY$ = INKEY$
SELECT CASE KEY$
CASE CHR$(27)
END
CASE "1"
FINISH = 0
EXIT DO
CASE "2"
FINISH = 1
EXIT DO
CASE "3"
FINISH = 2
EXIT DO
END SELECT
LOOP
IF TOP(START) = 0 THEN PRINT "There are no discs on that peg.": GOTO 1
IF START = FINISH THEN PRINT "The start peg is the same as the end peg.": GOTO 1
IF TOP(FINISH) > 0 THEN
IF TOWERS(START, TOP(START)) > TOWERS(FINISH, TOP(FINISH)) THEN PRINT "You may not put a larger disc on top of a smaller disc.": GOTO 1
END IF
CALL MOVEDISC(START, FINISH)
IF TOP(0) = 0 AND TOP(1) = 0 THEN EXIT DO
IF TOP(0) = 0 AND TOP(2) = 0 THEN EXIT DO
1 LOOP
END SUB
SUB SHOWDISCS
CLS
LOCATE 1, 60: PRINT "MOVES: "; NUMMOVES
LOCATE 25, 1
PRINT STRING$(80, CHR$(196));
FOR J = 0 TO 2
FOR I = 1 TO TOP(J)
LOCATE 25 - I, 27 * J + I
X = TOWERS(J, I)
IF X = 0 THEN EXIT FOR
SELECT CASE X MOD 8
CASE 1
COLOR 12
CASE 2
COLOR 14
CASE 3
COLOR 10
CASE 4
COLOR 2
CASE 5
COLOR 9
CASE 6
COLOR 1
CASE 7
COLOR 13
CASE 0
COLOR 5
END SELECT
PRINT STRING$(X * 2, CHR$(219));
NEXT
NEXT
END SUB
Answer:
SUB MOVEPILE (N, START, FINISH)
IF N > 1 THEN CALL MOVEPILE(N - 1, START, 3 - START - FINISH)
CALL MOVEDISC(START, FINISH)
IF N > 1 THEN CALL MOVEPILE(N - 1, 3 - START - FINISH, FINISH)
END SUB
Peek and poke tutorial
By RubyNL
If you have looked up some source and wondered why you didn’t found one single
PSET in it, or just wondered how to the fast, flicker-free graphics that you see
sometimes, for example in demo’s, this tutorial is the right thing to you. I’ll teach you
about peek and poke, which can be used as an alternative for point and pset, and some
other things.
What are peek and poke?
Peek and poke are two instructions that you use to look up bytes at
certain positions. With poke you can set a byte at a certain position a
certain value. With peek you look up a byte at a certain address. So, for
the clearness:
POKE position, value
value = PEEK(position)
In case you don’t know, a byte is not quite the same as an integer.
While an integer contains a value between -32768 and 32767, a byte is a
value between 0 and 255. So, these bytes are perfect to represent a
colour at some point in the screen. First, I’ll teach you how to use
peek and poke for normal variables. Before that, I have some theory
about memory for you. That means, no code yet. Sorry.
Memory theory
Something you need to know about is memory segments. A segment of memory
is a piece out of the memory. Its size is 65535 bytes(= 32767 integers). You
can only peek and poke in the current segment. The segment can be anywhere in
the memory, as long as it starts somewhere and ends 65535 bytes further. The
default segment is starts at 0, so it stops at 65536. When you need much
memory(more then 32767 integers) you need to change the segment.
Actually using peek and poke
Now, come on with the code! Before you read the example proggie, I
will explain the some things:
VARPTR is used address the integer that follows. A
variable that is used to address (point) to an integer, is called a pointer.
Instead of address you can use VARPTR(variable), but when you
need to have the address to the variable more frequently, it is faster to
save it in a variable.
CLS
DIM address AS INTEGER
DIM variable AS INTEGER
address = VARPTR(variable)
'let address be the pointer to the integer variable
variable = 10
PRINT variable
PRINT PEEK(address)
POKE address, 15
PRINT variable
PRINT PEEK(address)
When you look at this code, you can see that poking to address is the
same as setting variable to another value. But, this only is like that if
variable is a value under 255. Why? Well, remember that one byte can only
have a value from 0-255? And with peek, you only read one byte. So, cuz
one integer is two bytes, we need to peek another byte. Which? Simply the
next one. And, for integers, we use this formula:
Value = PEEK(address) + PEEK(address + 1) * 256
Value is the value of the variable where address points to. This formula is
only true for positive values of the variable.
For negative values of variable, we subtract 256 from the second bit:
Value = PEEK(address) + (PEEK(address + 1) – 256) * 256
Poking to the screen
Note: The ideas and code I present here, are only for SCREEN 13!
Be sure that you’re in screen 13 when you use this code!
Now you know how to look up the values if integers with peek
and poke. But actually, this is quite useless and I just cover
this for completion and for learning purposes. It is only to
give you the idea of how the memory works. To help you with a
really useful trick you can do with peek and poke, you have
to know how the screen is saved in the memory:
The screen (in screen 13) has 320 * 200 = 64000 pixels. Each pixel
can have a value from 0-255. Hey! This exactly the same value a byte
can have. And, it won’t surprise you: each pixel is one byte in memory.
But how you know which coordinates (x: 0-319, y: 0-199) are with which
offset(0-63999)? When you have the coordinates and you want to get the
offset, use this formula:
offset& = y * 320& + x
Then you poke or peek at that offset. Poke to set the pixel at
that offset to a certain colour, and peeking to get the colour at
that offset. Like this you can use peeking and poking instead of
psetting and pointing. When you poke a value or colour more then
255, the counting will start over again. So 256 becomes 0, 257
becomes 1, just like -1 becomes 255, -2 becomes 254…
Be sure that you use LONG integers for the offset, and a LONG
sign after the 320, to avoid an overflow error. But, of course you
can’t peek and poke to that yet, because the screen offset doesn’t
start at the starting segment of qbasic. It actually is at &HA000.
That looks weird, because it is a hex number(hex numbers have &H
before it always in qbasic). We use hex numbers just because &HA000
is easier to remember then -24576(the matching decimal integer for
the hex number &HA000). Now you set the segment to &HA000 or -24576,
you can poke to it where you want. Code:
DEF SEG = &HA000
When you’re ready with poking to the memory, always return to the normal
segment by DEF SEG (without any arguments). When you don’t do
this there may be some weird errors (screens that freeze and a bunch of other
things).
That is a useful feature of peeking and poking: it is much faster then pset and point.
But this can still be made a lot faster. We can either replace that multiply
with a lookup table with a size of 199 that multiplies every value you pass to
it with 320. Make sure that you multiply with 320& and use a long integer-type
array. An other way to do it fast, and avoid that some memory is wasted by a
lookup table, is just to access the screen in the way it is stored in memory:
row by row. You just initialise the pointer to zero, and after you plotted a
pixel, you add one to the pointer to go the next pixel. Be sure that the x
loop is the inner loop and the y the outer loop! Else it will mess up.
Here’s some code.
SCREEN 13
DEFINT A-Z
DEF SEG = &HA000
pointer& = 0
FOR y = 0 TO 199
FOR x = 0 TO 319
POKE pointer&, colour
pointer& = pointer& + 1
NEXT
NEXT
DEF SEG
Of course, the pointer is a long integer again.
There are still some faster and faster ways to get an image to the screen.
That is with a buffer. BTW, I still want to teach you something extras
about the VARSEG shit.
VARSEG and VARPTR
Do you remember the value of an integer, that was stored in memory with
the second bit representing a value 0-255 that needs to be multiplied with 256? Well,
varseg and varptr work actually the same way. Only, varseg is 16 times the pointer
instead of 256(that is because the segment is shifted 4 bits to the left, if you
understand, and care). Instead of adding 16 to the pointer, you could add one to
the segment. The same logic: instead of adding 320 to the pointer, we could add
20 to the segment. So, instead of drawing the whole screen with one long integer,
we can draw the screen with one integer, and update the segment every line. We do
this like this:
DEF SEG = &HA000 + y * 20
Then we draw like this:
FOR x = 0 TO 319
POKE x, colour
NEXT
This is not really faster then the other ways I showed you, but it is added
for completion, and to show you how varseg and varptr relate to each other. BTW,
some programs use this, and now you know exactly what’s happening ;). It is
possible to get the multiply by 20 out, and then it is, as I believes, the fastest
way of poking to the screen. You just add a variable that increases with 20 each
time on the end of the y-loop. You don’t need a long integer anymore that makes
it slow. The code is:
SCREEN 13
DEFINT A-Z
yp = 20
FOR y = 0 TO 199
DEF SEG = &HA000 + yp
FOR x = 0 TO 319
POKE x, colour
NEXT
yp = yp + 20
NEXT
Of course, you can replace the &HA000 segment by a buffer segment(you will
learn later how to do this). The fastest way, however, would be to write some
ASM routines. One to write to the buffer, some kind of PSET, and another to
copy the buffer to &HA000. This is not that hard to do, and well worth the effort
when you’re, for instance, making a game. It is also a fairly good practice for
your ASM coding.
Poking to a buffer
When you want to have flicker free graphics, a buffer is very useful. It
eliminates almost every flickering. The trick with a buffer is to set the segment
not to &HA000, but to the segment of a buffer. The actual buffer is just a large
array of short integers. The buffer needs to have enough memory for
- All pixel colours
- The height and width information
The size for the pixels is easily calculated by just multiplying the width of
the pic by the height of it. Then you divide by two, because we don’t use bytes but
integers, which exist out of two bytes. Then you add two, because the information
needed to put the pic to the screen is two integers. Formula:
Size = INT(width * height / 2 + .5) + 2
So, for a screen size buffer you get (320 * 200) / 2 + 2 = 32002 elements.
So, you dim an integer array with 32002 elements:
DIM buffer(32001) AS INTEGER
That actually are 32002 integers, because the counting starts at 0. So 0-32001
elements are 32002 elements ;).
Then you set the segment to the segment of the buffer:
DEF SEG = VARSEG(buffer(0))
Or, when you want to use this segment more frequently, you can first save the
segment in an integer:
buffersegment = VARSEG(buffer(0))
DEF SEG = buffersegment
But before you try this, you have to give up the width and height of the
buffer too. This is called initialising the buffer. It is needed to blit the
buffer to the screen. We do it in the following way: we set the first element
(in this example: buffer(0)) to 8 times the width. I don’t exactly know why
the width needs to be multiplied by eight, but be sure to do it, else it won’t
work. The second element is set to the height. In code:
buffer(0) = 8 * bufferwidth
buffer(1) = bufferheight
Ok, now you’ve set the segment and initialise the buffer, you’re ready to poke
to it. One thing I have to tell you about: there are easier ways to use a buffer.
With get and put. Once you have dimmed an array with enough space you can get any
portion of the screen with this command:
GET (x1, y1) – (x2, y2), buffer(0)
And put it on any position:
PUT (x, y), buffer(0), PSET
With PSET you make sure that the buffer overwrites the background. When you
don’t use it, it looks very weird. Not recommended :P.
An easier way to initialise the buffer is to simply GET the whole screen:
GET (0, 0) – (319, 199), buffer(0)
But, this copies the whole screen into your buffer, so when you want to have
a empty buffer your screen needs to be empty too ;). I told you about the
height/width manner too, because you need to know how GET/PUT work. GET
initialises the array automatically with the width and height, and PUT blits
the buffer super-fast to the screen.
You’re almost ready to use the buffer, the only thing to know is that your
pointer starts with a value(offset) of 4. This is because the first two integers
are used to save the height and width. And each integer is two bytes. So, when we
put everything together:
SCREEN 13
DEFINT A-Z
DIM buffer(32001)
buffer(0) = 320 * 8
buffer(1) = 200
pointer& = 4
FOR y = 0 TO 199
FOR x = 0 TO 319
POKE pointer&, RND * 255
pointer& = pointer& + 1
NEXT
NEXT
PUT (0, 0), buffer(0), PSET
Well, it’s not that hard, huh? And, the nicest, it gets rid of all flicker!
When your having memory problems, try using REM $DYNAMIC in your code. It gives
you more memory to use. Very handy when you use a buffer, because a buffer eats
up almost all memory. The only little downside of a buffer. But when you use dynamic
memory, with REM $DYNAMIC, you have no problems with that. One last thing, when you
have still some flicker, try this:
WAIT &H3DA, 8
WAIT &H3DA, 8, 8
Right before you PUT the buffer to the screen. That should eliminate all flicker. Bang :P.
Quick filtering
I will present a way to do very fast blurring or a fast fire filter.
You can do this by poke at the current pixel and peek at the right places:
for a blur filter, peek at the surrounding pixels, so:
- Pixel above:
PEEK(p& - 320)
- Pixel left:
PEEK(p& - 1)
- Pixel right:
PEEK(p& + 1)
- Pixel down:
PEEK(p& + 320)
Then you divide the value of all this pixels together, and poke this at
the pointer. You may need a loop from x: 1 to 318 and y: 1 to 198. This is a
bit weird coded, because the pointer needs to skip the first and last pixels
of a line. Also notice that you need to have a gradient palette to blur. Code:
SCREEN 13
DEFINT A-Z
FOR c = 0 TO 255
OUT &H3C8, c
OUT &H3C9, c / 255 * 63
OUT &H3C9, c / 255 * 63
OUT &H3C9, c / 255 * 63
NEXT
DEF SEG = &HA000
P& = 0
FOR y = 0 TO 199
FOR x = 0 TO 319
p& = p& + 1
POKE p&, RND * 255
NEXT
NEXT
DO UNTIL LEN(INKEY$)
p& = 321
FOR y = 1 TO 198
FOR x = 1 TO 318
total = PEEK(p& - 320) + PEEK(p& - 1) + PEEK(p& + 1) + PEEK(p& + 320)
POKE p&, total \ 4
p& = p& + 1
NEXT
p& = p& + 2
NEXT
LOOP
DEF SEG
You can make a LUT for the divide by four. The size of the LUT needs to be from
0 to 4 * 255 = 1020. You can add the centre pixel too and divide by five. The size
needs to be 5 * 255 = 1275 then. This gives a slightly less, but better blur.
If you want to copy one buffer to another, you just make a 0-199 loop and swap
the segment every time in the inner loop, like I told you in ‘VARSEG and VARPTR’.
Between the PEEKing from the one buffer and POKEing to the other, you need to
save the values in a LUT, which can hold 319 integers.
If you want to know more:
Memory tutorial (© by Qbasic for All!) – Teaches you all about the memory in Qbasic(not
about using it or implemention, but just how all the commands concerning memory):
http://www.petesqbsite.com/sections/tutorials/tuts/memory.htm
Get and put tutorial by Andrew L. Ayers – All about GET and PUT.
http://www.petesqbsite.com/sections/tutorials/tutorials/getput13.txt
Extra
I actually finished this tutorial, but then I though about something that
Galleon learned me. Credits go to him.
It is another way of using a buffer, but now you write to it with Qbasic’s
graphical functions(PSET, POINT, LINE, CIRCLE, GET, PUT). I think that it is
very cool when you understand it. But, it’s gonna be a bit complicated, so don’t
worry when you don’t understand. That’s why I called this part “Extra”.
What I’m going to try to explain to you, is a way to use Qbasic’s graphical
functions with a buffer. So, when you use LINE, it draws a line to the buffer. Unfortunately,
this doesn’t work for PRINT because text uses another segment.
First, we have this idea:
We know that Qbasic build-in graphical functions writes pixels to the
screen. But we want qbasic to write to our buffer. I accidentally know
that the place where Qbasic lets its graphical functions draw, is stored
somewhere in memory. So somewhere in the memory must be standing: &HA000.
OK. Now we must translate this idea to code:
Search in the whole default segment of Qbasic (0-65535) for &HA000. When you
make &HA000 an integer, and you look up each byte, you get:
- First byte: 0
- Second byte: 160
So it is easier to make an IF into the loop:
'Scan the whole memory
FOR pointer& = 0 TO 65534
IF PEEK(pointer&) = 0 AND PEEK(pointer& + 1) = 160 THEN
'You’ve found &HA000, now check if it’s the right place in the memory
Now we need to check if it’s actually the right place in the memory. We do this by
messing up the place where &HA000 stood first. Then we PSET a colour at (0, 0). Then we
peek a value at segment &HA000, offset 0. If that is the colour, then it is not the right
place in memory, so we restore &HA000 at the current offset and we need to continue
searching. If it is not that colour, we save the current value of pointer&, and stop
searching:
'We mess up the first byte(we make it 1 instead of 0)
POKE pointer&, 1
'Then we try if PSET still PSETs at &HA000
PSET (0, 0), 127
'If it does not, we have the right place
DEF SEG = &HA000
IF PEEK(0) = 127 THEN
'We have a wrong place, restore pixel at (0,0), and get &HA000 back into memory
DEF SEG
PSET (0, 0), 0
POKE pointer&, 0
ELSE
'We found the right offset, so get the buffer segment into the place of &HA000, then exit from the FOR loop
DEF SEG
place& = pointer&
Now we need to get the segment of the buffer into the memory. But here is a little problem,
because you can only set a segment in the memory and no pointer. But we want to start the
drawing at buffer(2), because the first two elements are saved for the height and width of
the pic. We can’t increase the segment by two due to the fact that the segment is 16 times
the offset. So an offset of 1(byte) in the segment would mean 16 bytes in the pointer. Hey!
Now we can use it! We just dim our buffer a bit bigger then normal, and let the drawing
start at buffer(8), which is the 16th byte in the array. So the width is set at buffer(6)
and the height at buffer(7). Then we can PUT it to the screen with:
PUT (0, 0), buffer(6), PSET
Also, you can easily initialise it with GET again:
GET (0, 0) – (319, 199), buffer(6)
Now we need to write the segment(VARSEG(buffer(8))) into memory. The memory is
split up in bytes, we need to split up the segment in bytes. We do this by letting
the first byte be the value AND 255, and the second byte the value \ 256. Code:
Segment = VARSEG(buffer(0)) + 1
POKE pointer&, segment AND 255
POKE pointer& + 1, segment \ 256
This manner(ANDing by 255 for the first byte and integer dividing by 256 for the second) works
also fine with writing positive values to integers.
Now you’ve done all this, we’re almost finished. One important thing to know is that you can’t
PUT to the screen no more, because you PUT to the buffer. When you want to put to the screen, you
will need to restore the &HA000 segment in memory. Therefore, you need to save the pointer into a
variable. To restore the &HA000 segment:
POKE place&, 0
POKE place& + 1, 160
Then you put the pic to the screen and then you restore the segment of the buffer in memory.
It’s recommended to put this into two subs, one for initialising the buffer and finding
the &HA000 in the memory, and the other to put the buffer to the screen. Well, I will
give you the whole code with some code to test it:
Note: the SUB initialises the buffer, searches the memory for &HA000 and sets the buffer
segment in the place of &HA000.
The SUB refresh sets the segment in memory back to &HA000, blits the buffer to &HA000, then
sets the segment back.
DECLARE SUB refresh ()
DECLARE SUB initialise ()
CLS
SCREEN 13
DEFINT A-Z
DIM SHARED buffer(32007)
DIM SHARED segment, firstbyte, secondbyte
DIM SHARED place AS LONG
initialise
DO
'Use this instead of CLS:
LINE (0, 0)-(319, 199), 0, BF
'(CLS will work on &HA000 always, and we only want to clean the buffer)
FOR x& = 0 TO 10000
PSET (RND * 319, RND * 199), RND * 255
NEXT
refresh
LOOP
SUB initialise
'Initialise the buffer, set the segment and the two bytes
buffer(6) = 320 * 8
buffer(7) = 200
segment = VARSEG(buffer(0)) + 1
firstbyte = segment AND 255
secondbyte = segment \ 256
FOR pointer& = 0 TO 65534
IF PEEK(pointer&) = 0 AND PEEK(pointer& + 1) = 160 THEN
'You’ve found &HA000, now check if it’s the right place in the memory
'We mess up the first byte(we make it 1 instead of 0)
POKE pointer&, 1
'Then we try if PSET still PSETs at &HA000
PSET (0, 0), 127
'If it does not, we have the right place
DEF SEG = &HA000
IF PEEK(0) = 127 THEN
'We have a wrong place, restore pixel at (0,0), and get &HA000 back into memory
'then continue with the loop
DEF SEG
PSET (0, 0), 0
POKE pointer&, 0
ELSE
'We found the right offset, so get the buffer segment into the place of &HA000
'and save pointer& into place&, then exit from FOR loop
DEF SEG
place& = pointer&
POKE place&, firstbyte
POKE place& + 1, secondbyte
EXIT FOR
END IF
END IF
NEXT
END SUB
SUB refresh
'Set memory to &HA000
POKE place&, 0
POKE place& + 1, 160
'Put the buffer to &HA000
PUT (0, 0), buffer(6), PSET
'Restore buffer segment into memory
POKE place&, firstbyte
POKE place& + 1, secondbyte
END SUB
Conclusion
I hope you liked this tut, and everything was clear. You may send me some feedback on
basicallybest@live.nl. BTW, thanks for reading the tut.
And also don’t bother to mail me if you don’t understand something. Also check out my site:
http://members.lycos.nl/rubynl
It’s a bit old, but I’m doing a re-organization soon.
Greets,
Codemss/RubyNL (Codemss is my new username).
Credits
Plasma for SetVideoSeg
Sphere mapping tutorial
By Codemss (RubyNL)
Introduction
Sphere mapping is a very nice trick that is used much on demos. I found
however that there are no tutorials on how to do it easily. One approach is
to use inv-sin and inv-cos operations, but I found that that way sucks. When
I was messing with some things to make a circle, I found out that it is
actually very simple. I will describe a pretty nice technique for this. I
believe that Relsoft used this technique also in Mono and disco, for both the
sphere mapping and the lenses. A little knowledge of vectors and normals would
come in handy to understand what this manner actually does, but it is not a must.
The dot product and normalizing vectors will be explained here too, but I won’t go
in any details.
Introduction to geometric equation of spheres
What? Geometric equations for spheres? What is that? Well, you remember the equation
that you may have learned on high school, for a circle:
SQR(x ^ 2 + y ^ 2) = r
R is the radius of the circle, of course. We can easily translate this to 3d:
SQR(x ^ 2 + y ^ 2 + z ^ 2) = r
When we want to so sphere mapping, we need to know the z coordinate a
point(x, y) on the sphere. We need to check if it’s on the sphere also. Now, we
can use this equation to make an equation for z.
SQR(x ^ 2 + y ^ 2 + z ^ 2) = r
Take the square of both sides
x ^ 2 + y ^ 2 + z ^ 2 = r ^ 2
Subtract x ^ 2 and y ^ 2 on both sides
z ^ 2 = r ^ 2 – x ^ 2 – r ^ 2
Take the square root of both sides
z = SQR(r ^ 2 – x ^ 2 – y ^ 2)
This square root is necessary evil, so I will explain one or more ways to make a
lookup table for this later. First, we need to check if the point(x, y) is actually
on the sphere. This is very easy. You know that you can’t take a square root of a
negative number, so when the equation inside the brackets of the square root is
negative, the point cannot be on the sphere. Notice that x and y have to be in
range –r to r, not in range 0 – 2r. Code:
CLS
SCREEN 13
DEFINT A-Z
CONST r = 50
FOR y = -r TO r
FOR x = -r TO r
equation& = r ^ 2 - x ^ 2 - y ^ 2
IF equation& => 0 THEN
Z = SQR(equation&)
PSET (x + 50, y + 50), 15
END IF
NEXT
NEXT
END
Colouring based on z-coordinate
I used a long integer for the equation, because it may overflow at larger radiuses.
We didn’t use the z coordinate in the colouring. We could use colouring based on the z
coordinate. BTW, the z coordinate is always positive, because we are saying: z = square root
(blabla) and square roots are always positive. When you would want the backside of the sphere,
you had to take the negative of z (–z). Now when we want to look it 3d, we simple say
colour(x, y) = zcoordinate(x, y)
BTW, we divide by the radius and multiply by 255 to get the colours into the good range. Code:
CLS
SCREEN 13
DEFINT A-Z
FOR c = 0 TO 255
OUT &H3C8, c
OUT &H3C9, c / 255 * 63
OUT &H3C9, c / 255 * 63
OUT &H3C9, c / 255 * 63
NEXT
CONST r = 50
FOR y = -r TO r
FOR x = -r TO r
equation& = r ^ 2 - x ^ 2 - y ^ 2
IF equation& => 0 THEN
Z = SQR(equation&)
PSET (x + 50, y + 50), z / r * 255
END IF
NEXT
NEXT
END
In case you don’t know: the first FOR…NEXT loop is for the palette.
Ok, now this is more what we want! It looks already a bit 3d. Before going on I
got to tell you some optimizing stuff:
- Always use x * x instead of x ^ 2. This is for y, z and r the same
- Precaculate a constant that is r * r, then you can use this constant in the equation in the inner loop
- Precalculate y * y in the outer loop, instead of the inner loop
So, this would the new code for the inner loop be:
CONST r2 = r * r
FOR y = -r TO r
y2 = y * y
FOR x = -r TO r
equation& = r2 - x * x - y2
IF equation& => 0 THEN
Z = SQR(equation&)
PSET (x + 50, y + 50), z / r * 255
END IF
NEXT
NEXT
END
This is quite a bit faster, but we still can’t use this in real-time.
I will tell you: that is kinda impossible, so we have to calculate a lut.
Not that I’m explaining this now, just that you know it. I hate surprises :P.
Texture mapping
OK, now you’re ready to learn to texture the sphere! It is basically a matter
of just multiplying the x and the value by the z component of the normal. If you
don’t know what that is, don’t be scared. It is just the z coordinated divided by
the radius. So:
u = x / z * r
v = y / z * r
U and V are just texture coordinates. When we implant this into our loop, we
have to change from the geometrically right equation& => 0 to equation > 0, to
avoid dividing by zero issues. We can, instead of using a real texture, use a
XOR texture, made by easily XOR’ring the u by the v coordinate:
colour = u XOR v
I don’t give you code yet, because I’ve got more to tell you. We can also multiply
the z component of the normal by the texture to get a shaded and textured sphere. You
only have to make sure that you AND the colour from the XOR texture by 255, so for the
colour:
colour = ((u XOR v) AND 255) / r * z
If you don’t do this, the shading won’t work.
Full code is(note that I used a gradient palette again):
CLS
SCREEN 13
DEFINT A-Z
FOR c = 0 TO 255
OUT &H3C8, c
OUT &H3C9, c / 255 * 63
OUT &H3C9, c / 255 * 63
OUT &H3C9, c / 255 * 63
NEXT
CONST r = 50
CONST r2 = r * r
FOR y = -r TO r
y2 = y * y
FOR x = -r TO r
equation& = r2 - x * x - y2
IF equation& > 0 THEN
z = SQR(equation&)
u = x / z * r
v = y / z * r
PSET (x + 50, y + 50), ((u XOR v) AND 255) * z / r
END IF
NEXT
NEXT
END
Y ratio correction
You may have noticed that the sphere is a little too high. We have to fix
this with manipulating the y coordinate of a point. We have to divide by 5 and
multiply by 6. Then we use this y coordinate in the equation for the texture.
An easy way to do this:
...
FOR yy = -r TO r
y = yy / 5 * 6
y2 = y * y
...
PSET (x + r, yy + r), colour
...
Like this you can fit in the code easily.
Bigger radius’
When you use a bigger radius, you may come across some problems:
- Overflow errors
- Very big, obvious and ugly aliasing on the edges
For the first issue, you can just use long integers (like I already did with
equation&). The second issue is a little more complicated. I think that the best
way for this is to do the checking just the same, but then add a constant (I call
it ‘errorfix’) to the squareroot. The constant needs to be relative to the radius.
Code:
CONST r = 100
CONST r2 = r * r
CONST somevalue = 25
CONST errorfix = (r + r / somevalue) ^ 2
...
equation& = r2 – x * x – y2
IF equation& > 0 THEN
z = SQR(equation& + errorfix)
...
END IF
Notice that I’ve added a constant named somevalue. The bigger this value,
the more aliasing problems etc you got. Still, you can make it fairly big without
real problems. Don’t make it small, because the sphere mapping effect will be not
or hardly noticeable. A value between 10-200 is fine. When you use shading also,
you can better use the normal z, so without the added errorfix, for that. This
goes for the shading with the z component as for the shading with a light vector
or point (you will learn this next).
Shading with a light vector
This is a pretty neat technique that you can use to light the sphere. First
you got to define a light vector. Try a bit what looks right. I found that this one
looks good:
lx! = -1
ly! = -1
lz! = 3
Notice that I use singles, and you should do that too, because we gonna work with
values from 0-255. You could use fixed point math for this, but that would be a waste
of work, because that would be not that much faster (and we’re going to make LUT’s for
the texturing and shading anyway)
After that, you normalize this vector. What that means is that you make the vector
have a total length of 1. You do this by dividing all components of the vector by it’s
length. I quickly made a SUB for this:
SUB normalize (x!, y!, z!)
length ! = SQR(x! * x! + y! * y! + z! * z!)
x! = x! / length!
y! = y! / length!
z! = z! / length!
END SUB
In the inner loop, you take the dot product by the normal vector of the sphere. Make sure
that the normal vector is also normalized by dividing it by the radius of the sphere (because
that is the total length of the not-normalized normal vector). Code, for the dot product:
FUNCTION dot! (x1!, y1!, z1!, x2!, y2!, z2!)
dot! = x1! * x2! + y1! * y2! + z1! * z2!
END FUNCTION
Then we just multiply the dot product by 255. But if it less then 0, you should make it zero,
because we don’t want a negative colour. Here’s the final version for a lighted sphere. Play a bit
with the light vector if you want. Code:
DECLARE SUB normalize (x!, y!, z!)
DECLARE FUNCTION dot! (x1!, y1!, z1!, x2!, y2!, z2!)
CLS
SCREEN 13
DEFINT A-Z
FOR c = 0 TO 255
OUT &H3C8, c
OUT &H3C9, c / 255 * 63
OUT &H3C9, c / 255 * 63
OUT &H3C9, c / 255 * 63
NEXT
lx! = -1
ly! = -1
lz! = 3
normalize lx!, ly!, lz!
CONST r = 50
CONST r2 = r * r
FOR y = -r TO r
y2 = y * y
FOR x = -r TO r
equation& = r2 - x * x - y2
IF equation& > 0 THEN
z = INT(SQR(equation&))
dotp! = dot(lx!, ly!, lz!, x / r, y / r, z / r)
IF dotp! < 0 THEN dotp! = 0
PSET (x + 50, y + 50), dotp! * 255
END IF
NEXT
NEXT
END
FUNCTION dot! (x1!, y1!, z1!, x2!, y2!, z2!)
dot! = x1! * x2! + y1! * y2! + z1! * z2!
END FUNCTION
SUB normalize (x!, y!, z!)
length! = SQR(x! * x! + y! * y! + z! * z!)
x! = x! / length!
y! = y! / length!
z! = z! / length!
END SUB
I took the integer part of z, because it may be a little too big else. For
texturing this doesn’t matter, but for lightning it does, because it turns black at
the brightest points else. Well, try removing the INT if you don’t know what I mean.
Real-time rendering by using a LUT
A LUT, a lookup table, is a handy thing when you want to do real-time things that actually
can’t be done in real-time. The ‘secret’ of a lookup table is that you do precalculations
before the actual inner loop. That precalculations may take like 3 seconds, and this is MUCH
to long to do these precalculations in real-time. For sphere mapping, the first reflex for a
sphere with radius 50, would be DIM sphere(100, 100). Don’t do this. You use too much memory
and you can’t, for instance, make a sphere with radius 150, as that would get you an error.

One way to solve this is to use a LUT that is half the size of the sphere. So:
CONST r = 50
DIM sphereLUT(r, r)
Then, you need to mirror the data in the LUT if the point you want to draw is on
the right or on the bottom side of the sphere. The good thing is that you can use this
table for both the u and the v coordinates if you mirror it right.
It is also possible to save everything in one large array, but this costs some more memory.
Less memory then saving the whole sphere is used however, but still more then the other manner.
You need to check one time how many pixels are used, then DIM the LUT, and then fill the LUT.
That costs a little more time, but I believe this method is a bit faster.
A problem occurs when you try to draw the sphere, because it tries to draw a solid rectangle. For
this, you need an array of size radius, where you save every highest value on the x-axis. Then in the
inner loop you do:
FOR y = -r TO r
FOR x = -array(y) TO array(y)
Draw sphere here
NEXT
NEXT
An example program is here. If you’re having problems, look it up here. This is quite old code
(I am too lazy too write this code again), so much things may be vague to you. I use a weird sphere
mapping technique there, but ignore that. Before I forget :P, here’s the code:
SCREEN 13
DEFINT A-Z
xc = 160
yc = 100
r = 100
FOR x = 0 TO 255
OUT &H3C8, x
OUT &H3C9, x / 255 * 63
OUT &H3C9, x / 255 * 63
OUT &H3C9, x / 255 * 63
NEXT
DIM array(100, 100), xwidth(100), shade(100, 100)
FOR y = 0 TO 100
FOR x = 0 TO 100
delta = -(x ^ 2 + y ^ 2 - r ^ 2)
IF delta > 0 THEN
nz! = SQR(delta) / r
nx! = ((x) / r)
ny! = ((y) / r)
u = (((((nx! * (2 - nz!)) / 2) + 1) / 2) * 255)
array(x, y) = u
IF x > xwidth(y) THEN xwidth(y) = x
shade(x, y) = nz! * 128
END IF
NEXT
NEXT
LINE (0, 0)-(319, 199), 0, BF
DEF SEG = &HA000
DO UNTIL LEN(INKEY$)
FOR y = -100 TO 100
yd = ABS(y)
xw = xwidth(yd)
offset& = (yc + y) * 320& + xc - xw
FOR x = -xw TO xw
xd = ABS(x)
IF xd <= 100 AND yd <= 100 THEN
pixel = array(xd, yd)
u = pixel
IF x < 0 THEN u = 255 - u
v = array(yd, xd)
IF y < 0 THEN v = 255 - v
c = ((u + a) XOR (v + b)) AND 255
c = (c * shade(xd, yd) \ 128)
POKE offset&, c
offset& = offset& + 1
END IF
NEXT
NEXT
a = (a + 1) AND 255
b = (b + 1) AND 255
LOOP
DEF SEG
SLEEP
END
A lighting LUT is implemented exact the same way. But notice that when you’re shading with
a light vector, the shading cant be implemented with the first way, because you really have
to save each pixel apart. This is because the shading is non-symmetrical, so you cannot use
the array size optimization because that uses symmetry.
Other ideas
This tutorial has become a bit longer then I meant it to be, so I aint writing no more in
detail. I explained everything what I know in detail now, but I still have some other thing I
haven’t really tried myself to tell you. The first thing is about lightning. I explained the
shading with a light vector to you, but it’s also possible with a light point. For this, you
have to take the vector to the point. This is not that hard. Do this in the inner loop:
- Set the vector as (lx - sx, ly - sy, lz - sz). (Sx, sy, sz) is the sphere position and (lx, ly, lz) the light position.
- Normalize vector.
- Take the dot product of vector to the light and the normalized (divided by radius) normal.
- If the dot product is less then 0, set it to 0.
- Plot the point with colour dot! * 255.
Ready! Now about rotating. Normally, there are three rotation angles, one for each angle.
| Rotation about x-axis | Pitch | Done with adding numbers to texture coordinates. |
| Rotation about y-axis | Yaw | Done with adding numbers to texture coordinates. |
| Rotation about z-axis | Roll | Done with a rotation formula. |
Pitch and yaw can be easily implemented by adding numbers to the u and v coordinates
(texture coordinates). Of course you need to AND the texture numbers to keep them in range.
When you want to implement roll, you will need this formula:
u = (x * cos(angle)) + (y * sin(angle))
v = (y * cos(angle)) - (x * sin(angle))
Roll is so hard to implement because the u and v coordinates actually rotate. With the x
and y rotation, the x and y actually stay the same, but you just change their range by adding
something to them. The pitch and yaw we use, depends on texture sizes, but when you want to
give them up in radians, you need to convert them by diving through 2 * pi and multiplying
with texture size.
What also is very nice to do is making two LUT’s, one for the texturing and one for the
lightning, and them mix them in real-time. Then you could add for example, phong lighting to
the light LUT. It is also possible to rotate the lighting LUT, just the same way you rotate
the texture LUT.
A scroller must be to easy to implant, and you could make it transparent by not painting
the background pixels. Like that you could make more scrollers inside each other, sounds like
a nice idea...
Conclusion
I hope you liked this tut, and everything was clear. You may send me some feedback on
basicallybest@live.nl. BTW, thanks for reading the tut.
And also don’t bother to mail me if you don’t understand something. Also check out my site:
http://members.lycos.nl/rubynl
It’s a bit old, but I’m doing a re-organization soon.
Greets,
Codemss/RubyNL (Codemss is my new username).
Almost forgot:
Credits
Galleon for helping to optimize my program.
Relsoft and (especially) Biskbart for their sources.
Making a Particle Engine, Part I
Written by notthecheatr
Note: This is a beginning level tutorial written using FreeBasic - converting to QBasic, or other similar BASIC variants, should
not be very difficult, only bear in mind that this is written mainly for FreeBasic.
Another note: All source code and example programs may be downloaded in a ZIP file - the link is at the bottom of the tutorial.
Hey there, notthecheatr here writing my first tutorial. I'm going to show you
how to write a particle engine in FreeBasic. We'll start with the basics, no pun
intended, and work from the ground up. There aren't a whole lot of tutorials
on this topic (though if you Google you'll find a few), so I'm writing from a beginners
stand-point, building up over several parts to a powerful and flexible particle
engine built entirely from scratch. I think you'll enjoy it, maybe you'll even learn
something from it.
Right, so the first thing we need to understand is what a particle engine is
and why you'd want to make or use one. A particle engine is essentially the
structures for organizing and the code for updating particles. In other words,
you'd have a few data structures that tell how to create and initialize these particles,
then you'd have the code to move the particles around in a predefined way. The
result? Well, when you have a couple thousand particles on the screen, the result
generally looks pretty cool. In fact, particle engines can be used to create decently
realistic explosions and fireworks, flames, smoke, water fountains, sprinklers, jets,
rain, snow, and much more. Probably if you're writing an RPG you'll want to do some
of the spell animations this way. So in short, the reasons for writing a particle engine
are many - but to me, the most important one is that it's a lot of fun. It's not hard to
do, and the return (really cool effects) is worth it. So let's begin!
OK, so now we know what a particle engine is, how shall we go about implementing it? Well a particle system generally has two basic parts: the emitter,
and the particles. You might have more parts, but these form the foundation. The emitter emits the particles, and keeps track of them. In my system, the emitter is responsible for updating the particles and eventually drawing them (actually, each particle draws itself, but that'll come later...) Thus, you can think of the emitter as a kind of gun that shoots out little tiny dots. Note that these dots can move in a variety
of ways - they won't necessarily look like bullets, they might look like snowflakes. Or rain, smoke, fire - or anything else you can think of that is made of particles.
OK, so we want a structure for the emitter and a structure for each individual
particle. Now if we're going to have thousands of particles in memory then it would
probably be wise to keep the variables in the particle structure down. Thus, we'll
try to put as many variables in the emitter as we can, since there usually won't be
thousands of those.
So what is a particle? Essentially an object. In physics, your average object
has two essential characteristics. These characteristics are the basis for our particle,
and in fact without these characteristics our particle would be nothing. We will add
other things to our particle type later, to make it do more interesting things, but
for the moment we'll focus on the most important thing. Every particle has to know
where it is now, and where it's going (how fast in each direction, to be exact). In other words, you need to keep track of it's position (x, y, z) and velocity (vx, vy, vz):