QB Express

Issue #25  ~  October 31, 2007

"A magazine by the QB community, for the QB community!"

In This Issue



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.


Express Poll

Every issue, QB Express holds a poll to see what QBers are thinking. The poll is located on the front page of Pete's QBasic Site, so that's where you go to vote. Make sure your voice is heard!

Which QB/FB character are you going to dress up as for Halloween?

GenreVotesPercentGraph
Lynn (Lynn's Legacy)00%
The Griffon Knight (Griffon Legend) 00%
Jocke The Beast70%
Cooey (Secret of Cooey)00%
ASCII Smiley Face Character785603100%
785603 Total Votes

This was quite the shocker! It appears that all seven hundred eighty-five thousand, six hundred and three of the people that voted in this poll are going to dress up as the humble ASCII Smiley Face Character who has been the hero of countless QB games. Who knew he was so popular?!



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.

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.

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.

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.

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.

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.

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



Comics

By Deleter, sir_mud, Pritchard, and Michael D.

We have lots of good cocmis this issue. We have six episodes of Deleter's "Whitespace" comics, a new godObject from sir_mud, a comic from Pritchard, and a couple form Michael D.

Click the images to see them full-size! (NOTE to comic submitters: If you keep the width of your images less than 640 pixels, we don't have to resize them and add clicky-links. It makes them *that much* more fun to read!)





Whitespace

Whitespace

Whitespace

Whitespace

Whitespace

Whitespace


FB Pirate.PNG









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:

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:

  1. If h>1 then first use this procedure to move the h-1 smaller disks from peg t to peg r.
  2. Now the largest disk, i.e. disk h-1 can be moved from peg f to peg t.
  3. 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

  1. All pixel colours
  2. 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:

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:

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:

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:

  1. Overflow errors
  2. 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:

  1. Set the vector as (lx - sx, ly - sy, lz - sz). (Sx, sy, sz) is the sphere position and (lx, ly, lz) the light position.
  2. Normalize vector.
  3. Take the dot product of vector to the light and the normalized (divided by radius) normal.
  4. If the dot product is less then 0, set it to 0.
  5. Plot the point with colour dot! * 255.

Ready! Now about rotating. Normally, there are three rotation angles, one for each angle.

Rotation about x-axisPitchDone with adding numbers to texture coordinates.
Rotation about y-axisYawDone with adding numbers to texture coordinates.
Rotation about z-axisRollDone 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):