QB Express

Issue #20  ~  May 15, 2006

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

In This Issue



From The Editor's Desk

Written by Pete

Ladies and gentlemen, boys and girls! Step right up! I've got something for you that's absolutely, proof-positive guaranteed to tickle your imagination, to provide you hours of worry-free enjoyment, and to make your household the envy of your block (gotta beat the Johnsons, right?). In fact, what I've got for you is so fantastic that it comes with my very own Pete Berg Seal of Approval -- and folks, if you know me, you know that I don't give that out easily. No, it's not a bearded woman...it's a new issue of QB Express!

Now let me apologize for this issue once again coming out behind schedule. I realize that for that last two months, QB Express has slipped from a monthly to a bi-monthly magazine. That's my fault. My life is quite busy at the moment, and QB Express has fallen by the wayside. Right now I'm writing this on a public computer in the middle of the night, because I'm 3000 miles away from my own computer and don't have time to work on anything QB Express-related during the day. I just finished my semester working in sunny Los Angeles, California, and I'm back in upstate New York for a few days, before I take off to go to Addis Ababa, Ethiopia in less than 48 hours. After I get back at the beginning of June, I'll be moving back out to Los Angeles to work for the summer. I've got a busy, computer-less month in store, coming up after several extremely busy months. But enough about me. QB Express is the focus here!

This issue, as always, is super-sized with more QB/FB news, articles and tutorials than you can shake a stick at. But rather than telling you all about them, I say just go take a look for yourself! You will not be disappointed.


A SPECIAL NOTE ON THE QLYMPICS 2006:

You'll notice that there's nothing about the Qlympics in this issue. That's because the Qlympics has been DELAYED for the month.

I have not had a chance to work on anything for the Qlympics since the last issue -- life has just been too hectic. But I assure you, things will get back on track for Issue #21. Once I am settled again, have some free time, and have my own computer to work with, I'll put together the best Qmunity awards ceremony you've ever seen!


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 pberg1@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 Paul Martos

Just read your QB Express #19 and I'm impressed with the amount of work that went into it and the passion of the QB community. I'm new to the community, though not to Basic. I started programming as a hobby in the 1970s but switched to DOS in the 90s and dabbled in HTML later. I like Basic but don't spend all that much time with it these days, using it mainly to solve science problems that interest me; games, I buy. So, I don't claim any expertise in programming.

I found the article of FreeBasic by MysikShadows especially interesting because it echoes my feelings almost perfectly. I was looking for a more modern and powerful version of the language and discovered FB. As much as I admire the language I can see that it is being tugged in the direction of complexity. Adding C-like functions is nice, but then if people want the power of C why not just learn that language? I agree 100% that any implementation of other languages in Basic should look and behave like Basic, otherwise it's just no longer Basic.

I also found interesting several references throughout the issue to factions and conflicts within the community. I joined the FB forums to try to learn more about the language, asked my 1st question in a Beginner's forum --- and was immediately flamed. Why? Because I was deemed too lazy and too stupid to look up the answer to my question. Actually I had tried and grown tired of it. Maybe it's something I "should have" known but in all honesty I'd never come across the term "IDE" other than as a hard drive standard, and the definition does NOT appear in any documentation I saw. I understand it now, but at the time I didn't, and thought it simpler to just ask. I was also called a liar for "claiming" that I had experience in programming Basic.

This is extremely disturbing. I post regularly in the Astronomy.com forums and there no one is criticized for asking "stupid" questions. I was both insulted and amazed by the hostility in the FB forum. Why does this exist? Whatever the reason, it can only do harm and reduce the number of would-be users. I will probably never post --- or even visit --- that forum again. It comes across as an exclusive boy's club rather than a serious gathering of enthusiasts.

I may be flamed for this post, too. I hope not.

-Paul Martos

You've made many excellent points in this letter! I agree with you and MystikShadows to an extent about FreeBasic -- I think that the format of the actual code should be kept as close as possible to BASIC, but the functionality should be extended as far as possible. Also, the C-like functions or headers should not be required to run simpler programs that don't require this code. Backwards compatibility with QB (and perhaps other forms of BASIC) should be of utmost importance, and adding additional functions should be a secondary priority. However, adding functionality should still be a priority. The more that FreeBasic can do, the better. It would just be nice if the code format adheres to BASIC syntax rather than C.

As for the conflicts in the QB/FB community, I agree that it's usually lame and can turn away new members. Then again, it also makes this community interesting. I like the diversity of opinion you'll find here, and the extreme personalities -- and that is what causes the squabbling and flame wars. Although this community is small, it is rife with politics and people trying to one-up each other. It's childish, sure, but it does give the Qmunity a unique flavor. It may turn some people off, but I wouldn't have it any other way.

-Pete


Letter From MystikShadows

Hi Pete,

Two months already since my last letter to the editor, wow, time flies. Now I know I'm not the first to say this, I've already read some of them on more than one forum, but I definitaly agree with those that said that QB Expresss #19 was more than worth the wait. What a line up, what great reading contents, what great letter from DrV and your reply to it ;-). Yay, I've got fans :-). The major reason why I created the MIDI series is because I've done the searches already on MIDI and I just didn't like to have to go to 4 or 5 different websites to endup with enough information about MIDI files to do something constructive with it. So I said to myself "it sure would be nice to have it all in one place and explained once and for all.". I agreed with myself (which can be a good or bad sign lol) so much that I sat down and started the series. I guess up to a certain point, this is how I pick what I want to write about if I can't find it easily and quickly, there's room for improvement so If I'm knowledgeable in the subject, I'll write about it, in my usual ways, and hope it does just that, bring the right information to those that wish to know about the topic I choose.

I reread my own article on FreeBASIC too and decided it might have been possible my message didn't go through as straightforwardly as I wanted it to (probably because of the size of the article ;-)). So I thought I'd take the chance to bring it right down to the bare facts and give a foundation to that article. As some people know, John G. Kemeny and Thomas Kurtz created BASIC back in 1964 at Dartmouth College. When they did, the 8 principles of a BASIC Language were also created. Those are:

  1. Be easy for beginners to use.
  2. Be a general-purpose programming language.
  3. Allow advanced features to be added for experts (while keeping the language simple for beginners).
  4. Be interactive.
  5. Provide clear and friendly error messages.
  6. Respond fast for small programs.
  7. Not require an understanding of computer hardware.
  8. Shield the user from the operating system.

These are the 8 principles I built my evaluation on and well the direction that FreeBASIC seem to be heading is either ignoring or just not having time to consider point 1, 3 and to some extent, point 4. One might say that since FreeBASIC is a compiler, not an interpreter, Point 4 can be neglected atleast to some extend. Great, I do agree with that because it is a compiler (maybe something can be done at the IDE level at that point then :-). But point 1 and 3, in my opinion, should be emphasized a little more than it is right now. And I do understand that point 8 is very difficult to achieve in a cross platform compiler so I appreciate that the FB Team managed to bring point 8 to the level it is at today. Great work on that side.

And how for the rest of the letter :-). For one thing, that competition (and polls) you're having right now, great idea, with all that coding that's been done in QB and FB over the years, there's definitally plenty enough material to do this kind of undertaking, I can't wait to see how everything ends and I, right now, wish every participants (who I'm sure are all more than deserving) the best of luck as we all see this event progress towards it's ultimate results. This will be one for the books for sure.

Now how about that newsbrief section huh? Plenty happening as we can all see. it's great to see all this activity going on right before our very eyes. Like you said, it's really about time that a site like FreeBasic.info exists that's definately a big plus for us. Lachie's projects are moving forward quite well I can't wait to get a look at them all when they are completed, especialy his QBasic Games Directory website. And what's to say about the Qlympics 2006 man, this outta be another great event to follow up on. Awesome idea.

In the gallery, the game "Mystic World" (something about the name that just grows on me ;-) hehe. I don't know why, but these classic zelda like games, when well thought of and created, I just find fun to play and watch. I really like where Stormy seems to be taking that game and when possible, I just might be the first to complete it if not for any other reason, for old times sake. But aside this project, wow, there's alot of creativitiy going on too with all those other projects I've seen in this issue. Amazing to say to the least.

The first article I want to talk about has to be Imortis Inglorian's "Can't We All Just Get Along?" article. even in my rather short history of 2 and some years, i've seen plenty of failed attempts at team developement efforts. In most cases, those that form teams do so to help make a project reach it's realization sooner than doing it alone. So the reason to form a team are definitaly valid. I think imortis brings some very interesting points in his article on the subject. Not everyone comprehends why 2, 3 4 or 5 people that all want to make the same project happen, sometimes give up. Not always about lack of motivation. Sometimes you gotta take the time to pick your team members not just based on who they are, but on what they know too. A little pre-selective phase can really make a difference as to wether a team reaches their goals or not. Great work there Imortis a very interesting read. Also, since this paragraph is about Imortis, I'll mention here that I really enjoyed his 2nd part to his text parser series. He's right, there are alot of text parsing tutorials out there, the main reason is they are so darn popular still today. The other reason is that I for one love to see the individuality in everyone's text parsing systems. It eems that each of them, when you look at the code, you see a different application or a different kind of game it would be good for just because it's coded in their different way of thinking. :-).

I want to make a quick note about Lachie Dazarian's game reviews (not just the one in QB Express #19 but most of the ones he did. Some people are gifted tutorial writers (Na_th_an IF series, relsoft's 3D series, and others which really have the knack to give it to the readers straight and clear about what they are covering). Other people, are gifted in reviewing games and probably other types of projects if they gave it a shot. Lachie is definitaly one of those people. Just take a look at how he took a tetris game review and turned it into something worth reading from start to end. I tip my hat to those greate reviewers. He's a natural and it's clear why he would take on such a project as his QBasic Game Directory. Awesome work. He's not the only one, but others I haven't seen that many reviews from so I don't have enough info from them :-). Lachie seems to be a multidisciplinary writer to say the least. He's great at reviews, but if you've read his tutorial on "How To Program A Game In FreeBASIC - Lesson #1" you'll see that he's pretty good at teaching too. he can really break the learning material down into easy to digest steps. I enjoy reading his articles and reviews each and every time.

In two articles, Nick Verlinden managed to impress me quite alot with this "Multi Processing Core for QB" two part series thus far and I want to know how far he'll take this Multi Processing thing in QB. I'm more than looking forward to seeing what is gonna immerge out of this. For too long I've seen many people say "no point in trying to do this in QB, no reason to, not worth it, can't do it and the likes" whenever multiprocessing and QB were mentionned in a complete sentence. I'm glad to see someone take on this challenge the way nick does and i'm even more curious to see what will arise from it. Nick, you've got someone wanting you to push it as far as you can take it. :-). Keep up the great work.

When mennonite said that 'apostrophe was an "add on" so to speak to QB Express, I didn't get a clear picture of that until I read the first issue of it. I really like what he does with 'apostrophe, the contents he puts in there are great, pertinent and well fun to read. So I welcome 'apostrophe and I hope we'll get to read more releases of this. I know I want to. Great work there mennonite and everyone involved in the contents of 'apostrophe. Keep on keepin on. :-).

The comics were pretty good. The horse is now friends with a penguin. Hmmm do I detect a linux influence in Rattrapmax6? hehe. I liked the debut of tunginobi's cartoons. These comics just bring a breath of "different" air to the magazine and I'm glad they are there. Hope to see plenty more of them.

I remember last month I read syn9's series on Tree creation and said to myself 2 things. 1. That tree looks bare without any leafs. 2. it would be fun if the next part of the series, if it comes out, put some darn leaves on that tree. Well, I guess this issue's Tree tutorial answered those questions. And it ended up being a pretty good tree too the leaves really made a difference and well, I'm genuinely impressed with how that series managed to pull it off. syn9 is, without a doubt, a great 3D designer. Maybe in part 12 adn 13, he can take on the Amazon jungle? ;-) hehe. I want more from syn9. I'm a fan now. :-).

And now, what's to say about "A FreeBasic Memory Leak Detector" by DrV himself. I don't know how many times I've been to the freebasic.net forum (and other forums) to read "______________ caused a memory leak!" Alot of times to say the least. And here comes DrV with what seems to be an awesome solution to this frequent problem. What better way to control memory leaks than if you can detect them? This is not only a very interesting read, but a very sought after one as well. Great work on that DrV. And I also want to say, right here, how much I appreciate all the hardwork DrV and the rest of the FB-DOS port team are putting into that version of FreeBASIC. I don't know how many others but me are happy that there's a DOS version of FreeBASIC, but I do know for sure that I'm not the only one that uses it anymore. So now you got more reason to keep up the AWESOME work. :-)

And now for the "disfunctional" part of the magazine ;-). I hereby named rdc's (really disfunctional coder) "A Closer Look At Managing Complexity" article. I don't know how many times I've been in that exact Data Complexity situation myself in my career. And like he mentionned, if the data structures and variable scopes aren't managed well, a rather simple program can turn into a nightmare pretty fast. There's a certain ease and temptation at just using global variables. You know you'll need them all over the place, you're tempted to just create them globally and think "there, this way, I'll have access to it". Well it doesn't take too many of those global variables and structures to begin to see how bad things can turn. Because in many cases, data related problems won't generate runtime errors per se so you have to take each of them, trace them throughout the code to make sure that they always have the right value assigned before they are used in some calculation process or whatever. Those are, by far, the longest types of bug to debug just because of the added process of following their values throughout a sub or function and even worse when their are used all over the place in your code. Alot of people should read rdc's article right now and really pay attention to it, there's a gold mine of information and problem solving techniques in there that anyone can definitaly benefit from, not just in applications, this definitaly applies to games too. Awesome and precious work in this one. Not bad for a disfunctional coder ;-). Hehe.

I would like to bring a correction to my 2nd part of the MIDI series here. The function GetVariableLength() doesn't have the right parameter names in itss contents. It should read as follows:

' =========================================
'  This function calculates the length of
'  a variable length MIDI message.
' =========================================
FUNCTION GetVariableLength( MidiHandle AS INTEGER, _
                            Position   AS INTEGER) AS INTEGER

    DIM Value     AS INTEGER
    DIM Character AS BYTE

    Get #MidiHandle, Position, Character: Pos = Pos + 1
    Value = Character
    If (Value And &H80) <> 0 Then
       Value = Value And &H7F
       Do
         Value = Value * 128
         Get #MidiHandle, Position, Character
         Position = Position + 1
         Character = Character And &H7F
         Value = Value + C
       Loop While (Character And &H80) <> 0
       End If
    GetVariableLength = Value

End Function

And this is it for this letter to the editor. I can't wait to see what QB Express #20 will have in store for us. And, i'm sure that like ALL the previous issues, it will definitaly be worth the read. Great work, as always to everyone involved. Wow, there's alot up ahead on the QB/FB scene, I can't wait to see it all :-).

MystikShadows
Stephane Richard

Once again, amazing feedback -- for EVERYONE who contributed last issue. You deserve a pat on the back for not only being this mag's best critic, but also our biggest cheerleader (or, if you prefer a manlier title, motivator). :-)

You make really great points about how FB is going a bit astray in its development. Thanks for sharing the Kemeny / Kurtz list of BASIC's 8 principles. Very interesting stuff. While I think V1ctor is doing a phenomenal job of living up to them, there's always room for improvement (which you also pointed out).

Thanks for the letter...I look forward to next month's letter! :-)

-Pete


Letter From Lachie Dazdarian

NOTE: I originally received this email before Issue #19 came out, but forgetful old me forgot to publish it last month. Whoops! So here it is, as well as a brief follow-up that Lachie sent me after I broke the news to him that I didn't include the letter.

Me again. It's been a while since as usual I had problems getting to college and therefore online.

This time I'm sending you another tutorial from my "How To Program A Game With FreeBASIC" series. This one is really big. I dare to call it monumental. I think I did a fine job there and included all the things I believe this kind of series should provide. I doubt another lesson will ever be written as I explained it in the very tutorial. As I see this will arrive for issue #19 so I urge you to keep it for issue #20 since my two huge articles I originally submitted for issue #19 are more than enough.

I had plans to write another article entitled "The Griffon Legend is crap?"(intriguing title, eh?) inspired by a conversation I had in the #badlogic channel(the unofficial community chat room). You can guess that my answer on the question is negative but the article didn't deal directly with The Griffon Legend. I only planned to point it out as my motivation to do the article. The very article supposed to be a general statement on how I feel computer games should be played and evaluated, especially if you are a game designer.

Unfortunately the article included too many philosophical traps(uh-oh) and on the top of that I had huge problems constructing more than one sentence. And I hate that. One part of the article supposed to deal with the game reviews in our community which really comes down to reviews in QB Express. What I wanted to point out (again) is that the community would really benefit from a proper FreeBASIC games site that would feature its own objective scoring system and of course archive our production. For example, VPlanet was/is for me a great source for the best QBasic games. Yes, VPlanet doesn't include all of them but most are there. Anyway, now in QB Express with several reviewers being active, each with his or her own taste and requirements, can result is some 2-3 hours effort being scored with the same score as some much more ambitious project because those two games were reviewed by two different persons. I don't know. I just feel some reviewers should think twice when giving a final score to some really small game. I could include reviews of Poxie into this topic too(hello Adigun!) so don't think I'm being subjective here. Still, I think there is a whole other group of FreeBASIC games that use CIRCLE and PRINT statements and where the designers don't put that minimum effort to implement sound effects(FMOD. Rings a bell?) but still get more positive critics than they really deserve. And now I'm touching the line which originally stopped me to complete the article.

Anyway, I'm probably giving this issue(if it's an issue at all) too much attention.

I also gave up on doing an article about the best QBasic game developers though I would really like to write something on that topic. A sort of hommage to the QBasic game design scene. But I simply I don't have the time to gather all the data I need from the net. I have all the games I want to mention but that's not enough. If I had an Internet connection at home I might be able to do it. Then again it IS a lot of research. When I'm writing an article I like to do it properly.

Another thing I want to talk about. Err, my activity in the community will have to decline which means no more articles and reviews from me in the next 7 months. I have to finish my study and after it...who knows? I have this army service(6 months) and job finding(oh, the joy!). The fact I DESPISE my profession(mechanical engineering) and also SUCK at it(probably a result of me despising it :P) doesn't help. What's even more worst is that there is a lot of job vacancies for my profession in Croatia which doesn't give me an excuse for not taking a shoot in it. Hmm, I think it will be more than 7 months. :P

Still, this is a good thing in one aspect. More and more FreeBASIC projects crawl on my PC like a slug(1-2 FPS). I was kinda in belief my sturdy "new" used PC will run FreeBASIC projects without sweating. I have a Pentium III, 866 Mhz with 192 MB of RAM and ATI 3D Rage Pro AGP video card. DirectX 9.0 installed. So the fact Tubez(a 2D game) crawls with less than 1 FPS on it as well as Asteroids 3D(even in the menu; a YAGL game) puzzles me. I was suggested that I should install a new video driver which I tried with Catalyst and failed. It says I don't have the proper hardware or software to install it. Bwhat? Also, in all this messing I was forced to reinstall my Windows XP(don't ask). Luckily I had all my work files on another partition and the installation files of the programs I'm using on CDs. Still, in this process I lost my sound card drivers. Crap! I hope I will find them on the net. Currently it's like I don't have a sound card at all. Stupid Windows!

Maybe I shouldn't get mad on the developers of FreeBASIC projects and people who SCREAM that YAGL is uber fast. I should probably get mad on Bill Gates. I think this is some kind of cosmic punishment because I defended Windows XP in another letter. :P Oh, well.

It's been too many issues from my last letter so I can't comment the articles individually. Anyway, I emailed some of the authors with compliments. It's comforting to know that QB Express is good as always featuring a stable number of submissions. I would even say that tutorials submitted for issues #17 and #18 were more than encouraging for the future. Great work! Nice to see Rattrapmax6 continuing on his series. MystikShadows suggested I should apologize to Rattrapmax6 after seeing this but I don't agree. I didn't call him a wanker(god forbid) or something like that. I just said I would like to see people sticking to their series. Nothing insulting in that. Anyway, I'm now falling into this category of "series breakers" too. Which really isn't my choice. I would so like to write another 3-4 editions of "Searching For The Unknown" column.

I'm adding this paragraph after writing the first part of the letter a week ago. I still can't get online. I wonder how old this letter will be once it reaches Pete. And this is more frustrating than you may think. I'm missing some vital scripts for an upcoming exam and the deadline is closing. I'm wasting time at home like a zombie. Anyway, the reason I added this new paragraph is my work on QBasic Games Directory I did during last few evenings(it was around the 9th of this month). Well ladies and gentleman, I created a fully functional QBasic Games Directory website! It was the last work I really wanted to do for the community before I leave to my college exile(which is never to start - in my head :P).

I had this great collection of HTML/PHP/MySQL tutorials downloaded from http://www.tizag.com/ (wonderful site) that was sitting on my hard disk so I thought why not check it out. One thing lead to another and I soon discovered you can become intermediate in HTML, PHP and MySQL in two evenings using these tutorials. These tutorials allowed me to create the site I originally imagined. The official PHP help file was also helpful. The site allows game filtering by categories and it also features a search by query page. Games are dumped in a nice looking tables. For a long time I though that implementing a search feature would be a huge problem until I discovered the wonders of MySQL's 'LIKE' statement. The site also features game dumping by letter and genre, all the sections from the preview site(running QBasic games, about the database, etc.) corrected and updated, nice downloads section with useful utilities(VDMSound, CPU Grabber, QBasic, MS-DOS boot disk, etc.) and most of the features that a site of this sort should have. The look of the site is not what I really want since I forgot to download few CSS tutorials and had to mock something up. It's not great but still better than the preview page. I sent you Pete the screenshot of the website so you can make THIS word a link to it. Or THIS word! Just don't make me look silly. :P The site will probably be hosted by Mark Wilhelm at his www.qbasic.com domain(I hope) since he showed interest for the project. For the starts the site will not feature download links but only screenshot links(around 420 screenshots). The games in the database(442 of them) are around 210 MB large total and since I'm having problems using FTP at my college connection sending this to Mark will be a problem. I only urge you to be patient about this. Anyway, even without the download links this site will be a nice source of information about the QBasic game design scene. I asked Mark to inform the community once he sets up the site. It will take some fiddling since we are talking about import a MySQL script, uploading around 10 MB of data and setting up some other things.

Once more Pete, thank you for all your hard work. Even if QB Express would stop being released today it would be remembered as something really special. Something hardly repeatable. I hope you are doing fine in California. It's great to know that moving across the country and looking for an internship is something you find relaxing. I really admire such proactive and resourceful persons like you. Which means I have to work on myself A WHOLE LOT.

Best Wishes All, Lachie Dazdarian(still chucking forward)

P.S.

Sorry if the letter was hard to read. I'm really having problems being coherent lately. Maybe I'm getting old. :P


And the follow-up...

I'm not happy about this but put the letter in issue #20. What else?

As for Qlympics I'm really disappointed with the lack of interest in it. I mean, I posted in Qlympics threads in QBasicNews and your forum and no replies for almost a week! Bah!

As for nominees I have one more for QBasic section. Cyber Chick BETA. I completely forgot about it since it was released in a really awkward moment for me. Then I still didn't have a proper PC(with a hard disk). Then again, nobody jumped on my neck for forgetting it. Or doing anything else. Bah, again!

Cyber Chick download is here.

Also, some might want to nominate SonicX(last build is number 10, right?). I'm aware of it but I just think that demo is too messy and too bitchy to run. I don't know. It really didn't impressed me.

I skimmed through issue #19 and I didn't notice news about Visna's End, a rather nice(not impressive but still) space shooter. (Link.)

MystikShadows is not doing his job!

Also, things about QBasic Games Directory has changed as you read IN MY LETTER. (Link.)

So the news about it in QB Express #19 are outdated. Partly my fault. Just be SURE to look around for latest news on QBasic Games Directory in issue #20.

Oh yes, another nominee. Can I nominate my Another World Memory FreeBASIC for Best FB Port of a Past QB Game?

Ok, that would be it. I think. I'm not sure if you took my suggestions about Qlympics into consideration(about including year 2003 into awards and selected jury thing) or you had set them from before. What ever it is I'm glad most of my suggestion appear in the Qlympics 2006 rules. I just hope that this top 3 out of 5 voting won't be retard. Leaving TerraScape without an award would be a shame. Me thinks. Uh, maybe I'm giving too much attention to this game. It's not like I made it. Still, I hate seeing a great product overlook. TerraScape beats everything 3D done in QBasic to a pulp(I hope I got that right)! :P

Cheers!

Lachie D.

Whew! That's a lot of reading. First of all, sorry about forgetting to include your letter in #19. It's tough keeping all of this QB Express stuff straight, especially with all the other things I've got going on at the moment.

First off, great work on your FreeBasic Game Programming guide. It's definitely one of the most complete and helpful tutorials we've ever had. I really would like to see what you wrote for your "The Griffon Legend is crap?" article. I'm sure it would be very interesting, and I always enjoy your theories on game design.

Your thoughts on changes to our game review format are good ones. I've been thinking about creating an "official" review format, but the reason why I've been hesitant is because I think the best reviews are ones written in long, paragraph form. I don't like it when people use these formats that split up the review by categories (graphics, sound, gameplay, etc.) -- because they are not accurate. They certainly don't reflect the overall satisfaction a gamer will get out of a game. A lot of games with good graphics and sound might suck to play, and a lot of ASCII games may be amazingly fun. But if you use a format like V Planet's, or the one I used to use on Pete's QB Site, fun games will often artificially low or artificially high scores based on these stupid categories that shouldn't even apply to some games. (Like Puzzle games getting docked points because they don't have a "Plot / Story"...who cares? Puzzle games don't need a story! That's not the point. Including a story is usually pointless to begin with.)

Here's my ideal review format: something written out in paragraph form, that addresses all aspects of the game, without having to split it up into sections that break the "flow". The game should get one score at the end of the review, out of ten, based on the overall quality of the product. None of this "adding up the scores for different categories" stuff. Games are about having fun and being entertained, and in the end, that's what they should be rated on.

Other stuff: (1) Can't wait for the QB Games Directory! (2) Check this month's gallery...Cyber Chick is getting finished, in FB! (3) Thanks so much for your help with the Qlympics. You've been the most helpful and constructive contributor by far. I'd respond to every aspect of your letter, but I'm on a deadline, so let's just call it even and say that I can't wait for your next letter to the editor!

-Pete


Letter From James Pruitt

Would it be possible for you to release two versions of the newsletter: one with all the content on one page and another seperated into links and the first page an index? For those of us with dialup, wanting to get to a specific article as soon as we start reading can be a near impossibilty some days.

-Jimmy

Yes, it's definitely possible to release another version, but I don't know if I have time to do it. I'm barely able to get the normal version out each month, let alone a dial-up friendly version.

However, if someone else wants to volunteer to put another version of the mag together, I'd be happy to host it on my site.

So, all you READERS out there...any takers? Email me, and we can talk.

Pete

-Pete


Letter From David P.

Computer Language Shootout

Hello,

I am a reader of your magazine and I think that your magazine is good.

Perhaps the magazine can help. I know that FreeBASIC is mentioned on the following website.

This is an interesting website.

http://shootout.alioth.debian.org/gp4/index.php

Implementations of different programming languages are compared. ( speed )

For example, FreeBASIC, Free Pascal, PHP, gcc, etc.

http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&lang=fbasic&lang2=fpascal

However, FreeBASIC still needs five programs. ( I mean source codes. )

http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&lang=fbasic&lang2=fbasic

Can you mention this website in the next issue of the magazine? Hey! I hope that you will encourage readers to submit source codes to this website in the next issue. Thank you very much.

Thanks again.

David P.

Great website! It's a lot of fun comparing FB to other languages to see how it stacks up. And based on what I saw, FreeBasic stands up amazingly well. Check it out!

-Pete


Letter From Seb McClouth (QBinux Update)

Letter:

Hi Pete

First and all, I like to state that I had a wonderful holiday in Spain... When will you have time for a holiday?

It’s has been a little down time for Qbinux, but as far as I can see it seems to be a hot topic on your forum since the Qbinux –topic in QB News and Announcements has been viewed almost 5000 times (okay only sumfin more then 4700 but you get the point).

It the month or so before the holiday I created a new site and a new forum. Which can be found at http://www.freewebs.com/mcclouth. The old one is removes so that one can’t be accessed anymore.

I’d like to say that the QB-Express is the best mag I’ve ever seen (and not just because I’m posting in it). As I always say, keep it up, the good work.

Till next time.

Seb


Sub-mission:

Hi all,

As some of you might have read on the forum Qbinux was going through some changes. Some rough changes may I say.

At first I only had a working hardware-detection-system.

Then I was going to implant Novix.

Now I have starting back from square one (not now but a little while back). I’ve decided to use Novix more for reference and try to make sumfin more like Linux. For that reason I’ve been translating some of the C to Basic code, as you might have read on the forum. It all seemed to work the way it should. I do use a bit of Novix, else I would not be able to have the nvxfs, the NoViX-FileSystem. That part isn’t yet working completely working like it should, but I’m working on it.

The latest release you might have seen has a working boot-sequence, which is only the hardware detecting (which is still under development, due to some delays), and a proper login-system (not that the novix-version isn’t good), based upon Linux.

On my develop-system I currently I have slimmed Qbash version along with it. Due to the Novix-implentation problems I won’t release it yet.

I’m trying to keep the developing up to date on my website. If you would pass by check it, and don’t forget to sign my guestbook!

Well I’m going back to the drawing table and develop some more.

Until further notice,

Grtz

Seb

Thanks for the updates on Qbinux! Oh, and we're all glad ...and jealous... that you had a great holiday in Spain!

-Pete


Have a letter for the editor? Send all your rants, raves, ideas, comments and questions to pberg1@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!

What is the best QBasic game developer of all time?

With the help of Lachie Dazdarian, I've decided to run a tournament to find out who the community thinks is the greatest QB game programmer / programming group of all time.

The two of us have nominated the 50 top QB game developers, who we feel deserve special recognition for their contributions to the QB gaming scene. From these 50 choices, YOU are going to vote to select the greatest QB game programmer. The winner will receive a special award at the Qlympics 2006, which will take place in QB Express over the next few months.

I've randomly split up the nominees into five divisions. You will get to vote for the top developer in each division, and then we will have a final vote between the five finalists.

So, without further ado, here are the nominees. (Category winners are in bold.):

DIVISION 1
Aleksander Trojanowski (ATTE series)
Bulma Produktions (Suds Skins 1 & 2, Johnny Abbot's Sex Adventures 1&2)
CMC (DarkPhear)
Hamster Republic (Wandering Hamster, SpitWar, RPG, Cowbobs)
Hyper Anime (BAkuen SakuRu, Kunio Kun)
Pieslice Productions(MUX, TerraScape)
RelSoft & Adigun A. Polack (Frantic Journey)
Shattered Realm Productions (TWIGZ Engine, The Great Escape)
TopGun Software (Space Commando 1&2)
Typosoft(Ped xing's Quest, Sumo, SuperSumo 1&2)


DIVISION 2
Darkness Ethereal (Mattress Warrior, Secret Of Cooey series, In The Nocturne, Mysterious Song, Lianne in the Dark Crown, Legend of Lith II)
Eric Carr (SpinBall)
focus ZERO (Monkey Blast!)
J.B. (Sonic Xtreme)
Master Creating (Shadow Of Power, Diamond Fighter IV)
M \ K Productions (Pieces 1&2, Bob Saget Killer 2000, Fury)
Na_th_an (Jill The Goddess, Lala Prologue, Oytkator's Plans)
Pantera55 (Elysian Fields)
Pasco (Groov Buggies, France '98 World Cup Soccer)
Sasha Vukelich (Dynamic - The Colonization of Jupiter)


DIVISION 3
Piptol (Ghini Run, Squealer TNT, Kingdoms)
Future Software (BomberZone, Zelda Clone, Cobra, Space Invaders)
Jocke The Beast (Dark Woods 1&2, Mirkwood)
Lachie Dazdarian (Detective Academy, Ball Blazing Fantasy, Rocket Fuel Mayhem, Dark Quest, Another World Memory, Run 'Em Over, Pong Worz)
Mark Hall (ARC Legacy)
Oren Bartal (Super Stack, Ultimate Super Stack)
syn9 (ZeroG)
Stefan Hendriks (Arrakis)
Terry Cavanagh (The Hunt, Black Hole)
WisdomDude (Hack-Man 2&3, Cyber Chick)


DIVISION 4
BINARYmagic (Alien Terror, Anaconda)
BjM Software (DreamScape)
Danny Gump (Mystical Journey, Super Mario World Clone)
Jason Gould / The_Brain (Puz, Peanut Patrol 2)
JAWS V Soft (Mini RPG series)
Mike Snyder (Lunatix, Lexter 1&2)
Nekrophidius (Wrath Of Sona, Two Lords)
PHAT Kids(Kids of Karendow Chapter 1, PHAT Professional Burglar)
SV Reanimator (PromZone, Cyclone)
TMB (Percussor, Around The World, The Little Pixie 2, The Adventures)


DIVISION 5
Angelo Mottola (WetSpot 1&2)
Delta Code(Larry The Dinosaur 1&2, Unofficial Tournament)
Jace Masula (CODELINK, StarQuest)
Kevin Reems (Stick Fighters Brawl 1&2)
Michael Hoopman (Dark Ages)
Milo Sedlacek (MonoSpace)
Nick London / NutzBoy (Peanut Patrol)
SonicBlue Productions (SB's Bricks)
StarsDev (The Terror)
Tsugumo (Untitled, TheGame)

In order to vote, visit the front page of Pete's QB Site. (The poll can be found in the left column.)

Good luck to all the nominees -- and may the best developer win!

Results of Division 2

The top two developers move on to the final round of the competition!

DeveloperVotesPercentGraph
Darkness Ethereal3036%
Eric Carr34%
focus ZERO22%
J.B.1620%
Master Creating45%
M \ K Productions00%
Na_th_an1417%
Pantera5534%
Pasco34%
Sasha Vukelich79%
84 Total Votes

It's no surprise that QB RPG master DarkDread's group Darkness Ethereal came in with a healthy first place in this poll, but some of the other results were less than expected. The runner-up was J.B., creator of the SonicX Sonic The Hedgehog port, which, while good, is certainly not any match for some of the other games on the list (in my opinion, Master Creating's Shadow of Power, Na_th_an's Jill The Goddess, Sasha Vukelich's Dynamic, and Pasco's Groov Buggies are all much superior games, and especially because they are original, deserve more praise.)

Na_th_an came in a close third, but in the end, he was 2 votes short -- so Darkness Ethereal and J.B. move on to the next round.

Make sure you vote in round 3 of this poll, now available on the front page of Pete's QB Site.



News Briefs

News from all around the QB community, about the latest games, site updates, program releases and more!

QB Site News

QuickBasic & FreeBasic Frappr Maps!

For several months, there has been a Frappr map that shows where in the world members of the FreeBasic community live, and just a few weeks ago, Optimus decided to create one for the QuickBasic scene. Frappr maps are really simple; you enter your name and the location where you live, and you are shown on a map in relation to where the rest of the people registered on the map live. It's pretty cool to see which areas are most populated by QB/FB-sceners, and I encourage you to add yourself to both maps:


  • QuickBasic Scene
    Currently with 27 Male members worldwide, and.... 0 female members. Surprise, surprise.

  • FreeBasic Scene Map
    Currently 87 people registered worldwide, both genders. :-)

News Brief by Pete


New QB site: Quickbasic.info

Matthewr2_1, a coder who frequents the QBasic.com forums, recently launched a QB site at http://quickbasic.info/. It's very small at the moment, and is lacking in the content area (pretty much only some links, news posts and an empty forum)... but it's only been around since the end of March, so that's to be expected.


Anyway, the more new QB sites the better, as far as I'm concerned! Check out Quickbasic.info (and make a post in the Shoutbox on the side of the page!)

News Brief by Pete


AAP's FreeBASIC GFX Demo Central Reaches 120 FB Demos

Like always, Adigun A. Polack has been keeping his website, the AAP Official Projects Squad up to date, and a few weeks ago (4/27), he passed a new milestone:

In this newest update of the official projects site of Adigun Azikiwe Polack, three (3) new FB graphics demos have just now been added to the FreeBASIC GFX Demo Central, plus a vital update to Lachie’s Custom Font Printing Routines in FB appears there, too!!

With all of that, the FreeBASIC GFX Demo Central now hits a staggering total of at least 120 demos that have been produced using FB!!! So phenomenally good, huh?

See you there beginning at http://dhost.hopto.org/aapproj/ for all the goods!!!

Adigun deserves a big hand for his hard work keeping his site up to date. It is still the biggest FB programs collection on the Internet, and at this rate, it won't be losing that title anytime soon!

News Brief by Pete


A New, More Open QB Forum? / Seph Goes Bonkers

Recently, Seph was banned from the QBasic News forums for making some "unsavory" posts. This "censorship" and singling-out really struck a nerve with him, and he vowed to form a new, more open QB forum. Seph went all over the Qmunity and posted the following message, to try to stir people into action:

This is my original post on QBN. It has since been deleted and I have been banned. There was also a topic started by cha0s in the Debate section called "Stop the Fascism" which might also have been deleted. Please notify all members on QBN about this thread. The admins and mods of QBN are ruining our good fun and making it impossible to enjoy staying at QBN! Please read:

This thread is intended to be a discussion about creating a new forum *similar* to this, yet without the tyrrany.

This thread *should* be protected from locking or deletion because it brakes no rules. It is not spam, but instead a valid discussion that many might take part in.

Sumojo's post here is an example of his corruption. Finally when people started to post agreeing with me (one so far only), Sumojo posts a contradictory post saying the thread is not locked, however anyone who posts in it will be banned for two weeks.

Nek has already attempted to start a QB forum similar to this, yet it has remained largely unvisited. I think this could be for two reasons:

1) The rules are much more open than this forum and people aren't used to such a drastic change all at once

2) People don't like to change forums because it's a habit to go to the same place

3) People believe their friends will not all transfer over so they don't want to limit who they are talking to.

These can all be solved with a few easy solutions:

1) Change the rules over time by voting on each change. This will create a slow and easy transition to a more liberal forum.

2) Just change the bookmark link's address to the new forum. Not hard!

3) You don't need to make sure that all your friends go, because as long as you make certain that you (the reader of this) change over to the new forum, then everyone who reads this should in theory move to the new forum.

The only problem is that you may need to tell people who do not read this thread about the new forum.

Another MAJOUR concern.

Also, this means that some people will not move to the new forum because they do not like ME. This includes Zire and Sumojo (it's his forum) and Zap (since when did HE start hating me!?) for example. And assuming some people don't want to limit who they talk to (problem number 3) then they won't want to leave Zire and Zap etc. behind. However if they can be convinced to come to the forum without mod/admin powers (because they are corrupted) then this problem is solved.

But then the question arises, why would they want to leave power behind? Well I have another idea of how to accomplish them coming to the new forum without mod powers:

If everyone else posts at the new forum, and boycotts this forum (I mean literally 3 people posting here over three weeks, all being mods/admins), they will have nobody to moderate and will be forced to either move to the new forum or protest that forum. Of course it would be smarter to just move to the new forum without question.

This is my proposal. Even if it is deleted, I will have the original copy and email/PM/IM it to everyone here who has posted in the last two months.

-seph-

So where's this new-and-improved QB forum? Nowhere to be found. Seph was alone in his disgust with QBN; Everybody else could care less, and they treated his "treatise" like the ravings of a crazy man. I guess most people on QB/FB forums just....(gasp)... get along.

News Brief by Pete


Project News

Emporium Xenos - Whack A Mole!

The Big Bad Wolf recently released a FB Whack-A-Mole minigame:


It's a simple but fun game, features both keyboard and mouse play, and definitely worth checking out. It'll entertain you for at least a few minutes!

Download it here: http://www.sitesled.com/members/exupdate/tbbw/wam.rar

News Brief by Pete


Pritchard's Wheel Function

Here's an interesting program by Pritchard. I haven't checked it out yet....but you should!

Hey there! Pritchard here!

Recently I released a small but semi-useful Wheel Function Lib for FreeBASIC. It also includes an SNO_Print function.

(SNO_Print stands for Scientific Notation Off Print. This is useful to those who don't like the scientific notation printing FB does with very large, small, or complex numbers.)

What it does, is creates a wheel (I have a hard time explaining, but there's a screenshot), with perfectly spaced out lines, points, or images. It's really useful for that kind of small graphics effect, similar to those from the good old Sonic games ^_^;;

It comes full with Rotation, x and y positioning, size, points per wheel, space between next drawing point, and even making a wheel out of images, alpha and all ^_^;;

For those of you wanting a better image to see what it is exactly I made, here's a screenshot:


If you like the screenshot or just want the SNO_PRINT, here's a link to the original thread on the FreeBASIC forums (enjoy!):

http://www.freebasic.net/forum/viewtopic.php?t=3614

News Brief by Pete / Pritchard


Eternal Journey Demo #1

Smithcosoft Creations (SSC) has released the very first demo of his upcoming RPG, Eternal Journey. It's an extremely rough engine demo at the moment (with perhaps the loooongest credit roll of all time) -- but it looks very promising. The graphics look very nice, and the engine currently supports MP3 music, and basic scripting for in-game cinematic sequences. Take a look:


You can download the demo here: ej_demo.zip, or if you're on dial-up, you might want to spring for the No Sound version, without the 4.5MB mp3 included: ej_demo(no_sound).zip

And of course, you can check out the SmithcoSoft Creations website for the latest on Eternal Journey.

News Brief by Pete


Yagl Developer-Less...?

The speedy YAGL, or "Yet Another Game Library", which was created and developed my Marzec for the last few months, has now lost its developer. Here's a news report from Z!re:

Yagl stands without a developer, which is a very sad thing. Marzec no longer have the time, nor will, to actively develop the project. Someone needs to take over this amazing project and make it all that it could to be.

Alas, it is true. For the full story, visit the YAGL Official Site and read the latest news posts. (For the uninitiated, you can also download YAGL here.)

We at QB Express encourage anyone interested in game library design to contact Marzec for the source code, and to look into carrying the torch forward. Don't let the YAGL fire get snuffed out!

News Brief by Pete and Z!re


Too Much Cement -- The Newest Cute Short Game Project

The ninth "Cute Short Game Project" by Redcrab (last issue's programmer of the month) is here! CSGP #9, entitled "Too Much Cement," is Redcrab's biggest and most complicated game yet.


The goal of the game is to direct wet flowing cement in a hectic factory, making sure that none of it spills. Here's some more specific info on the game, from Redcrab:

Hi Pete,

May I write something more just for your exclusivity ;) , (Usable for a QB Express ?)

  • It's directly inspired from handheld game that is not really handy . Was qualified as "tabletop"
  • Color LCD style
  • It's the most complex CSGP title that I create until now: 103 different sprites. To do the comparison Sleepwalker only contains 39 sprites, HurryChef contains 31 sprites, Bouncing Stuntman only contains 5 sprites, Mushroom Raindrop 6 sprites.
  • The hero is almost free to move
  • 320x240x8 screen resolution
  • All in one source file
  • No lib dependency, No Operating System API dependency

And of course, I hope this title will be as fun as the other titles.

Regards,
Redcrab

The official CSGP website is here: http://csgp.suret.net, and you can download Too Much Cement here: TooMuchCement.zip. This is a fantastic game, and you should definitely check it out.......Now!

In other news, Redcrab has released a single program containing all of the CSGP titles in one. Get a copy at this forum post. That Redcrab sure is a busy guy!

News Brief by Pete


Jofers: "Gooey, gooey, gooey..."

At the beginning of April, Jofers posted the following at the FreeBasic.net forums, about his new GUI library. Here's the full scoop:

Okay, I posted a barebones GUI library awhile back, but because of limitations I completely canned it and started over. Well, I just hit a point where I finally surpassed the first project yesterday, so I figured I oughta post a demo:


The library's really more of an object framework than a GUI library... But it works such that I can write GTK drivers later and just compile a different set of driver modules. Plus, the modules are completely separate from the code so users can write extensions without recompiling the library. So the nice things:

  • It's a static library, no runtime DLLs.
  • Only includes what modules you use, so you can write 50k GUI apps
  • Can/will be cross platform in the future
  • Extendable
  • Simple. No jxGet_Top_Bar_Color_Around_X_Button() functions, just jxGet and jxSet


BUT, it's still a mess:

  • Event system is a federal disaster area
  • Memory leaks galore (yeah, be careful running the demo in Win98)
  • Slow development (I'm a senior engineering student, no time)


So I'm probably going to need some help, as much as I hate the thought of working with other people. First, is I'd like to redo the layouts. I was hoping to making something like "BorderLayout" in Java (the one thing they do get right), where or HTML, where someone could just plop elements in instead of having to provide coordinates (that was a major PITA making that demo). Any suggestions? (ballpark's open on this one)

So: help wanted, the more the merrier, but I really have no experience working in an online project with more than 3 people (that documentation thing was a disaster), so if anyone here has experience working in any big OSS settings, I could use some advice.

And finally, I have some questions about WinAPI in general:

  • My buttons seem sluggish, and I can't fix it. What gives?
  • Is there a way to get themed controls without making some chump use manifests. I can't use owner-drawn controls, that would make my library as bloated as wx-c.
  • Anyone know how to get TAB focusin' working?

So, there you have it. Last time I posted something like this, a bunch of people got excited and started posting technical questions about things I hadn't done yet, so lemme be clear: This is nowhere near completion, all that's in that demo is all that's implemented, and anything's open.

'Nuff said!

News Brief by Jofers / Pete


QuickRogueFB (Beta) by Rick Clark

If you haven't checked it out yet, I DEMAND that you take a look at Rick Clark's QuickRogueFB roguelike game. It's fantastic. Here's the description:

QuickRogueFB is a speed rogue-like game. There is one level, 50 monsters and a set amount of time to find the Amulet of Nikktu and escape. The game play is very streamlined so there is no inventory or stats management and a very small set of commands to make gameplay quick and easy.

Various versions of the game have been kicking around for a few months now, but the latest version truly is a must see. You can find a release here, or just download the program here: qroguefb.zip.

News Brief by Pete


Pixel Scroller by Hallifax

Hallifax recently posted a screenshot of his FB pixel scroller at Freebasic.net, and it looks pretty nice:


Since so many readers are interested in RPG programming, I figured you guys might be interested. Hey, this might end up being a full game!

News Brief by Pete


Screenshots of a game by Lithium

Lithium recently posted the following screenshots of a game he is making, which has been compared to "Bart vs. the Space Mutants" for the NES.






Lithium gave no details about the gameplay, but he did mention that he would release a demo, "as soon as [he] gets the first 5 levels done...[he's] up to 3 so far." Oh, and Lithium has never played "Bart vs. The Space Mutants", if you're wondering.

News Brief by Pete


Mandelbrot Viewer by Antoni Gual

Antoni Gual recently released a Mandelbrot Viewer program that creates some pretty spectacular graphics effects. Take a look:






The Mandelbrot Viewer is still a work-in-progress, but you get the idea. Check out the original post for full details, or just download the program now: mandel.zip. At the moment the program should compile in Win, Linux and DOS.

News Brief by Pete


Dr_D and RelSoft Dazzle with new Kart Game

Dr_Davenstein and RelSoft have been hard at work at a new (unnamed) FreeBasic 3D Kart racing game, and it's awesome. You should check it out. There is a playable engine demo available right now.






From the Readme:

Basically, this is just a demo of the engine. It doesn't keep track of any score/pole position or anything. Also, some of the models are incomplete/testing versions... You'll probably notice that some of the polygons with transparent pieces, like the guardrail, will block out certain objects behind them... this is expected behavior and will be taken care of when the time comes. ;)

They have also released a video of gameplay footage that really shows off the engine's physics capabilities.

The demo is rough, but is already leaps and bounds ahead of most QB racers that we've seen in the past. The kart models look good, the steering and physics are nice, and the racing seems pretty balanced gameplay-wise. I enjoyed my few minutes messing around with it. Unfortunately, the game runs extreeeeeeemeeeeely slooooooowly on this computer... 2 - 3 FPS and very choppy on this admittedly old computer that I'm using right now... But this is still an early demo and with optimizations, it could surely be increased substantially. I can't wait to see the next demo!

News Brief by Pete


Hello Kitty Mini-Game

Pritchard recently released a mini-game based around the popular Japanese character Hello Kitty. The reason he made it is sad but heart-warming...


Here's a Hello Kitty game I made for X_Toaster_X. She's around 20 and has cancer. I really wanted to make her a game just because she's a nice person. Tell me what you think and tell me if the exe has the kitty icon ^_^;;

Note, You need winzip or winrar to use these files:

http://fileanchor.com/22967-d - Hello Kitty.rar
http://fileanchor.com/22968-d - Hello Kitty.zip

No Sound:

http://fileanchor.com/23014-d - Hello Kitty.rar
http://fileanchor.com/23015-d - Hello Kitty.zip

Source-Code (To compile, download normal version above, then paste .bas in Hello Kitty main folder. Compile ^_^;:

http://fileanchor.com/22986-d

We all hope that X_Toaster_X gets better! (I'm sure this game will help.)

News Brief by Pete


BALLSBREAKER!

NovaProgramming released a FANTASIC mini-game a few weeks ago called BALLSBREAKER. It's a very simple concept, but it's a lot of fun and very addictive. With your mouse, you must knock a board full of stationary green balls so that they're all "rolling" -- but once they start moving, they become red and you must avoid them. Play it, and you'll understand.


You can download the game at this link: BALLSBREAKER.zip.

BALLSBREAKER proves that good gameplay trumps all else when it comes to game design. Try it out, and be sure to post your best times in the BALLSBREAKER thread at QBasic News!

News Brief by Pete


Kryton - Gravity Graphics Demo by Klyde

You've gotta check out this awesome FB graphics demo by Klyde. It's called "Kryton", and it was made in FB from Gravity.


If you're into graphics effects, this is some of the best FB eye candy I've seen all year. Get it here: Kryton.zip

News Brief by Pete


Aflib2 Released!

Adigun A. Polack's Aflib2 is here! He posted the following at QBasic News:

The wait is finally over!!! AFlib2 - Aura Flow Library 2 is here at long last after almost one (1) year in development, and it is the grand successor of both RelLib and the first AFlib for QB. This ALL-NEW game library incarnation for FreeBASIC features a ton of jaw-dropping, never-before-seen stuff including Waterfall, Scale2X/4X/8X, Screen-to-Sprite collisions, Screen-to-Screen collisions, custom graphics filtering, and a whole slew of others!!!

Grab yourself a copy today beginning at http://dhost.hopto.org/aapproj/ and your FreeBASIC game programming will NEVER be the same again!!!

Amazing work on Adigun's part, but I'm sure you figured that much out already!

News Brief by Pete


Thrawn Releases "Ploader"...A Library to Load PNG Files!

Now this is a useful release: a PNG library for FreeBasic! Thrawn posted the following on the Freebasic.net forum on May 3rd:

Well, some of you may have heard of this project already, it's a library to load png files.

The goal was to make a library that would load a PNG file written in FB, it was ment to be as easy as Bload(), thus the name Pload()

It does Alpha transparancy and everything, well...currently does not support all of the Interlaced types, but that's it....

Apparently this has been compiled and tested by v1c under v0.16, so good luck: Download Ploader Here

It is also fast, so dont worry about that. ;-)

~Thrawn~

PNG is clearly the best image format for the web these days, and it's got all the features that make it useful for game programming: low file size, high fidelity, transparency and wide compatibility. And now you can use PNGs for your FB programs, thanks to Thrawn!

News Brief by Pete


Piptol Ports Kingdoms to FreeBasic!

One of the best QB strategy games is now *THE* best FB strategy game! Here's the news, straight from Piptol himself:

Old-skool fantasy/strategy game Kingdoms has received a FreeBASIC makeover, 5 years after the original QB release.

So now it's a fully fledged Win32 game, the same game you know and love with a few new surprises! This version adds some new characters to help or hinder your Ablyssian adventures, there's minor graphical improvements, resampled music and faster battle sequences.

Come get it while it's hot at Piptol Productions!

Direct download: http://piptol.qbasicnews.com/files/kingdoms.zip

If you haven't tried Kingdoms, give it a shot -- it's simple, but also very entertaining. I'm sure you'll love it. But then again, I'm a big fan of Kingdoms...as you can probably tell.

News Brief by Pete


Competition News

Qbasic.com T-shirt Design Contest

Mark Wilhelm, webmaster of the new QBasic.com is running a t-shirt design contest. Whoever designs the best shirt will receive a free shirt with their design on it, and everyone else will be able to purchase shirts for $10. No word yet on a deadline for the compo, but several people have already made entries. For more information, check out the official contest thread. "Ladies and gentlemen, fire up your PhotoShop!"

News Brief by Pete




Gallery

Written by Pete

Every issue QB Express features a preview and exciting new screenshots from an upcoming QB game. If you would like your game featured, send in some screenshots!

Cyber Chick

Way back in 1999, when I was still working on the first iteration of Pete's QBasic Site, WisdomDude emailed me one day with a little QB engine demo he'd put together. I loaded it up to find a smoothly-animated, one-room 2D shooter/platformer engine, similar to Metroid -- but starring a pudgy woman with pink hair and a spreader gun. Back in those golden ages of QB, this was one of the most impressive demos I'd ever tried, and after chatting with WisdomDude about his plans to make a full-featured adventure game, I was waiting with bated breath. This was Cyber Chick... and it was good.

Since WisdomDude (or James Robert Osborne) didn't have a website of his own, I created a dedicated section of my site for Cyber Chick. Every few weeks, religiously, WisdomDude would release a new demo of Cyber Chick, and for months, I'd post them in the Cyber Chick section. (Go take a look, it's still there.) In its first year in development, the engine made terrific progress, and WisdomDude released a total of 36 engine demos. Cyber Chick looked like it was going to be one of the best QB games ever, and a large and growing number of fans. Unfortunately, around the time of engine demo thirty-six, I began my hiatus from the Qmunity, abandoning my site and the Cyber Chick page. WisdomDude continued working on Cyber Chick for many more months, and eventually released some Cyber Chick demos with some more significant gameplay -- but just like with me, real life got in the way and Cyber Chick fell by the wayside, half completed.

Flash forward to 2006. It's been years since I've even thought about Cyber Chick, and everyone's presumed that the game had joined the mass graveyard of perpetually unfinished QB projects. So imagine my surprise when I heard from WisdomDude that he's picked up Cyber Chick where he left it off all those years ago, and was planning to finish it in FreeBasic!

That's right, folks, SEVEN YEARS after he began work on Cyber Chick, WisdomDude has released a new demo of the game that once rocked the QB world. And it is looking better than ever!

According to WisdomDude, the engine is now complete, as well as most of the graphics. The demo also features high-quality music and sound effects. The most of the work he has left to do is create the remaining levels and worlds that you will fight through with Alexa (our heroine). No estimate yet on a release date, but I can assure you, Cyber Chick is far closer to being released than it ever has before. :-)

Download the demo: CyberChickFB.zip (17.3MB)

And without further ado, here are a series of screenshots from the most recent Cyber Chick build. Check out all of the different areas, graphical styles and gameplay varieties in this game. It looks simply incredible:





















QuickRogueFB - Game Review

A review by Kristian Virtanen (lurah)

INTRODUCTION:

Well, most of us knows who and what is rdc. From his website, you can find nice range of games, programs and even books to enjoy. "Latest" (when writing this review, he's been very productive so thats why I say "latest" lol) one from rdc's coding garage is QuickRogueFB. An ASCII (quick) rogue game.

ABOUT QuickRogueFB:

Everyone who has ever coded with QB, still codes or has even heard of it knows what is text based roguegame, so i guess that part don't need more explanations =) QuickRogueFB as in name of game sounds like a promise of fast, thrilling and intensive playing experience. "There is one level, 50 monsters and a set amount of time to find the Ammulet of Nikktu and escape." Also name of programmer put some extra expectation for it.
Very easy to learn. Basically what you need is direction buttons, "t" for teleporting, "g" for gettin potion, "z" for some monster zapping and "<" or "," to exit from level when Ammulet of Nikktu and exit point has been discovered. Sounds easy? It is. Boring? No.

As an ASCII "fanatic" i was pleased when intro of game appeared on my screen.



My first try with this game was pure suicide, in every possible way...



And now, for the review itself. Playability, overall entertainment, rogue likeness, replay value and technical feature.

PLAYABILITY: Score (4/5)

Simple to learn, quick to play and nothing special...read also as "useless". rdc has added practically all things on game that is needed. No inventory, stat menus, buying or selling. Its max. one hour gaming experiment / game so nothing much more needed. Only thing i actually missed was bow or spear so i could try to kill monsters from a distance. Zap is close to it, but its not 100% the same thing.

You can't see thru walls, doors, far beyond straight passage either, enemies behind the corner...very nice and working concept and in this case, it really works too. Small map view on the down right ofg the screen is also very clever and it also helps from time to time. Enemies are letters, floor are dots, traps are...never mind and everything is easy to figure out in seconds and remember even then when HP is 10/81 and there is those few penguins around you.

OVERALL ENTERTAINEMENT: Score (4/5)

Well, ASCII games requires, first of all, one thing from player, imagination. Without it, apparently no chance to enjoy those games. Gladly, my imagination is at least universal :D Took only seconds and i was in dungeons, hiding from monsters, sneaking behind their backs and avoiding traps. Map is big enough and different at every new time when playing. When monster sees you, it runs after you, often there is few of them but with some clever moves you can locate yourself at point where you can fight with only one at time. Even if the main goal is to find Amulet of Nikktu and exit point, each time i wanted to explore "just a bit" more caves....and bit more...and bit more...until clock sayd time is out...damn :D Potions gives or takes from you something. Quick healing, mana points and so on. They also can prevent you for using teleporting, slow you down etc. Potion at corner of room in middle of tight fight can be a saver or ultimate game over.

Oh no!!! Scotty cant beam me up and safe...

ROGUE LIKENESS: Score (2/5)

Maybe ill miss things on this that rdc havent even planned, because of the game's quick style. Fights are pretty simple ones after finding a good location, if more than one bad ass is trying to beat you. Just press the enemy's direction and that's it. Zap is nice add, but won't fill the whole hole of good ASCII rpg combat. Personally, opinion is, bow or spear is needed for long distant fight. Also "all in defence" or "all in attack" choises in combat would make fights more interesting. Although comparing what this game offers and whats its nature, roguelikeness is "OK".

REPLAY VALUE: Score (4/5)

This game is surprisingly addictive, i wanted to achieve the goal and finish it as winner. But what then? Is it all over then? Well, for me quick cave investigations were allmost more important ones than Ammulet of Nikktu. Is it because of me or this game? Can't tell, but somehow this game calls me back to it from time to time. Been playing it lots of times, and probably I'll do so in the future too. After reaching goal of game, fun part is more on studying caves instead of finding Ammulet and exit. And its fun to fight against Jocke the Troll and other monster buddies. This is a pretty quick game, is good way to forget our own "stuck" codes, dirty floors that screams vacuum-cleaning or angry girlfriend for a while. Some prople do it with solitaire, but I'll suggest you to try this too.

TECHNICAL FEATURES: Score (4/5)

Well, what to say? Game is simple and nice. Alltho no sounds or music. Most likely, rdc didn't want to add them because of the nature of the game. ASCII rpg with mp3's? No way, at least for me. But maybe possibility for listening some MID song or few sound effects might give more that "feeling". But as told, this is ASCII rpg, and a very well made one too. Graphics are good ASCII stuff. No useless tricks, known and workable chars are used and colors works fine.

THE FINAL VERDICT: 18/25 (72%)

Fact is, There is more than alot of ASCII rogue games, some if them are great, others are something totally different. rdc's QuickRogueFB is good add-on for this scene. It's simple, easy to learn, hard but not too hard and no bugs on code (at least i didn't find any). It definately earns its rightfull place on all ASCII/Textgame websites game lists, right next to adom and other known rogue games. As is now common knowledge from rdc, the source is included with the game and in the same light, it's great source to learn from, so if you're interested for creating your own roguelike game, then this game is good to have a look at.

Also, I'm not sure is this the final version of this game. (BETA) was on the topic where i downloaded the game from, so there is more than good chance that rdc still adds something new to this game. For sure, I'm gonna keep an eye on what he's doing with QuickRogueFB.

In case you wanna check rdc's QuickRogueFB, then just click here or visit rdc's website.
Game tested with XP and Ubuntu linux.

lurah
Kristian Virtanen
virtanen.kristian@ascii-world.com


Making a QB or FB Site

Written by Pritchard

Hey there! Pritchard here! As you may or may not know, I have absolutely no experience in making a QB/FB site or a forum, so bear with me here.

Making a New QB/FB Site


Plan Out Your Intended Audience

This has to be the most important part of making a new site. Whether it's a C site, an animal site, or the oh so famous around here (for whatever reason ^_~) QB/FB site!

Why is this important? Well think about this, if the official Microsoft site was full of Java Games and had Theme Music in the Background from a Java Game, who do you think would come? Java Programmers? Interested Microsoft Developers with years of experience? Nope! Teenagers! - and people wanting a few quick jokes and a place to talk l33t.

You have to, have to, have to figure out what your intended audience for the site is. Now, I'm not saying that your intended audience is just an age group, I'm saying not everyone likes the Professional Setup a site like "FB.net/forums" has who's over 25. No Avatars, Simple Color Scheme, and very serious posts expected at times. Not. For. Everyone.

A site like QBasicnews.com though - Avatars, cool black background, more forums to hang out with and discuss things other than the main language, and a smiley that's throwing up feces. . .Now that attracts the audience that's generally not coding QB/FB to put food on the table, or maybe they are. Right now though, they just want to have fun ^_^;; - Or maybe one of the largest QB forums around hahah.

There's other sites. Other Features. More things you can have that attract your audience. Think right now before we go on. . . Do you want to make a site that attracts mainly and almost always, the people who want to work in the most professional manner, or do you want a place where fun comes first? I know there's a lot of in betweeners and I can't put all programmers in just two groups, but that's something to think about.


Think of What Attracts That Audience

Now we are kicking it! Whoot! Alright, what attracts the audience you would like on your site? You decided on a "feeling" you want the site to have? Wild and Crazy!? Strict and Intelligent? Mellow, simple yet flexible? I hope you've made up your mind, because now you have to think of what attracts the audience you want.

What Makes a Site "Fun-Based":

Example: http://forum.qbasicnews.com/index.php

Anything else for "Fun-Based" sites? Yup! Lots! I just can't think of all of it right now! But you're the site designer, or interested person, not me. You have to think for yourself sometimes. Just make sure that with a "Fun" Site, the environment's free and optimistic. Personally I think later on, we need an FB-site that's Fun-Based that links to the Official Site (Just to be Polite).

Remember, Fun sites are about the information, but more about the community and the people there than the hard-work we do to keep up with the community. It's one big party!

What Makes a Site "Professional Work Based":

Example: http://www.freebasic.net/forum/index.php

We all know that there's a lot more that could go in a Professional site. It all depends on how far the project the forum/site is about is. But you have to make sure not to attract a bunch of teenagers looking for "l33t h4x1ng t0015" on your professional based site. People don't like having people like that respond to their well-written posts with detailed information on the problem they're having.


Plan Out Your Site Features and Scheme

Alright! Now you should have some idea, with a little thought, on what kind of site you want to make and what you want to put in it. Now how do you put it all together though? Simple.

Each and every place on the computer screen that people use to view your site is of great importance. You must use a complex algorithm to figure out the placing of each and every link, image. . .

Wait no!!! What the heck are you thinking!? Oh wait, I typed that...

Yes the placing of everything is important, but it's not that hard! Your site should have a basic home-page stating what the site is about with links to the forum, downloads, links to other sites, and depending on your site theme, maybe a jokes section or technical information page. Or both? XD!

The Home Page can be very serious, or maybe an update from the Webmaster to all his friends, "Yo guys what's up? Think I might add avatars today, so I'm preparing myself for a visit to the hospital. Who know what nonesense people will put for images as their avi".

See? Isn't that different from "Version .8 is out today. Basic new Features include File Paging, G-code asm support, and big-endian support. Read the changelog for full changes."?

Very different sites you can tell, just from the introduction to the site. You should build each and every page this way. Get serious when you need to for humor sites, but make sure that you're sticking with the general theme.

Contact information could be on a technical support page for a professional site, or maybe on the forum or larger on the games section for a fun site. I don't know. Webmasters tend to build their sites different ways once they get going, so prepare to fool around a little.

For Scheme Color and Layout, here's some basic coloring info:

Fun Colors - Orange, Black, Yellow, Blue, more than one color

Professional Colors - Gray, White, Something Simple - Can still be very beautiful though

Wicked Colors - Green, Purple, Red, Black

And those are just a few examples. Imaes of skulls, butterflies, or none at all - Maybe just plain backgrounds, start plotting it all around and in no-time you'll have the basic feel for your site.


Conclusion

Well I kinda dozed off near the end of writing this article, but haha...It was fun! I was able to have so much fun because I'm currently on a fun site.

Your audience should be unique. That's important. If you want to make a site just to have a forum for you and your little buddies, don't spend 5 months planning it out, and of course, have a good time with it.

If you want a big site where you have a lot of features, you want your word to be spread everywhere, take your time, and make sure your site isn't a clone of the rest out there. If it is, change it.

Hope you don't have too much trouble,

Pritchard


Download a copy of this tutorial, or visit the original thread.


Creatively Writing Game Story Lines

Written by Nathan1993

You remember reading DarkDread's series, right? The first tutorial was about a story, mostly what not to do. Here is a little piece to tell you what to do. Forget every game you have ever played. Why do Mario and Zelda survive on a simple story? In Zelda, look at all the side-plots, like saving the Gorons, Zoras, etc. You get it! Use your imagination (if you still have one) and come up with a great story. Here's how I would start:

Jyla heard a rumbling, shaking his very home, deep in the night. As he woke up, he slipped a simple tunic on and ran outside. The village of Yehan's worst nightmare has been realized. The massive snow buildup started falling from the top of Mt. Yehan, coming straight for them. Yehan's residential area was directly in the path of the snow, ready to get slammed. Soon others start coming out of their homes, realizing doom was near and embracing for the worst. They had no plan, for they were all in denial that this would ever occur.

Jyla knew he couldn't stand there, allowing his doom to arrive. Yet he knew he couldn't stop the snow. It was like an arrow: you can't stop it, and you know it's coming. So what do you do? You try dodging it. He couldn't hide anywhere, he would just get trapped in. He quickly sprinted inside, grabbed his knapsack. Knifes, rations, and a jacket was able to be located but he was too stressed in time to get anything else. He had to leave soon. Now.

No one could be taken with him, it would slow him down. Most people were just started to realize the peril they were in. Some were in denial. Others we praying to their God's, begging for forgiveness. As he started his way out of town, he noticed many fields of corn. Their city rained often, for it was in the path of rain shadows due to the mountain...

Now is the where the multi-linear part would go. You have a great story, with cause and effect, environment, multiple reactions, and a believable (or not too far-fetched) story. The played can now do many things, like stock up on food, see what others are doing, make peace with his God, or get the hell out of there! Obviously there would be more than one option for where to go. You could try to go around the mountain, go up and around the mountain, try to block it, or outrun it... a million things could happen. The limits are what you are willing to do.

Hopefully this has given you an idea of what you can do to create a story other than “The evil wizard stole the princess!Armed with only your sword and shield, you have to train until you are able to save her!” Some important points:

Thanks for reading my article on creative story lines, and I hope it gave you ideas and a new perspective on how you should go about developing game story lines. Remember, your story should take more work than your engine!


You can email Nathan1993 at nathant93@gmail.com or download a copy of this tutorial.


The Fallacy of Meaningful Codes

Written by Moneo

In the early 1960's, I was working on a programming contract for Schering Corporation to implement a Production Planning and Control System. My mentor, Tony Penta, was the project manager. In addition to programming, I was assigned the task of creating the codes for the Product Master file. I analysed all the possible classifications, and designed a code composed of fixed-length sub-sections such as: group, class, department, etc. I proudly showed the code design to Tony Penta. He took a look at it and said the following words which I never forgot: "Ed, the more meaning you put into a code, the quicker it will corrupt."

Tony went on to explain that sub-sections of codes, like the department for example, today fits fine into a one digit number, because today they only have 6 departments. But what happens to this one digit code tomorrow when they expand to 40 departments? Even converting the one character position to alphanumeric would not hold the required combinations. The structure of the code would have to be modified to add extra digits, and the result would be a corruption of the original code design which would require a costly conversion project to convert all the related files, input formats, and reports.

He explained that the safest and simplest approach to code design is completely random or consecutive numbers. How many products do you have today? let's say you have 5000. That's a 4 digit number. Then, allowing for expansion, make the code 6 digits, which will allow the company to grow to 1 million products.

It took me a while to grasp the magnitude of Tony's warning, but then I kept it fresh in my mind for the rest of my life.

The biggest argument that I ever got in support of meaningful codes is that you can look at a code and tell what the item is based on the digits of the code. This is only true if the code has not suffered any changes in format. Hey, if you want to know what exactly an item is, lookup the item's code on the Item or Product Master File. Another argument is that meaningful codes are easy to remember. The truth is that people who work with the items/products every day, can just as well recognize or memorize the codes that were assigned without meaning.

Here's a few examples...

In 1983, at a computer assembly company in Mexico, I was developing a complete manufacturing system. The industrial engineers, who were from Ericsson, had begun design of a part number, which curiously looked very similar in style to the original product code that I had designed back at Schering. It took me quite some time to convince these engineers of Tony's rule. We finally decided on a 6 digit, numeric part number with no embedded meaning.

In 1990, while at Citibank-Mexico, I was developing a Manpower Planning system, for which every job or post had to have a unique code. My boss, the IT director, already had a design in mind consisting of 10 digits, of course with all kinds of meaning in the digits. So, I let him have Tony's rule with both barrels. Amazingly, he thought about it for a few minutes, asked a few questions, understood it, and said "Do it." Since we had less than 1000 employees/jobs, we went with a 5 numeric digit job code.

A classic example of code corruption is the Mexican TaxID which is the equivalent of the USA Social Security Number. When I arrived in Mexico in 1983, the code consisted of 4 leading alpha characters plus 6 numeric digits. The 4 alpha were taken from your last name, mother's maiden name, and your first name. The 6 numeric were your date of birth as YYMMDD. When I first saw this code, I immediately remembered Tony's rule.

Well, sure as heck, in 1991 the government announced a "new" 13 character TaxID, where they had appended an additional 3 alphanumeric characters in order to solve the problem of collision in the numbers. The conversion of existing computer systems was chaotic. Some companies attempted to generate the extra 3 characters using algorithms of dubious origin. Actually, the government never published the algorithm because it really wasn't an algorithm perse. The logic was contained in one continuously changed program at the central bank. I happened to see this program, and was amazed at the amount of hard-coded exceptions that it contained especially to inhibit generating codes that contained "dirty" words.

To make matters worse, in 1999, they announced another code called "CURP: the unique code for population registration". This beauty did not substitute the TaxID, but had to be used in conjunction to the TaxID for payrolls, invoices, taxes, etc. This CURP code is 18 characters long, using the first 10 characters of the TaxID, and adds additional "meaningful" codes, such as sex, place of birth, the first consonant after the start of last, mother's maiden, and first name, one numeric digit (normally zero) to be modified for duplicate codes, and a check-digit whose algorithm is a goverment secret. If my dear friend Tony were to see this code, he would turn over in his grave.

*****


Download a copy of this tutorial: Meaningful_Codes.txt


Artificial Intelligence Technology Reviews

Written by Stéphane Richard (Mystikshadows)

INTRODUCTION:

Artificial Intelligence is still a fast growing science. Today, more and more applications of A.I. are created and there's just no telling what the future holds for it. No matter how you slice and dice it, Artificial intelligence has evolved greatly over the past 20 years or so. Today you can find highly specialized fields of A.I. that have very specific applications. This brought me to wring this article whihc aims at giving you the most widespread A.I. technologies with their descriptions along with some reference links for each of them so you can learn more about them and see where they might fit in your projects. Here is the list of technologies we will be covering in this article.

  • Knowledge Tree Architecture
  • Learning Machine Architecture
  • Process Of Elimination
  • Decision Making Engine
  • Expert Systems
  • Fuzzy Systems
  • Case Based Reasoning System
  • Support Vector Machines
  • Neural Networks
  • Bayesian Networks
  • Behavior Based Artificial Intelligence
  • Evolutionary Computation

As you'll see here, there's atleast one good purpose for each of these A.I. systems I'll describe here. These fields can be used in anything from games to real simulations to anything inbetween as well as domain specific applications. So have a read, you just might find something interesting here.

Knowledge Tree Architecture:

What It Is:

Knowledge Trees are, as the name says, more of a data structure than an actual A.I. Engine per se. However, when such a structure is devised and implemented, it makes it easy, with minimal code, to interrogate the knowledge in such a way to answer questions. The general idea behind this structure is that you go up the hierarchy to determine the knowledge element's classification and go down the hierarchy to determine a knowledge element's information contents. You can say that a knowledge tree and it's functionality is more of a search algorithm than an A.I. specific engine however if the tree is organized the right way, the responses you may get might surprise you.

One of the classic example if this type of organization is of course the Life classification tree (the Taxonomy chart) where plant, insect and animal life are grouped under their species groups in order to make the information about a specific lifeform easy to follow down the hierarchy towards the specific details of the given lifeform. With this type of structure you can easily know that a dog barks, has 4 legs, by going down the tree right down to a dog's specific information. Going up the tree will tell you such things that a dog is a canine which is a mammal, which is an animal lifeform, and so on and so forth. It's one of the oldest form of knowledge organization for the purposed of later retrieval of that information there is. It's also one of the best one when it comes to organizing a vast amount of knowledge.

Where you can learn more:

Learning Machine Architecture:

What It Is:

Another one of the classic A.I. fields. One of the first Learning Machines applications was a program that could "learn" to play chess and get better at it with every game it played by somehow saving moves and strategies that it tried that worked. Today, this field pushed itself quite forward where this knowledge can also be statistically and mathematically evaluated to determine the best possible moves based on the current position of the player's pieces and the location of the enemy pieces. Today, a real A.I. based Chess program is quite hard to beat as it can anticipate the player's actions alot more accurately.

Chess playing is not the only field where machine learning can be useful. This technique is still used in many simulation based projects to anticipate reactions to decisions/moves made by one of the elements of the equation. All in all, learning machines are problably the most widespread older A.I. engines you can find.

Where you can learn more:

Process Of Elimination:

What It Is:

This Technique is based on the classic detective Sherlock Holmes. Essentially you define a conclusion by defining all possible exceptions and alternatives and proving them wrong. Once all the of the alternatives have been proven wrong, the one and only remaining alternative therefore must absolutely be right. Of course, in such a system, the more alternatives you can prove wrong (hence enter in the system) the more valid you make the right alternative. Depending on the domain in which you elaborate the system, making sure all alternatives are present and accounted for can become tedious due to the amount of data you need to enter for the alternative.

One of the best system to use to implement this type of A.I. application is of course Prolog (also known today as Visual Prolog). Prolog is just the language to implement process of elimination systems of all types. Whether it's a very small system or a big complex one. Just keep in mind that this specific type of A.I. application can only be as accurate as the data it works with. The more complete dataset the more precise the conclusion the system will arrive at.

Where you can learn more:

Decision Making System:

What It Is:

We can define a decision making system as an application that can come to a decision, a choice between two or more alternatives (conclusions). The means by which the system can arrive at that decision is where the science lies in this type of A.I. application. The main idea behind decision making can be pushed all the way to actually making a decision. It seems however that Decision Support Systems are the most used types of decision making systems. Basically help the user arrive at his own conclusions based on what the support systems yields as results.

One of the most widespread of these tools is of course the "Monte Carlo Method". This method is often used in business when evaluating risks of failure of projects and/or investments strategies. But it doesn't stop there. Monte Carlo excels when the need to calculate results based on many variables (that are hard to calculate) are involved. For example, Integral calculations. But there are also other fields where the Monte Carlo Method can be applied. As you'll see when you take a look at the links below.

Where you can learn more:

Expert System:

What It Is:

Expert System is a class of A.I. that has been developed back in the 70s by researchers in artificial intelligence. This concept serves to simulate how an expert in a given field would act or react to a given situation that requires his expertise in the field. Contrary to popular beliefs, Expert Systems are not meant to replace the experts but rather work with the expert on a given situation. It's common practice that the expert be present to change and adapt the expert system depending on what new technologies and theories arise in his particular field of expertise.

Expert systems are used all over the place in car diagnostics, medical field, and so many other fields. Expert Systems are designed to work with a wide range of domain specific data in the field. As such, and because of the vast amount of related data needed by an Expert System, it's usability is usually restrained to a very specific area of expertise. If it wasn't, the amount of research, analysis, calculations and processing needed would become quickly overwhelming.

Where you can learn more:

Fuzzy Systems:

What It Is:

Fuzzy Systems (Fuzzy Logic itself) is a science that deals with uncertainty. It is designed to reason approximately rather than precisely. Fuzzy systems are probably the most wide spread of the A.I. systems yet it is also one of the most contraversial. For example, statisticians reject it because they claim that probability is the only sure means of defining uncertainty. Nonetheless, Fuzzy logic has it's share of userbase and so far has proven itself amongst all the uncertainty based domains.

Fuzzy logic is widely used to control household applications like a washing machine (to determine the load size and adjust the washing cycle accordingly) or even a refrigerator. The best area where fuzzy logic is used is in high-performance error correction to improve information reception over a limited-bandwidth communication link affected by data-corrupting noise. For example Two decoders may analyse the data in parallel, arriving at different results for the values intended by the sender. Each can then use as additional data the other's likelihood results, and repeats the process to improve the results until a consensus is reached as to the most likely values.

Where you can learn more:

Case Based Reasoning Systems:

What It Is:

Case Based Reasoning Systems are applications designed to solve situations and problems based on similar past problems. For example, a computer technical support that fixed a printer that won't print based on other printers that weren't printing that he fixed is using case based reasoning. There are many other fields that use case based reasoning as well. Anything that can be solved based on other solutions to the same kind of problem that worked before can be thought of as case based reasoning.

In essence, Cased Based Reasoning Systems is based on a four step analysis method. The first step is "Retrieve" which means that when a situation occurs the first thing to do is to recall any and all past experiences that was of a similar nature that pertain to the current situation. The second step is "Reuse" which means that if the past situations were solved using a given suggestion, they should be applied here first to see if they will solve the current situation as it did the past one. The third one is "Revise" which is apply the passed solution to the current situation to see if it worked or not. The last step is "Retain" which means when the solution has been applied (adjusted if needed) to the situation and it worked, save it as a new case to add to the arsenal of past experiences to work with.

Where you can learn more:

Support Vector Machines:

What It Is:

Support Vector Machines are defined as a set of related learning machine used mainly for classification and regression. A vector means that it works with a list of related elements or items that have to do with the give system to analyze. For example, sets of data that may need some form of classification before it can be processed in some way. SVMs are typically used in combination with other A.I. methods as their main purpose is to organize data (much like the knowledge Tree Architecture) but in lists of related classified items rather than a hierarchy or tree of items.

One of the fields that this method can be used for is GIS systems where perhaps longitudes and lattitudes may need to be geographically sorted out before one can apply any geographic based calculations or apply a dataset of elements over a specific geographical set of longitude and lattitudes. In that respect, there are of course many mathematical fields where such a technique can be applied for example to analyse the graph of a mathematical function or specific formula.

Where you can learn more:

Neural Networks:

What It Is:

This techniques was inspired entirely by the way neurons work in our brains. A Neural Network is nothing more than a much of neurons (nodes) interconnected to each other (exchanging information) in order to seamingly work as a group towards a final result. Each of these Units are so simple that their states are represented by a single numeric value. Each of the units generate their results based on their activation value. In the network, some of these units can weigh more than others (influence the outcome) and that influence is also represented by a numerical value. Needless to say that Neural networks since they start as very simple elements need to be trained into their application so to speak. Hence before a neural network can be used, it must be "educated" into what it is dealing with, how it will deal with it and what the output should be based on what they should do with these values.

One of the major fields of applications of neural networks is pattern recognition. For example, the ability to recognize a person in a photograph based on the evaluation of the distance between the eyes, the width of the mouth and nose, facial characteristics like scars (if any) and the likes. Needless to say that Finger Print recognition would be a good application of a neural network system. It's among the newest A.I. engines and more and more fields of application of neural networks are discovered as it's usages evolves and progresses.

Where you can learn more:

Bayesian Networks:

What It Is:

Bayesian Networks are best described as graphs. Calculated graphs that give you 2 types of information. The points (or nodes) on the graphs represents the variables themselves while the curves on those same graphs represent the dependance relations between the variables of the graph. Learning the structure of a graph, in the case of Bayesian Networks, is just as important as the data (nodes and curves) that were generated as it also describes the recipe, so to speak, that was used to generate the graph.

Bayesian Networks are used for modelling knowledge in such fields as gene regulatory networks, medicine, engineering, text analysis, image processing, data fusion, and decision support systems. with this wide range of applications, it goes without saying that like neural networks, a Bayesian networks need to be trained into it's field, however, the training principles differ from the list of numerical values needed by a neural network because numbers, formulas and rules can be used to train a Bayesian network.

Where you can learn more:

Behavior Based Artificial Intelligence:

What It Is:

This is a process by which a character (in a given seen) is predetermined to follow a specific set of rules as far as it's environment is concerned. The oldest of such example is the classic game of life where a dot lives as long as there isn't too many neighbours in which case it will die. But today things have evolved a whole lot in that field of Artificial Intelligence.

One of the best modern examples of this is a group of whales the travel from place to place, there is typically a leader in the group, if they detect a good enough concentration of plankton, they will dive to eat but if it's not a high enough concentration of food, they will typically just keep on travelling. The whole process involves setting things in regular motions and adding influencial parameters to the general formula. Needless to say that there are many domains where this technology can prove to be more than helpful and useful.

Where you can learn more:

Evolutionary Computation:

What It Is:

Evolutionary Computation is a rather brand new field, technically a subfield of Artificial Intelligence itself. This can't be eplained in once sentence alone because Evolutionary Computation is really a set of sub technologies that can all be used with the goal of achieving Evolutionary Computing. Evolutionary Computation can be recognized by a list of criteria. These are: Iterative progress, growth or development, population based, guided random search, parallel processing and they are often biologically inspired. In other words, they are often simulation of real world biological evaluation and organization that can be observed in biology.

As you can imagine, one of the main fields of application of evolutionary computation is life and ecosystem simulation. The classic game of live can be thought of as the first Evolutionary Computation experiment in a way. Where Behavior Based A.I. focus on the intelligence of animals and how they respond to their surrounding in a present context. Evolutionary computation can be thought of as as how an organizm, life form, human, anything else that can evolve, adapts to it's current environment if a need to adapt is present. Sure some of this can be implemented in behavior based A.I. But Evolutionary Computation is idea when simulating organisms and other lifeforms that actually need to genetically mutate in order to really adapt to their surroundings. As you can see, this ends up being a very different type of application all together althought some mutations are caused by a reaction to an organism's environment and direct surroundings.

Where you can learn more:

IN CONCLUSION:

There's no doubt that Artificial Intelligence is a very broad domain that has many fields of applications. It's also no doubt that each of these fields of applications ramify themselves into even more sub fields. It would take a very big book to really cover everything you need to know in the field of Artificial Intelligence. What I hope to have gained with this articile is that I have made you curious enough to persue your quest for knowledge in the A.I. Field. One of the main reason each A.I. technologies I described here includes links to even more information about the technology.

I'm always open to discussions and answering questions, exchanging A.I. experiences and Method of operations with anyone, so if you have a question, if you know of a specific application of one of the fields mentionned here that I haven't specified, be sure to email me (see my email below) and let me know about it. I'll be happy to modify this article to reflect this new found information. Until next time, happy coding and learning (if you choose to further study one of these fields).

MystikShadows
Stéphane Richard
mystikshadows@gmail.com


Download a copy of this tutorial: aitechnologyreviews.html


What Not to Do as a Programmer

Written by Imortis Inglorian

This article will be different from the ones I have done so far (notice my vanity in assuming that people have noticed my writing style). This article will be more along the lines or a rant about things that I see in programmers both on the net and in my everyday life. I will start with my biggest pet peeve.


Category 1: The "Why Would You Want to Do That?" category

I don't know home many times I've said something to someone and gotten this response: "Well, why would you want to do that?" This question and be in response to any number of inquiries or statements of intent. More often than not it is because you are using a programming language that the other person either a) doesn't know how to use, or b) doesn't prefer to use.

I also place in this category people asking questions like "How can I do [insert task here] with [insert library here]," and having people respond with "Use [insert other library here]." If a person doesn't know how to do what this person is asking, how they are asking, that person should tell them as much. It makes the responding person sound arrogant and unpleasant to deal with. As a manly man (read: testosterone junkie), I often find myself doing this in order to avoid saying "I Don't Know". That's just my reason for doing so. Others, I'm sure, have other reasons. I have been trying to correct myself to keep from doing this because it can sound almost nasty at times and is similar to slicing ones nose from ones face and saying "That'll learn ya!" It doesn't help the person saying it or the person seeking help.

I can't speak for most people but I don't program because it's easy. I do it because it's fun. I enjoy the challenge. If it's too easy, it's not fun. Telling me to use some other method that the one I asked about because it is easier will ensure that I don't use it. I will, of course, ask for help or a nudge in the right direction when I am stumped, but if I want to go to Los Angeles, California by way of Omaha, Nebraska, don't tell me to change my route, unless it is absolutely impossible. If it is impossible, tell me why (if you know). Then I will change my plan.


Category 2: The "Size is No Longer Important" category

This one has chapped me for a very long time. Just because you have the space, doesn't mean you need to use it. I for one am upset when my videogames take up 4 times the space of my operating system. One of the main reasons used for not learning assembly language is that new computers have a lot of storage space, so it doesn't matter how bloated the program is. I'm talking to you, .NET Framework! I recently downloaded a CD Image which contained over 800 DOS games. That means that each game clocked in at around 1mb a piece. Now, you are lucky if you can get one game on 2 CDs. It would be one thing if the size was in relation to the fun of the game, but many of the old DOS games were as fun, if not more fun, then the new Behemoths. I'm all for good graphics, but there needs to be a balance graphics and size.

Also speed is important too. Many people insist that since RAM is so cheap and abundant, conserving memory is a thing of the past. This is far from true. I can't tell you the number of times I have had programs crash from overuse of memory. Windows XP requires at least 512mb of RAM, then it makes a page file which takes up anywhere from 128mb to 512mb (system default settings) of hard drive space to use as RAM, and yet is will still crash when any real strain is put on the OS. A combined 1gb minimum of space is not enough for this resource hog.


Category 3: The "I Know That And You Know That, But They Don't Know That" category

Many commercial software companies fall prey to this one. A good example is CYBERSitter, an internet filtering software. They used to proclaim that their software was able to filter web pages on the basis of context. It was supposed to be able to discern the difference between, "His court room tactics were barely legal" and "Our porn stars are barely legal." They had been telling customers that for a good while when a study done showed that they were lying through their teeth. The idea was that if they tell the customer that it works, the general customer won't question it. And they were right. Once someone saw through their 'clever' ruse, they promptly removed the claim from their web site.

Antivirus companies do this all the time by saying they posses the "industries leading virus detection technology", when many of them could not find their own rear end in the dark with both hands.


Conclusion

I do feel better now that I have gotten those off my chest. If you are guilty of any of these things, it couldn't hurt to change your ways. It could very well hurt to not change your ways… Anyway, that's just my 2 cents worth.


Download a copy of this article: NotToDo.zip


Monthly Awards

Written by Pete

Every month, QB Express hands out two awards to recognize QB or FB coders and websites that have done exceptional work in the last month. They are not awarded for work done in the past, only for work that has been released since the last issue of the magazine. We will bring you these awards on a monthly basis to help give credit where credit is due.

Thanks to MystikShadows for suggesting this month's winners.


Site of the Month

Jace Masula's QBASIC LAB
http://qb45.think-new.com

Webmaster: Jace Masula


Jace Masula's QBASIC LAB is a website I've had my eye on for a long time. Its clean, simple design is both stylish and functional, and it does everything a hobby developer's site sets out to do: promotes and distributes the webmaster's programs.

At QBASIC LAB, you'll find information and screenshots for all of Jace Masula's (aka momoguru's) programs -- including ASCIIQUEST, QBPLAY, ASCIIPAINT and his latest release, JACE'S BLACKJACK v1.0. Most of these programs are ASCII-based, and all of them are pure-QB releases with no external libraries. I guess you could say that Jace's programming style is similar to his web design style -- simple and functional, but still managing to look very attractive. The site also has forums (temporarily down), a contact page, and a links / resources page, not to mention the front page, which has the latest news. It's small, but all of the information is well-laid out, well-written, and presented in the site's classy red, gray and white layout.

This month, Jace switched the site to a new server, and also released his new Blackjack game. Not a huge update, but still enough for me to name Jace Masula's QBASIC LAB this month's Site of the Month!



Programmer of the Month

Piptol
http://piptol.qbasicnews.com/

Piptol is one guy who deserves a lifetime achievement award for his contributions to the Qmunity -- and his latest release, the FreeBasic port of his classic QB strategy game, Kingdoms, confirms that. The 2002 QB Gaming Gold Award Winner for Best Strategy Game may very well win the award for Best FB Strategy Game Ever, now that it's available in a FreeBasic version. Kingdoms is a simple, but very fun game that will definitely keep you coming back for more. And the FreeBasic version is even improved over the QB original: "This version adds some new characters to help or hinder your Ablyssian adventures, there's minor graphical improvements, resampled music and faster battle sequences."

I'm not going to bother talking about all of Piptol's other contributions (Ghini Run, Squealer TNT, etc....), because I'm sure you're already aware of them. Just for his awesome FreeBasic Kingdoms release, Piptol is the QB Express Programmer of the Month!


Have a suggestion for Programmer / Site of the Month? Email me!


Comics

By Rattrapmax6, redcrab & Tunginobi

Rattrapmax6 and Tunginobi are back this month with their comics, plus redcrab debuts his brand new "0 1" series!


Horse Humor Comics by Rattrapmax6


QBasic Horse Humor


Stickblob Comics by Tunginobi

stickblob comics


stickblob comics


stickblob comics

0 1 Comics by redcrab



Polar Plasmas

Written by Optimus (Michael Kargas)

I am really wondering how many diferrent types of plasma effects do there exist. Sometimes, when I code a new 2d effect, some friends from the scene tell me "Wow! Nice plasma!!!" (Especially the ones who aren't much into modern effects or graphics coding in general). I try then to explain them that it's something more than a plasma, a new effect I've just coded that takes again the concept of painting each pixel by a color that depends on a function using the pixel coordinates. Would that be considered as a plasma effect? Dunno. And yet there are still several 2d pixel effects whose I neither know their real names nor I have tried to code them. Some of them are just variations or combinations of what I've coded before. Those effects my friends still tend to call plasmas are maybe in this category. One of my favorites are those whirlwinds or flowers that I would call polar plasmas here.

The concept is quite easy. In regular plasmas the color of each pixel came from a function that added the sines of x and y of the current pixel plus even more combinations of random sines of x and y. Now, if each pixel can be represented with two variables, the angle and distance from the center of the screen, then we just take the color as a function of these two variables for each pixel and have beautiful circular color shapes instead!

I will try to explain myself soon..

First of all, we have to get the radius and angle of each pixel from the center of the screen (That is near to (160,120) if we are working in 320x240 resolution). We wouldn't like to do this in realtime because we need to use SQR for the radius and ATAN2 for the angle. So, all that is needed is to precalculate two big arrays of size 320*240 each. This is how we do it:

const SCR_WIDTH  = 320
const SCR_HEIGHT = 240
const SCR_SIZE = SCR_WIDTH * SCR_HEIGHT
const xc% = SCR_WIDTH / 2
const yc% = SCR_HEIGHT / 2

const rang% = 512
const pi = 3.14151693
const d2r = 180/pi
const d2b = (rang% * d2r) / 360

dim shared radius(SCR_SIZE-1) as ubyte, angle(SCR_SIZE-1) as ubyte

    i% = 0
    for y% = 0 to SCR_HEIGHT - 1
        for x% = 0 to SCR_WIDTH - 1
            xs% = x% - xc%
            ys% = y% - yc%
            radius(i%) = sqr(xs% ^ 2 + ys% ^ 2)
            angle(i%) = atan2(xs%, ys%) * d2b
            i% = i% + 1
        next x%
    next y%

xc% and yc% are the x and y coordinates of the pixel on the center of the screen. We have two tables, radius and angle, holding the radius and angle of each pixel on the screen. These two tables could be two dimensional to make things more clear but I just copied the code from my old sources, it's faster this way anyways. Just imagine that the upper-left pixel onto the screen is the very 1st element of our array and as we move to the next byte, we also move to the next pixel in the right, exactly the same way you talk to your videobuffer. Anyways, I think most of you have no problem with that so I don't need to explain. These tables corresponds with the same pixels in your videobuffer.

As you may know, to get the distance of (x1,y1) from (x0,y0) you just need to calculate SQR((x1-x0)^2 + (y1-y0)^2). That's math. Here, (x0,y0) could be the center of the screen and (x1,y1) variable for each diferrent pixel. We calculate those diferrences in xs% and ys% and the distance is given by SQR(xs%^2 + ys%^2). Preety simple! As for the angle, ATAN2 is a quite useful function that returns the angle in rads between the line from a point to (0,0) and the X axis. Simply, it returns the angle of a given point based on it's x and y coordinates. Actually atn is the inverse function of tangent but atan2 is a better version of it. In the past I used atn but I had to split the code in 4 cases according to the quarter my pixel was, for some mathematical reasons I can't explain here this didn't worked easilly. But thanks to rel who pointed it out to me, atan2 does the job alone!

And there is a reason we multiply the result by d2b. Above in the consts, we've made some hocus pocus, nothing else than calculating some consts useful for converting from radians to degrees and the opposite. By multiplying by d2r you convert radians to degrees and by dividing by d2r the opposite happens. That's because we know from math that one rad equals 180/pi degrees. But why calculating d2b based on a const named rang% and using this one instead? I just want to be sure that the angle values cycle from 0 to 512 instead from 0 to 360 and that's because I am later using a table of 256 colors pallete with continuous colors that cycle after 255 from 0. Else, you will see a harsh bug in your polar plasmas, except if you also use a 360 color pallete that cycles it's colors at the end :)

Here is an example of the little code that generates some palete in 32bit mode. When I say the color cycles after 255, I mean that if the color fades to black till 255 it should start from black at 0. In our polar plasma, color addition might give overflows (values over 255 that start from 0, if we use unsigned byte for our color variable) but if we make the shade table appropriately, we have smooth color and no clashes. Maybe you are still wondering why I didn't put rang%=256 but 512, but there is no problem with that, cause the angle ends well enough at 511 which is 255 in ubyte. If you put multiplies of 256 in rang% you see your shapes change. But don't worry about that for the moment..

dim shared pal%(255)

for i%=0 to 63
    pal%(i%)=(i%*2) shl 16 or i%*4
    pal%(i%+64)=(128+i%*2) shl 16 or (i%*4) shl 8 or (63-i%)*4
    pal%(i%+128)=255 shl 16 or ((63-i%)*4) shl 8
    pal%(i%+192)=((63-i%)*4) shl 16
next i%




And now to the point:

Before we start though, we'll precalculate some sines we will need later..

    l!=0.25
    for i%=0 to 2047
        fsin1%(i)=sin(i%/(l!*d2b))*48+64
        fsin2%(i)=sin(i%/(l!*d2b/2))*40+48
    next i%

And now we are ready..




Which shape would we get if each pixel was colored after it's radius from the center?

dim c as ubyte

for i%=0 to SCR_SIZE-1
    c= radius(i%)
    vram(i%) = pal(c)
next i%




And what would happen if each pixel was colored after its angle?

dim c as ubyte

for i%=0 to SCR_SIZE-1
    c= angle(i%)
    vram(i%) = pal(c)
next i%



Now imagine adding these two!

dim c as ubyte

for i%=0 to SCR_SIZE-1
    c= radius(i%) + angle(i%)
    vram(i%) = pal(c)
next i%




Now about the next shape. I hope that till know you can easilly imagine the corresponding of the images with the actual code. How about a flower shape now?

Just imagine taking the first case with the colored cycles, but now trying to manipulate it's code so that the radial color is disturbed in diferrent angles. That's how the flower shape looks like! At diferrent angles the colors are more open, you say the same color in further distance in one angle from the other. Just imagine taking the first case with the colored circles, where at the same radius the color is the same. And disturbing that fact by adding a sine function of the radius! We use the precalculated sines to make the disturbance being wavy! And of course the sines were also generated by using d2b so that there are no bugs with color overflows.

dim c as ubyte

for i%=0 to SCR_SIZE-1
    c = radius(i%) + fsin2%(angle(i%))
    vram(i%) = pal(c)
next i%




And here in short, we have some nice examples of shapes that can be produced by these codes:

dim c as ubyte

for i%=0 to SCR_SIZE-1
    c = radius(i%) + fsin2%(radius(i%) + angle(i%))
    vram(i%) = pal(c)
next i%




But till now we only had static plasmas! Of course, but if you put a variable (k% here) inside some of the sines, which you increase per each frame (either by addition or preferably by the timer) you have some great moving shit!!!

dim c as ubyte

for i%=0 to SCR_SIZE-1
    c = angle(i%) + fsin1%(radius(i%) + fsin2%(radius(i%) + k%))
    vram(i%) = pal(c)
next i%


You can experiment and make much more cooler shapes! I am still amazed by what was produced and I still fiddled with my code during the writting of this tutorial to discover more wild stuff! I hope I explained the whole stuff well here, though I wrote this tutorial really fast to support the magazine. I never expected it will all end up like this in such a hurried article. Still, if you have any questions or problems with these codes, feel free to send me an email at optimus6128@yahoo.gr. See you in my next tutorial (if there will be any soon) ;P


Michael Kargas aka Optimus


Download a copy of this tutorial: polarplasmas.htm or polarplasmas.zip


A Beginner's Introduction to Gtk+

Written by red_Marvin

This is not a document to explain exactly how and why stuff works, but rather an introduction to how to use it.

Gtk+ is one, but not the only, linux equivalents of the winAPI, which means it's what you use when creating windows and buttons etc. If you use a linux distro that lets Gnome or XFCE take carer of the desktop you already use gtk+. KDE uses something else, but you should still be able to run gtk-based programs if you have the right libs installed. When developing you of course need the development libraries and fbc comes with the bi headers.

Generally one could say that gtk+ works through allocating objects (widgets), setting it's properties and then connecting your callback functions to one or more of it's signals. Each time a button is pressed the signal ”clicked” gets emitted, and if you have connected any callback functions to that button, listening to that signal, then the callback function will get executed.

If you are interested in learning and using gtk+ for your programs I strongly suggest that you bookmark this site: http://developer.gnome.org/doc/API/2.0/gtk/index.html

Here's an example that is more or less identical to one included with fbc.

option explicit
#include once "gtk/gtk.bi"

declare function close_button_has_been_pressed cdecl (o as gtkObject ptr, d as gPointer ) as integer

'--------------------

gtk_init 0,0

dim myWindow as gtkWidget ptr
myWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL)
gtk_window_set_title GTK_WINDOW(myWindow), "Woot! a window! 1337"

g_signal_connect(myWindow, "destroy", GTK_SIGNAL_FUNC(@close_button_has_been_pressed), 0)

gtk_widget_show_all myWindow
gtk_main()
end 0

'--------------------

function close_button_has_been_pressed cdecl (o as gtkObject ptr, d as gPointer ) as integer

   print "The window is destroyed, I can't feel my legs!"

   gtk_main_quit

end function

The program starts with a gtk_init, which I suppose is more or less like calling screen before using graphic related commands. the 0's are argc and argv parameters, which I think is used if you want to pass any extra parameters to gtk_init, I have yet to have a use for them.

Later we dim a gtkWidget ptr, and it is through them we can manipulate ha widget's appearence etc. We also create a new window widget and the GTK_WINDOW_TOPLEVEL means that it is a ”normal” window instead of the kind used on popup menus etc. Even the reference library tells you that you're not likeley to need anything else than the toplevel variant.

We also set the title of the window to something that will leave all future users in awe. You might notice the GTK_WINDOW(), which I think is a macro that cast the parameter to a window, bundled with an assert that it actually is one.

After that we make sure that, when the ”destroy” signal get's emitted for myWindow, the function close_butto(etc.) is called. Simple.

Then we of course make sure that the user of this mighty fine program can see the fruits of our labour.


When gtk_main is called, the gtk faries takes over, and starts listening to keypresses, clicking and all that stuff and makes sure all get's redrawn nicely etc.

If we at that time press the close button of the window or alt-F4 = we close the window, then the window is destroyed an deallocated, and guess what?

The ”destroy” signal is emitted, catched, and close_butto(etc.) is run!


The signal callback functions must take a certain list of parameters, slightly depending on which type of signal it is.

  1. The widget the signal came from, useful if you connect different widgets' same signals to the same sub.

  2. Some signal callbacks need an extra parameter here but not any of the signals we use here.

  3. Some user data. If you want some extra data pass it here, the type is a gPointer which is the same as an any ptr, but you'll have to cast it to avoid warnings.

In the above program we have no extra data to pass, so I put a zero there.

Also note that all functions dealing with signals need to be declared with cdecl.

Inside the function I have put a gtk_main_quit that tells the fairies in gtk_main to go home for the day, so when the function returns to it's caller, gtk_main exits and the program execution continues on the next line, which happens to be an ”end 0”


Download a copy of this tutorial: gtkintro.txt


Making Good Sound Effects

Written by Michael "Fuzzypig" Reiley

As some of you may know, I am the official Sound FX guy for FieldView, Zire's MMORPG game. Well, I'm going to tell you some tips and tricks for making good sound effects, which can be used in a variety of ways. So, let's get started.

First, you're going to need a microphone. A midi microphone is good, but if you're like me and don't have a midi box, you can get a good quality microphone that plugs right into your computer's micrphone jack. You probably want a dynamic microphone, because it doesn't need batteries. Also make sure that it has a miniplug jack; that will plug straight into your pc. I got mine on amazon.com, and it was only $8! :D

Next, you're going to need some software. Don't waste your money on commercial software, though :P. I use Audacity. It's free and open source. It's a really neat tool because it lets you record directly to it, and also lets you trim your sound and apply effects, like amplification. You can get it at http://audacity.sourceforge.net/ . It has a very simple interface that I figured out very quickly, but if you need extra help, email me at: blahboybang@gmail.com . There's probably some good tutorials out there to, if you want those.

Finally, you need to make your sound effects. My best tool is the environment. There's sound everywhere, outdoors and even as close as your own house, just waiting to be recorded! Whether it be a drainpipe on a rainy day, or a rusty hinge on your bathroom door, there's always a way to get your sound effect.

And now, some helpful tips and tricks:

  1. If you can't find a microphone, you can always use a pair of headphones. That's right, headphones. What many people don't know is that most cheap-o headphones are backward compatible; that is, they will work as a microphone if plugged into your microphone jack. Also, if you have a mono jack, which most computers do, only the left-side headphone will work.

  2. Most affordable microphones have a cord, which is going to be a problem with desktop computers. You're best off using a laptop, because you can take it anywhere. If you don't have a laptop, borrow a friend's.

  3. When you amplify your sound effects, it could make static noise. The noise gets worse the more you amplify, but if you get your sounds loud at the start, you won't have a problem. Just a little amplification won't hurt, though.

  4. If you can't get at the thing you wan't to record, try making the sound with something else. For example, I needed a footstep sound a while back, so I squeezed the head of a giant plush crayon. :D

  5. Don't get discouraged. Sometimes it's hard to get your sound, but don't give up. Have Fun with it.

Michael "Fuzzypig" Reiley : blahboybang@gmail.com


Download a copy of this tutorial, or visit the FieldView Website.


MIDI Programming - A Complete Study
Part 3 - Timing, Windows API and MIDI Events

Written by Stéphane Richard (Mystikshadows)

INTRODUCTION:

Welcome to the third part of the MIDI Programming Series. There is a small change of plans. I was supposed to make a playback engine in this third part. But because of the contents of everything before it, I've decided to keep the engine for part 4 and instead, take the time to explain everything you'll need to know to fully understand the playback engine. As such, this part of the series will cover Timing issues, The windows API and how to manipulate standard MIDI events to get them ready to send to the MIDI devices on your computer.

To do so, we'll start by looking at some basic notions you'll need to know about sequencing and timing. We'll also take each type of MIDI event and see how we need to prepare the MIDI message to send them as valid MIDI events to the MIDI device.

TIMING RELATED NOTIONS:

When it comes to MIDI files, there's two things that can really define the quality of a MIDI software and they are resolution and Accuracy. These two combined determine how a MIDI file is played and/or recorded when you are playing on a keyboard to be recorded on your computer. Let's take a look at some definitions you'll need to consider.

TIMING CALCULATIONS AND FORMULAS:

And now it's time to get to the core of sequencing. Without timing, we have no way of knowing what's supposed to happen next when it comes to playing our MIDI song. Timing is at the core of any program that can play this type of file. The truth of the matter is that you need to know how long a given note should last on a given tempo. This value will help scale the playing of the whole song itself.

The Beats Per Minute (BPM):

Any keyboard you buy, any sequencing software gives you the ability to change the tempo of a song. The tempo determines the speed at which the song will be played. To a musician, a beat is always based on a quarter note. With this in mind a BPM of 100 means that the musician must play 100 steady quarter notes in one minute. For the other note durations you would simply multiply or divide the BPM according. For example Take a look at this list of values. Remember that there are 60,000,000 microseconds per minute. We just need to divide that by the BPM to determine the interval where each beat should be played.

Note Count And Time Lapses BPM=100 NOTE NAME COUNT/MINUTE MICROSECONDS PER BEAT ----------------- ------------ ------------ Whole Note 25 2,400,000 Half Note 50 1,200,000 Quarter Note 100 600,000 Eight Of A Note 200 300,000 16th Of A Note 400 150,000 32th Of A Note 800 75,000 64th Of A Note 1600 37,500 128th Of A Note 3200 18,750

For a quarter note, at a BPM of 100 means that every note should be played every 0.6 seconds to have 100 notes in a minute. This is is a time based calculation. As you see next, the MIDI hardware doesn't speak in terms of time based values directly. This is also where the playback resolution of a song can and will be affected. Take a look at the same chart for a BPM of 120.

Note Count And Time Lapses BPM=120 NOTE NAME COUNT/MINUTE MICROSECONDS PER BEAT ----------------- ------------ ------------ Whole Note 30 2,000,000 Half Note 60 1,000,000 Quarter Note 120 500,000 Eight Of A Note 240 250,000 16th Of A Note 480 125,000 32th Of A Note 960 62,500 64th Of A Note 1920 36,250 128th Of A Note 3840 18,125

As you can see, BPM timing is all about dividing the 60,000,000 microseconds of a minute into your Beats Per Minute. Since, in MIDI music, everything is based on the quarter note, you'll notice on both these charts that the quarter note has the BPM in questions (120 in this last case and 100 in the chart above). Let's now talk about the next biggest item in this part, the Pulse Per Quarter Note.

The Pulse Per Quarter Notes (PPQN):

What is a PPQN? You can think of them as the number of intervals a quarter note can be broken into in order to reproduce a song in time. It is dependant on the hardware used (Hardware sequencers, sound cards, etc...) and the Software/OS it is executing on. On today's hardware and software, one can usually expect a good stable PPQN of 480. This means that if you take the chart above (BPM of 120) a quarter note, which lasts 0.5 second can be split into 480 equal time slots. As such, any note that will be played must be played on one of those 480 time slots of 1041.7 microseconds each (just about a millisecond long). This is known as the resulution of the playback. Not too long ago, a PPNG of 96 seemed to be enough to reliably play a song faithfully. However, there were, back then, many songs that just weren't played electronically. This of course changed. For example, fully orchestrated classical musical pieces. It didn't take too long to notice that a recorded song would play these types of song with strange offbeat notes that felt like they didn't belong where they were being played. Hence the PPQN needed to be raised, considerably, to allow for such songs to be reproduced with the accuracy they needed.

Here's the same table as above only this time we'll include different PPQNs to give you a more visual idea of the resolution they allowed. The most widespread PPQNs up to today were 96, 192 and 480. You'll see how it affects things right here:

Note Count And Time Lapses BPM=120 MICROSECONDS NOTE RESOLUTIONS NOTE NAME COUNT/MINUTE PER BEAT 96 PPQN 192 PPQN 480 PPQN ----------------- ------------ ------------ ---------- ---------- --------- Whole Note 30 2,000,000 20,833.36 10,416.68 4,166.80 Half Note 60 1,000,000 10,416.68 5,208.34 2,083.40 Quarter Note 120 500,000 5,208.34 2,604.17 1,041.70 Eight Of A Note 240 250,000 2,604.17 1,302.09 520.85 16th Of A Note 480 125,000 1,302.09 651.04 260.43 32th Of A Note 960 62,500 651.04 325.52 130.21 64th Of A Note 1920 36,250 325.52 162.76 65.11 128th Of A Note 3840 18,125 162.76 81.38 32.55

As you can see here, the higher the PPQN, the smaller the time slots. This of course means that the notes being played can be played closer to the actual time it should have been played at when you have a smaller time slot resolution. This is what PPQN does, divide time into manageable timeslots. All you have to do after that is loop through time, collect what should be sent in the next time slot and send it off through the MIDI port. Sounds Simple? One more obstacle stands in the way of accomplishing this and that is the Windows API.

MIDI AND THE WINDOWS API:

As I mentionned previously in the series, I plan to use the Windows API and make a low level MIDI player. Of course, this means we'll need a few things from the API in order to be able to accomplish our goal. If you've ever taken a look at the mmsystem.bi include file, just doing that might seem quite overwhelming. It's a big file, but it's there to do a lot more than play a MIDI file. The first thing will do is take a look at what exactly we'll need to play a note on a MIDI device.

The needed MIDI Subs and Functions:

The purpose of this part is to show you how to play a note through the MIDI device of your choice. As I said before, you don't need the whole mmsystem.bi functions to accomplish that. As far as functions and subs are concerned, you only need five of them. Let's take a look at their declaration so you can get familiar with them.

Declare Function midiOutGetNumDevs () As Integer DECLARE FUNCTION midiOutGetDevCaps _ ALIAS "midiOutGetDevCapsA" (ByVal uDeviceID AS INTEGER, _ lpCaps AS MIDIOUTCAPS, _ ByVal uSize AS INTEGER) AS INTEGER DECLARE FUNCTION midiOutClose (ByVal hMidiOut As INTEGER) As Integer DECLARE FUNCTION midiOutOpen (lphMidiOut AS INTEGER, _ ByVal uDeviceID AS INTEGER, _ ByVal dwCallback AS INTEGER, _ ByVal dwInstance AS INTEGER, _ ByVal dwFlags AS INTEGER) AS INTEGER DECLARE FUNCTION midiOutShortMsg (ByVal hMidiOut AS INTEGER, _ ByVal dwMsg AS INTEGER) AS INTEGER

Note that the midiOutShortMsg API function is used to send all standard MIDI events (&H8X to &HEX) And we'll be cvering all of them in this 3rd part of the series. One quick look at these declarations and you can see that they all use standard data types, mostly integers, all except midiOutGetDevCaps which requires a MIDIOUTCAPS parameter. MIDIOUTCAPS is a user defined type. Here is its definition so you can see what it's made of.

Type MIDIOUTCAPS wMid AS INTEGER ' Manufacturer identifier of the device driver wPid AS INTEGER ' Product Identifier vDriverVersion AS INTEGER ' Version number of the device driver. szPname AS STRING * 32 ' Product name in a null-terminated string. wTechnology AS INTEGER ' Either MOD_FMSYNTH, MOD_MAPPER, ' MOD_MIDIPORT, MOD_SQSYNTH, MOD_SYNTH wVoices AS INTEGER ' Number of voices supported by internal synthesizer. wNotes AS INTEGER ' Maximum number of simultaneous notes wChannelMask AS INTEGER ' Channels internal synthesizer device responds to. dwSupport AS INTEGER ' Either MIDICAPS_CACHE, MIDICAPS_LRVOLUME ' MIDICAPS_STREAM, MIDICAPS_VOLUME END TYPE

This User Defined Type is used in combination with the midiOutGetDevCaps() function to get information about the different MIDI devices that are currently installed on your system. the wTechnology field uses constants as it's possible values. These constants are defined as follows:

MOD_MIDIPORT 1 <- MIDI hardware port. MOD_SYNTH 2 <- The device is a synthesizer. MOD_FMSYNTH 3 <- FM synthesizer. MOD_SQSYNTH 4 <- square wave synthesizer. MOD_MAPPER 5 <- Microsoft MIDI mapper.

Likewise, we have the dwSupport field which also needs some constant values. These values represent addition technologies and features that are supported by the hardware that you get from the driver. Here is their definitions:

MIDICAPS_VOLUME 1 <- Supports volume control. MIDICAPS_LRVOLUME 2 <- Separate left and right volume control. MIDICAPS_CACHE 4 <- Supports patch caching. MIDICAPS_STREAM 8 <- Support for the midiStreamOut function.

With all these definitions at hand, we're ready to begin the code we need to send MIDI events through the MIDI device of our choice. To do so we'll need a few steps. So let's get right to it.

Step 1 - Acquire The MIDI Devices' Information:

As probably expected in the world of programming, you need to

' --------------------------------------------- ' Include mmsystem.bi to have its definitions ' --------------------------------------------- #include "windows.bi" #include "win\mmsystem.bi" ' ---------------------- ' Variables we'll need ' ---------------------- TYPE MidiDevice DeviceID AS INTEGER DeviceName AS WSTRING * 32 VoiceCount AS INTEGER Polyphonics AS INTEGER END TYPE ' ---------------------- ' Variables we'll need ' ---------------------- DIM MIDIDevices() AS MidiDevice ' Create Dynamic Array DIM DeviceCount AS INTEGER ' Number of MIDI devices DIM Caps AS MIDIOUTCAPS DIM Counter AS INTEGER DIM MIDIHandle AS INTEGER '---------------------------------- ' Get the rest of the midi devices ' ---------------------------------- DeviceCount = midiOutGetNumDevs REDIM MIDIDevices(0 To DeviceCount - 1) AS MidiDevice ' ---------------------------- ' Index 0 is the MIDI Mapper ' ---------------------------- MIDIDevices(0).DeviceID = 0 MIDIDevices(0).DeviceName = "MIDI Mapper" ' -------------------------------------------------------- ' Loop Through devices to populate the MIDIDevices array ' -------------------------------------------------------- For Counter = 0 To (DeviceCount - 1) midiOutGetDevCaps Counter, @Caps, Len(Caps) MIDIDevices(Counter + 1).DeviceID = Counter + 1 MIDIDevices(Counter + 1).DeviceName = Caps.szPname MIDIDevices(Counter + 1).VoiceCount = Caps.wVoices MIDIDevices(Counter + 1).Polyphonics = Caps.wNotes MIDIDevices(Counter + 1).Channels = Caps.wChannelMask Next Counter

So far I think it seems simple enough. We call the midiOutGetNumDevs to get a count of the devices we have installed in Windows. Then, we call midiOutGetDevCaps API function is called in a loop to populate the rest of the MIDIDevices array with all the existing device names. This gives us the list of available MIDI Output devices. There is also the midiInGetDevCaps to allow us to get all of the devices we have that can receive information from the MIDI port. Here's what the code above gave me for output devices:

0 - MIDI Mapper 1 - SB Audigy 2 Synth B [D000] 2 - SB Audigy 2 Sw Synth [D000] 3 - SB Audigy 2 Synth A [D000]

And there you have, we now have the code to get the list of devices we can use. Of course, with that information comes the next step. And that is, actually using one of the devices and playing some notes and other things. The next section is entirely devoted to showing you just that. So, let's get right to it.

Step 2 - Accessing The MIDI Devices:

Using devices that we have is typically a simple question of opening the MIDI device we want, sending what we want MIDI to interprete, and when we're done, we just close the MIDI Port we opened. So let's take a look at some code and I'll explain it right after.

' ---------------------------------------------------------- ' Variable to Get the handle of the MIDI Device we'll open ' ---------------------------------------------------------- DIM MIDIHandle AS INTEGER DIM CurrentDevice AS INTEGER DIM Result AS INTEGER DIM MIDIMessage AS INTEGER DIM Instrument AS BYTE DIM Volume AS BYTE DIM Channel AS BYTE DIM NoteNumber AS BYTE DIM PressureValue AS BYTE DIM Value AS BYTE DIM LeastSignificant AS BYTE DIM MostSignificant AS BYTE ' ------------------------------------------- ' First we get which Device we want to open ' ------------------------------------------- CurrentDevice = Devices(DeviceIndexNumber).DeviceID Result = midiOutOpen(MidiHandle, CurrentDevice, 0, 0, 0) If (Result <> 0) Then PRINT "Could not Open MIDI Device." End If

If all goes well at this point you have the device you want opened and ready to get outward messages. All we need to do at this point is get the MIDI messages ready and send them to that MIDI Handle. And now that we have an MIDI port, let's start defining how each type of MIDI message is prepared and sent to the MIDI device. I'll just describe them in their numeric order.

&H80 Events (Note Off Events):

The Note Off event turns the note being played off. Although no error messages are reported by turning a note that isn't playing, you can imagine that before turning a note off, you'd typically be turning it on first. You need a MIDI Channel and a Note Number variables to turn a sound off. Here is how you would do it.

' ------------------------------------ ' Assign Values to needed parameters ' ------------------------------------ Channel = 0 ' 0 to 15 for active MIDI channels NoteNumber = 70 ' 0 to 127 for the notes. ' --------------------------------------------------------- ' Prepare the MIDI Message and send it to the MIDI Device ' --------------------------------------------------------- MidiMessage = &H80 + (NoteNumber * &H100) + Channel midiOutShortMsg MidiHandle, MidiMessage

&H90 Events (Note On Events):

This, of course, does the opposite as the Note Off event. It basically sends a note, a volumn and a MIDI channel to the MIDI device. When the MIDI device receives this message it will start playing the specified note at the requested volume through the specified MIDI channel. Here's how you prepare this type of message.

' -------------------------------- ' Define the note values we want ' -------------------------------- Volume = 60 ' 0 to 127 Channel = 0 ' 0 to 15 for active MIDI channels NoteNumber = 70 ' 0 to 127 for the notes. ' ------------------------------------------------------ ' Arrange the MIDI even in the right order and send it ' ------------------------------------------------------ MidiMessage = &H90 + (NoteNumber * &H100) + (Volume * &H10000) + Channel midiOutShortMsg MidiHandle, MidiMessage

&HA0 Events (Polyphonic Pressure Events):

This type of message is also called the Polyphonic Aftertouch Event. In essence, when you press a key on a keyboard it would generate a Note On event, when you release it, and just before the Note Off event is when an Aftertouch event can be inserted. Some keyboards have some pretty special aftertouch events and are well worth the effort to have them heard when it's supported. To do so, you need the note you want to play, a Polyphonic Aftertouch value (0 to 127) and of course the MIDI channel you want to send the message to. Here's how it works.

' -------------------------------- ' Define the note values we want ' -------------------------------- PressureValue = 127 ' 0 to 127 Channel = 0 ' 0 to 15 for active MIDI channels NoteNumber = 70 ' 0 to 127 for the notes. ' ------------------------------------------------------ ' Arrange the MIDI even in the right order and send it ' ------------------------------------------------------ MidiMessage = &HA0 + (NoteNumber * &H100) + (PressureValue * &H10000) + Channel midiOutShortMsg MidiHandle, MidiMessage

&HB0 Events (Controller Change Events):

If you remember in part one of the series, the biggest table I presented there was the list of Controllers. Each type of controller work differently from others, expect different parameters and perform a very different type of functionality. If you also remember, some controllers are known as continuous controllers, others are basically control switches and then you have the normal controllers. You basically need the Controller number, in some cases a value to apply to the controller and again the MIDI Channel you want to send the event to. Here's how you would do this.

' ------------------------------------ ' Assign Values to needed parameters ' ------------------------------------ Channel = 0 ' 0 to 15 for active MIDI channels Controller = 70 ' 0 to 127 for the notes. Value = 0 ' ------------------------------------------------------ ' Arrange the MIDI even in the right order and send it ' ------------------------------------------------------ MidiMessage = &HB0 + (Controller * &H100) + (Value * &H10000) + Channel midiOutShortMsg MidiHandle, MidiMessage

&HC0 Events (Program Change Events):

This type of event serves to change which instrument a note is to be played with. In a very typical scenario you would change instruments to each track's default instrument and play the whole song. However there's nothing stoping you from changing instrument whenever you want with this type if MIDI event. You simply need to specify the Instrument Number and the channel to send the MIDI event to and then 3 messages to the MIDI device will perform the program change. Here's how it works in code.

' ---------------------------------------------- ' Set Instrument and Channel to desired values ' ---------------------------------------------- Instrument = 51 ' 0 to 127 for MIDI instruments (51. SynthStrings 1) Channel = 0 ' 0 to 15 for active MIDI channels ' ------------------------------------------------------ ' Send a Patch/Program change event to the MIDI Device ' ------------------------------------------------------ midiOutShortMsg MIDIHandle, &HC0 + Channel midiOutShortMsg MIDIHandle, 32 * &H100 + &HC0 + Channel midiOutShortMsg MIDIHandle, Instrument * &H100 + &HC0 + Channel

&HD0 Events (Channel Pressure Events):

Channel Pressure Events are quite simple events that is sent whenever the force of a note (when played on a keyboard or generated numerically) influences the strength at which the sound is played and heard. MIDI has the &D0 event to simulate and reproduce this effect on a MIDI channel. It is known as channel pressure and essentially affects the volume (regardless of the default volume value) at which the note is played. To do so you need the Channel number and the Pressure Value (0 to 127) to apply to the MIDI channel. Note that this type of event differs from the Polyphonic Aftertouch message in that the Aftertouch affects the note that is in the message where as the Channel Pressure message affects the whole channel. here's how to send a Channel Pressure message.

' ------------------------------------ ' Assign Values to needed parameters ' ------------------------------------ PressureValue = 80 ' Desired Pressure Value to Applyu Channel = 0 ' 0 to 127 for the notes. ' --------------------------------------------------------- ' Prepare the MIDI Message and send it to the MIDI Device ' --------------------------------------------------------- MidiMessage = &HD0 + (PressureValue * &H100) + Channel midiOutShortMsg MidiHandle, MidiMessage

&HE0 Events (Pitch Bending Events):

Pitch bending is the act of starting on a specific note and bending the note down or up. Typically this is done, on a keyboard with a wheel control (a pitch bending wheel) and is often used in music in order to add a certain human flavor to a sound (specifically on guitar sounds, but on other sounds as well). Pitch bending requires 2 specific values. The way the work is that a pitch bend of &H0 means the note is lowered the the minimum pitch bending value, a value of &H7F7F means that the note is bent to it's maximum value. A value of &H4000 means that the note is played at the normal pitch (no bending). These values are represented as a least significant byte and a most significant byte. Aside that, you'll need the channel number where you want to send the pitch bending message.

' ------------------------------------ ' Assign Values to needed parameters ' ------------------------------------ MostSignificant = &H7F ' These set the maximum upward bend value LeastSignificant = &H7F Channel = 0 ' 0 to 15 for active MIDI channels ' --------------------------------------------------------- ' Prepare the MIDI Message and send it to the MIDI Device ' --------------------------------------------------------- MidiMessage = &HE0 + LeastSignificant * &H100 + MostSignificant * &H10000 + Channel midiOutShortMsg MidiHandle, MidiMessage

Now, much like my file manilulation series, there is one more important step to do when you're done sending things to the MIDI device. You guessed it, you have to close the MIDI device. To do so, you simply need to make a call to the midiOutClose API with the Handle of the MIDI device as it's parameter. You do this as follows:

' ------------------------------------- ' Dont forget to close your MIDI port ' ------------------------------------- Result = midiOutClose(MidiHandle)

And there you have, you should now be able to handle all standard MIDI events that you can read from a MIDI File. Each of these types of events will become an independing subroutine in the next part of the series to help organize the code better for our MIDI playback. Each value needed will be parameters that are passed to the subroutine to make them reusable for all types of occurrences of a specific MIDI event. This, along with the timing engine will allow us to playback any type of MIDI file we can find.

IN CONCLUSION:

And there you go. I think this is plenty of information for this third part of the series, don't you? The bet advice I can give you, if you're interested in this MIDI series and learning more about it, is to play with the code samples I've supplied here. Experiment with different values for each of them so you can see exactly how these values and types of event affect the way a sound is played on your MIDI device. It will also show you if, in any case, your hardware doesn't support a given feature. Not to mention that being very familiar with everything I've mentionned in this 3rd part will really help you easily and quickly understand the next and final part of the series.

In the next part of the series, we'll attack the actual playback engine itself as I promised in the last part. The code samples here will greatly help us in the next part as we will of course be using them in the playback engine to reproduce a MIDI file. For the sake of completeness, I'll introduce you to the API needed to handle SySex events as well in the next part. This way you'll be ready to handle anything MIDI can throw at your code. It takes a bit of a twist to handle SySex and this is mainly why I'm saving it for the next part of the series. You have enough to digest right now I think. Until then, happy coding, experimenting and learning. MystikShadows
Stéphane Richard
mystikshadows@gmail.com


Download a copy of this tutorial:


How To Program A Game With FreeBASIC - Lesson #2

Written by Lachie D.(February, 2006)

Introduction

In this lesson I'll cover several topics that should introduce you with some real game design oriented programming. It's the programming that extends on the simple "walk around and do nothing" type of demos. Stuff like player to monsters/objects/whatever interaction, artificial intelligence as well as some basics like subroutines(declaration, usage, etc.). I'll also show you how to use the mouse routines with GFXlib. So these two lessons will include most of the statements, methods and routines I think you should know to code any DECENT game using GFXlib. Just don't fear to EXPAND on the knowledge you'll learn here.

This lesson continues on example #2 from lesson #1(download). Please download this archive since it contains the updated SPRITES.BMP file with the swing sprites corrected. They didn't blend well with the walking sprites and I only noticed that after implementing swinging.

We'll add sheep in our mini-game, implement artificial intelligence which will tell the sheep to run from the warrior and add the code that will allow the player to kill them. Poor sheep. :P I'll also add a menu in the code just to point out that it's BAD to end the program completely when the player loses a game. I've seen that in few QBasic games and found it very annoying. This menu will also be a nice opportunity to show you how the mouse routines work in GFXlib and write some more "generic" code. And that's just some of the things we'll cover.

A note: In the first tutorial I inputted a wrong link for the download of the first example. This is the first example program from lesson #1 that you should have been able to download: move_circle.zip

It's possible that this was fixed by Pete but I doubt he puts every article through a rigorous inspection having in mind the amount of articles he receives every month.

What are subroutines and how to use them?

This section is for real beginners so if you are familiar with this topic just skip to the next chapter.

SUBROUTINES are sections of code which execute any set of instructions placed inside them every time you call them(and only then). They are beneficial in many aspects. From reducing the size and complexity of your code to making it easier to write/read. What's important is that you can pass variables to them. I believe this will be more clear to you if you think of these variables as PARAMETERS. Let's say we want to have a subroutine that draws a circle on the position specified by the user. So we need to have a subroutine declared with two variables(parameters) which would flag(set) the circle's position. Here is a simple example of how this would work in FreeBASIC. We would first declare the subroutine like this:

DECLARE SUB DrawCircle (xpos, ypos)

Subroutine declarations go on the beginning of our code before the variable declarations. Some subroutines need to declared behind a user defined type but only if that subroutine includes parameters(variables) defined with this type.

The very subroutine would be formatted like this:

SUB DrawCircle (xpos, ypos)

CIRCLE (xpos, ypos), 10, 15

END SUB

Subroutines need to be placed after all the code in the main module. The concept of main module might not be clear to you since FBIDE(version 0.4.5) still doesn't separate the main module from the subroutines like QBasic IDE did. Just think of the main module as all the code before the first subroutine starts.

The user would call the subroutine like this:

DrawCircle 120, 55

This line would draw a circle on coordinates 120, 55, with a radius of 10 and color 15. We could make a sub that would pass the radius and the color too.

Of course, you will never create this kind of sub since the very CIRCLE statement is simple enough but this example illustrates the issue we are talking about very well.

FUNCTIONS work on a similar way like subroutines but functions can return a value(like be TRUE or FALSE). The most obvious example of a function(from a game design perspective) is a function which checks if the player is colliding with a colliding tile(or object) according to his position. If he is colliding we would flag the function as TRUE and according to this state tell the program to prevent the player to move. Check R.E.Lope's scrolling engine I ported to FreeBASIC to see how this type of function works(go to the end of this tutorial for the download).

Let's roll!

The first thing we'll do with our mini-game code is place all the graphics loading code in a subroutine named "LoadGraphics", the main loop in a subroutine named "MainLoop", lines that initiate player's position in a subroutine named "InitVariables" and create an extra subroutine named "MainMenu".

After these changes our code should look like this(reduced version):

#include "fbgfx.bi" 

' Our subroutine declarations will go here!
DECLARE SUB MainMenu ' Sub that runs our main menu loop.
DECLARE SUB MainLoop ' Sub that runs our main game loop.
DECLARE SUB LoadGraphics ' Sub that loads all the program's graphics.
DECLARE SUB InitVariables ' Sub that initiates the game variables
                          ' (should be called before every new game).

' Useful constants(makes your code easier to read and write).
const FALSE = 0
const TRUE = 1

DIM SHARED background1(64004) AS INTEGER ' An array that will hold the
                                         ' background image
DIM SHARED WarriorSprite(12, 404) AS INTEGER ' An array that will hold
                                             ' the warior sprites.

SCREEN 13,8,2,0 ' 13 means 320*200 graphics resolution; 8 means
                ' 8bit color depth; 2 means two work pages and
                ' 0 means window mode(1 would be full screen mode).
                ' When your program is running you can toggle
                ' between full screen/window mode with ALT+ENTER.
                
SETMOUSE 0,0,0  ' Hides the mouse cursor.

' Our user defined type containing 8 variables.
TYPE ObjectType
X          AS SINGLE
Y          AS SINGLE
Speed      AS SINGLE
Frame      AS INTEGER
Direction  AS INTEGER
Move       AS INTEGER
Attack     AS INTEGER
Alive      AS INTEGER
END TYPE

DIM SHARED Player AS ObjectType ' Our player.

LoadGraphics ' Load the program's graphics.
MainMenu ' Initiate main menu.
END ' End program.

' MAIN MODULE ENDS HERE!
' **********************

SUB LoadGraphics
    
' Graphics loading code goes
' in here!

END SUB

SUB MainLoop

' Main loop code goes in here!

END SUB

SUB MainMenu

' We'll add code here later that calls
' the main loop after the player clicks
' on an option in the menu. For now
' the main loop is called right away.

' Load initial variables(player's position, etc.).
InitVariables
' Call the main game loop.
MainLoop

END SUB

SUB InitVariables
    
' Warrior's(player's) initial
' position, speed(constant)
' and direction(1 = right).
Player.X = 150
Player.Y = 90
Player.Speed = 1
Player.Direction = 1
    
END SUB

You can check the full code here: codever1.txt

I didn't want to input it directly in the tutorial since it's too long and repeats all the code from lesson #1.

Copy and paste the full code in a new FBIDE document. You can compile it and the result is the same as in lesson #1. But now our code is easier to read and manage. You will notice how the “MainMenu” subroutine runs the main loop right away(no conditions). In the final version the main loop will be called only after the player clicks on the right option(like "START GAME") in the main menu.

A subroutine that resets all the game variables(game variables in the sense of player's health, position, number of lives, score, etc.) is something you should always include. I've noticed in several QBasic games bugs which were the result of the programmer putting the initiation of some or all game variables on the beginning of the program and not on the place where the user starts a new game. This caused for some or all game variables not to reset properly when another new game was started(after the first was loss).

I also noticed quite few designers placing the main loop in the main module which is something I don’t understand. It always made their code more difficult to read and to me that kind of code is clumsy to manage. I mean, when the player loses a game the main loop ends and you need to return the program to the beginning of the main module(to the main menu or title screen sub) with a GOTO statement.

Before we continue we need to add new graphics into our program. The new graphics will be loaded from this image(click to enlarge):

Download the original image(EXTRASPR.BMP). As you see it contains the sheep sprites(two sprites for each direction), bloody sheep pieces(7 of them), fireball sprite(the warrior will be able to shoot them at the sheep), a mouse cursor and a menu pointer we'll use on the main menu to flag graphically which option is active.

The code that loads this graphics needs to be inputted in the "LoadGraphics" sub but before that we need to create a generic sprite array that will hold all these sprites. We'll name it "ExtraSprite" and declare it where we declared the other graphics arrays("background1" and "WarriorSprite") with the following line:

DIM SHARED ExtraSprites(18, 900) AS INTEGER ' An array that will hold
                                            ' the additional sprites.

18 because in the new image file we have 18 sprites total and 900(30*30) just to be safe that every sprite will fit. Probably a smaller number would do but the difference in memory consuption is really ignorable. We don't need to be nitpicky here. We are only storing 18 small sprites.

Now we should add this code in the "LoadGraphics" sub(at the end of it):

' Load the image holding the additional sprites and store
' them into the "ExtraSprite" array on specific positions.
BLOAD "EXTRASPR.BMP", 0
' Load the sheep sprites.
FOR imagepos = 1 TO 8
GET (0+(imagepos-1)*24,0)-(19+(imagepos-1)*24,19), ExtraSprite(imagepos, 0)
NEXT imagepos
' Load the bloody sheep meat.
FOR meatpos = 1 TO 7
GET (6+(meatpos-1)*13,25)-(17+(meatpos-1)*13,34), ExtraSprite(meatpos + 8, 0)
NEXT meatpos
' Load the fireball.
GET (11, 42)-(23, 53), ExtraSprite(16, 0)
' Load the mouse cursor.
GET (108, 24)-(121, 40), ExtraSprite(17, 0)
' Load the menu pointer.
GET (127, 25)-(139, 37), ExtraSprite(18, 0)

' The sprites are saved in the "ExtraSprite" array as follows:
' ExtraSprite(1, 0) - sheep moving down image #1
' ExtraSprite(2, 0) - sheep moving down image #2
' ExtraSprite(3, 0) - sheep moving up image #1
' ExtraSprite(4, 0) - sheep moving up image #2
' ExtraSprite(5, 0) - sheep moving left image #1
' ExtraSprite(6, 0) - sheep moving left image #2
' ExtraSprite(7, 0) - sheep moving right image #1
' ExtraSprite(8, 0) - sheep moving right image #2
' ExtraSprite(9, 0) - ExtraSprite(15, 0) - 7 bloody meat pieces
' ExtraSprite(16, 0) - the fireball sprite
' ExtraSprite(17, 0) - the mouse cursor
' ExtraSprite(18, 0) - the menu pointer

I think this code speaks for itself. Note how I was able to use two FOR loops to capture the sheep and bloody meat sprites since I aligned them nicely in the BMP image.

Now we should create an array that will be used to control the sheep. Let's agree we'll have 10 of them in the playfield. This array should be declared with the following line and placed where the player array is declared('DIM SHARED Player AS ObjectType'):

DIM SHARED Sheep(10) AS ObjectType

10 stands for the maximum number of sheep we'll manage. If you want to have 100 sheep maximum on one map/location just change 10 to 100. Sometimes it's good to dimension this type of object with two dimensions, first representing the location/map/etc. Something like this:

DIM SHARED Sheep(15, 10) AS ObjectType

Let's image we would have a game with 15 locations max and with 10 sheep max on each location. This kind of declaring allows us to manage such type of objects(like NPCs) on a more efficient way. Every time the player would change location we would flag a specific "location" variable and according to its value manage the NPCs on THAT SPECIFIC locations(flagged with the first element in the array). But for our mini-game we'll only need one dimension(use the first line).

Note how we connected the "Sheep" array with "ObjectType" so we can use the variables inside "ObjectType" to control the sheep.

We'll add now the code that initiates sheep's positions and their mode(alive or dead) in the "InitVariables" sub. Sheep positions will be RANDOMIZED so the next piece of code shows how you do that too. Entire "InitiVariables" sub with the new code should look like this:

SUB InitVariables
    
RANDOMIZE TIMER
    
' Warrior's(player's) initial
' position, speed(constant)
' and direction(1 = right).
Player.X = 150
Player.Y = 90
Player.Speed = 1
Player.Direction = 1

' Initiate all the sheep(their positions, etc.).
FOR countsheep = 1 TO 10
' Randomize a number 1 to 300(sheep's X position).
Sheep(countsheep).X = INT(RND * 300) + 1 
' Randomize a number 1 to 180(sheep's Y position).
Sheep(countsheep).Y = INT(RND * 180) + 1 
' Randomize a number 1 to 4.
Sheep(countsheep).Direction = INT(RND * 4) + 1 
' New game -> all sheep alive by deafult.
Sheep(countsheep).Alive = TRUE
' Speed of all sheep.
Sheep(countsheep).Speed = 0.6
NEXT countsheep
    
END SUB

All that RND does is returns a number from 0 to 1 based on the random seed. You set the seed with 'RANDOMIZE seed' and the best way to get unpredictable random numbers is to use 'RANDOMIZE TIMER' where TIMER returns the number of milliseconds past midnight. I also recommend you to use 'RANDOMIZE TIMER' every time you start a new game. INT converts the expression in brackets into an integer since we need WHOLE numbers. You can change ' + 1 ' in lines with RND to any number you want to be the minimum possible. For example, the following line would randomize a number from 50 to 60:

RandomNumber = INT(RND * 10) + 50

Ok, now we are fully read to create a sub that will draw and move the sheep according to player's position. We should declare a new sub named "MoveDrawSheep" with this line:

DECLARE SUB MoveDrawSheep

And at the end of our program we have to input the following lines:

SUB MoveDrawSheep
    
' Our "sheep" code goes in here!
    
END SUB

Now, let's create a code that will draw the sheep according to their positions and directions. We need to create a FOR loop that will "go through" all the sheep and according to their direction flag the proper sprite. And if the sheep is alive draw it! The variable that will cycle in the FOR loop(countsheep) will be connected with the Sheep array as you will see in the next peace of code.

SUB MoveDrawSheep
 
' Loop through all the sheep. 
FOR countsheep = 1 TO 10

' The current sheep is not moving by default. 
Sheep(countsheep).Move = FALSE

' Sheep(countsheep).Direction = 1 -> sheep moving right
' Sheep(countsheep).Direction = 2 -> sheep moving left
' Sheep(countsheep).Direction = 3 -> sheep moving down
' Sheep(countsheep).Direction = 4 -> sheep moving up

' The current sheep frame(sprite) by default(sheep not moving).
IF Sheep(countsheep).Direction = 1 THEN Sheep(countsheep).Frame = 7
IF Sheep(countsheep).Direction = 2 THEN Sheep(countsheep).Frame = 5
IF Sheep(countsheep).Direction = 3 THEN Sheep(countsheep).Frame = 1
IF Sheep(countsheep).Direction = 4 THEN Sheep(countsheep).Frame = 3

' If the current sheep is moving flag the proper sprite according 
' to its direction.
IF Sheep(countsheep).Move = TRUE THEN
IF Sheep(countsheep).Direction = 1 THEN Sheep(countsheep).Frame = 6 + Frame1
IF Sheep(countsheep).Direction = 2 THEN Sheep(countsheep).Frame = 4 + Frame1
IF Sheep(countsheep).Direction = 3 THEN Sheep(countsheep).Frame = 0 + Frame1
IF Sheep(countsheep).Direction = 4 THEN Sheep(countsheep).Frame = 2 + Frame1
END IF

' If the current sheep is ALIVE draw it!
IF Sheep(countsheep).Alive = TRUE THEN PUT (Sheep(countsheep).X, Sheep(countsheep).Y), ExtraSprite(Sheep(countsheep).Frame, 0), TRANS

NEXT countsheep
    
END SUB

I think this sub is very illustrative a needs no clarifications. It works almost the same way like the code that draws the player. Just be aware that you can put a variable behind 'TO' with any FOR loop. Like you might want to have different maximum numbers of NPCs on different locations. On the other hand, you can always tag with "Alive" or some other variable NPCs you don't want to manage and draw on the screen. To play this sub we need to call it in the main loop. Just place 'MoveDrawSheep' right after the line that pastes the warrior on the screen('PUT (Player.X, Player.Y), WarriorSprite(Player.Frame, 0), TRANS'). Since we are now using the "Frame1" variable outside the main loop in another sub we need to make it SHARED by placing 'DIM SHARED Frame1' right after the player and sheep declarations. Without this declaration "Frame1" would be always 0 in the "MoveDrawSheep" sub as well as in any other sub where its value is not changed.

After all the changes the code should look like this: codever2.txt

Compile it and the sheep should appear on the screen. But that's not what we want. The sheep just sit there and do nothing. We need to implement an artificial intelligence so the sheep would react on the warrior. It sounds more complex than it really is. It’s just a set of lines which tells the sheep to move in this or that direction according to warrior’s position. We’ll also add some code that will prevent the sheep to walk off the screen like we did with the warrior. The updated "MoveDrawSheep" sub should look like this:

SUB MoveDrawSheep
 
' Loop through all the sheep. 
FOR countsheep = 1 TO 10
 
' The current sheep is not moving by default. 
Sheep(countsheep).Move = FALSE

' Sheep(countsheep).Direction = 1 -> sheep moving right
' Sheep(countsheep).Direction = 2 -> sheep moving left
' Sheep(countsheep).Direction = 3 -> sheep moving down
' Sheep(countsheep).Direction = 4 -> sheep moving up

' The next 4 IF clauses is the AI. In more demanding projects
' your AI will most likely be more complex so you will probably
' place it in a separate sub.
' Each IF checks if the player is less than 50 pixels away from
' the sheep in both directions(scope of detection - change all 50 to 
' higher or less number to get a different scope of detection/reaction). 
' The first condition in each IF checks where's the player according 
' to sheep(in X or Y direction) and then we flag the sheep's direction 
' if this condtition is met. The last two IFs have another condition 
' inside them which is just nitpicking and gives a better feeling.
IF Player.Y < Sheep(countsheep).Y AND ABS(Player.Y-Sheep(countsheep).Y) < 50 AND ABS(Player.X-Sheep(countsheep).X) < 50 THEN
Sheep(countsheep).Move = TRUE
Sheep(countsheep).Direction = 3
END IF
IF Player.Y > Sheep(countsheep).Y AND ABS(Player.Y-Sheep(countsheep).Y) < 50 AND ABS(Player.X-Sheep(countsheep).X) < 50 THEN
Sheep(countsheep).Move = TRUE
Sheep(countsheep).Direction = 4
END IF
IF Player.X > Sheep(countsheep).X AND ABS(Player.X-Sheep(countsheep).X) < 50 AND ABS(Player.Y-Sheep(countsheep).Y) < 50 THEN
Sheep(countsheep).Move = TRUE
IF ABS(Player.X-Sheep(countsheep).X) > 20 THEN Sheep(countsheep).Direction = 2
END IF
IF Player.X < Sheep(countsheep).X AND ABS(Player.X-Sheep(countsheep).X) < 50 AND ABS(Player.Y-Sheep(countsheep).Y) < 50 THEN
Sheep(countsheep).Move = TRUE
IF ABS(Player.X-Sheep(countsheep).X) > 20 THEN Sheep(countsheep).Direction = 1
END IF

' If the current sheep is moving change its position
' according to its direction(flagged with the AI code). 
' If the current sheep is out of bounds prevent it to
' walk off the screen. Note how the SELECT CASE statement
' works.
IF Sheep(countsheep).Move = TRUE THEN
SELECT CASE Sheep(countsheep).Direction
CASE 1
Sheep(countsheep).X = Sheep(countsheep).X + Sheep(countsheep).Speed
IF Sheep(countsheep).X > 300 THEN Sheep(countsheep).X = 300
CASE 2
Sheep(countsheep).X = Sheep(countsheep).X - Sheep(countsheep).Speed
IF Sheep(countsheep).X < 0 THEN Sheep(countsheep).X = 0
CASE 3
Sheep(countsheep).Y = Sheep(countsheep).Y + Sheep(countsheep).Speed
IF Sheep(countsheep).Y > 180 THEN Sheep(countsheep).Y = 180
CASE 4
Sheep(countsheep).Y = Sheep(countsheep).Y - Sheep(countsheep).Speed
IF Sheep(countsheep).Y < 0 THEN Sheep(countsheep).Y = 0
END SELECT
END IF

' The current sheep frame(sprite) by default(sheep not moving).
IF Sheep(countsheep).Direction = 1 THEN Sheep(countsheep).Frame = 7
IF Sheep(countsheep).Direction = 2 THEN Sheep(countsheep).Frame = 5
IF Sheep(countsheep).Direction = 3 THEN Sheep(countsheep).Frame = 1
IF Sheep(countsheep).Direction = 4 THEN Sheep(countsheep).Frame = 3

' If the current sheep is moving flag the proper sprite according 
' to its direction.
IF Sheep(countsheep).Move = TRUE THEN
IF Sheep(countsheep).Direction = 1 THEN Sheep(countsheep).Frame = 6 + Frame1
IF Sheep(countsheep).Direction = 2 THEN Sheep(countsheep).Frame = 4 + Frame1
IF Sheep(countsheep).Direction = 3 THEN Sheep(countsheep).Frame = 0 + Frame1
IF Sheep(countsheep).Direction = 4 THEN Sheep(countsheep).Frame = 2 + Frame1
END IF

' If the current sheep is ALIVE draw it!
IF Sheep(countsheep).Alive = TRUE THEN PUT (Sheep(countsheep).X, Sheep(countsheep).Y), ExtraSprite(Sheep(countsheep).Frame, 0), TRANS

NEXT countsheep
    
END SUB

Few things I want to explain here. You will notice I used a new statement here - SELECT CASE. SELECT CASE works very simple and it's a nice substitute for IF clauses. In QBasic it was known as being faster than IF clauses. It functions like this:

SELECT CASE some_variable
CASE value1
' You put here the code that
' needs to execute if
' some_variable = value1
CASE value2
' You put here the code that
' needs to execute if
' some_variable = value2
CASE value3
.
.
.
END SELECT ' End every SELECT CASE with this.

Anyway, SELECT CASE comes in handy very often with certain problems that can be coded more illustrative and simpler than using several IF clauses.

Another thing I didn't point out the first time I pasted the "MoveDrawSheep" sub. In some cases you will need to add another variable to the user defined type you will connect with your enemy array("ObjectType" in our mini-game). I usually name that variable "Exists". You see, you might want to have a game where a corpse of a monster or an enemy is left in the playfield once the player kills it. So you need another variable together with "Alive". "Alive" would flag if the monster/enemy/whatever is alive or not and according to this status we would check for collision with it and similar. "Exists" would flag if this monster/enemy is activated(present) at all and if it's not the program wouldn't draw it! If "Exists" of that monster would be TRUE we would always draw it no matter if it's alive or not. If this monster would be dead(Alive = FALSE) we would tell the computer to paste the "corpse" sprite of that monster and not the regular "walking" sprite. In our mini-game when the player kills the sheep we'll spawn some bloody meat pieces in the playfield(be patient) so we don't need corpses. We WANT for the sheep to DISAPPEAR from the playfield once we kill it. Just have this in mind when working on your own project where your requirements might be different. Also, the more "smarter" enemies you want for your game to feature you will have to create a more complex AI and will probably place it in a separate sub. QB Express features quite few AI tutorials so if interested in this topic read your QB Express :P

Now I'll do some more coping and pasting of the current code. I know, this is probably annoying you on this stage but it needs to be done. I'll remove all the code that controls and pastes the warrior from the main loop and place it in a separate sub. We'll name this sub "MoveDrawPlayer". We also need to declare it and call it in the main loop. This new sub should look like this:

SUB MoveDrawPlayer
    
' Player.Direction = 1 -> warrior moving right
' Player.Direction = 2 -> warrior moving left
' Player.Direction = 3 -> warrior moving down
' Player.Direction = 4 -> warrior moving up

Player.Move = FALSE ' By deafult player is not
                    ' moving.

' According to pushed key move the
' player and flag the proper direction.
IF MULTIKEY(SC_RIGHT) THEN 
Player.X = Player.X + Player.Speed
Player.Direction = 1
Player.Move = TRUE
END IF
IF MULTIKEY(SC_LEFT) THEN 
Player.X = Player.X - Player.Speed
Player.Direction = 2
Player.Move = TRUE
END IF
IF MULTIKEY(SC_DOWN) THEN 
Player.Y = Player.Y + Player.Speed
Player.Direction = 3
Player.Move = TRUE
END IF
IF MULTIKEY(SC_UP) THEN 
Player.Y = Player.Y - Player.Speed
Player.Direction = 4
Player.Move = TRUE
END IF

' The following 4 conditions prevent
' the warrior to walk off the screen.
IF Player.X < 0 THEN 
Player.Move = FALSE
Player.X = 0
END IF
IF Player.X > 300 THEN 
Player.Move = FALSE
Player.X = 300
END IF
IF Player.Y < 0 THEN 
Player.Move = FALSE
Player.Y = 0
END IF
IF Player.Y > 180 THEN 
Player.Move = FALSE
Player.Y = 180
END IF

' Attack variable needs to reduce to 0 by 1 in
' each cycle since we want for the attack to 
' "time out" once we initiate it(swing with the
' sword).
Player.Attack = Player.Attack - 1
IF Player.Attack < 0 THEN Player.Attack = 0

' When the player presses SPACE and the SPACE
' key is released from the last time you 
' swung the sword(KeyPressed = FALSE)
' initiate new attack(Player.Attack = 10) and
' flag that SPACE is pressed(KeyPressed = TRUE).
' KeyPressed variable is used to prevent the
' player to be able to hold the SWING. This can
' be done on more ways like prevent the player
' to swing until Player.Attack = 0(replace
' KeyPressed = FALSE with this condition).
IF MULTIKEY(SC_SPACE) AND KeyPressed = FALSE THEN
KeyPressed = TRUE
Player.Attack = 10
END IF

' According to player's direction flag the 
' proper sprite.
IF Player.Direction = 1 THEN Player.Frame = 6 + Frame1
IF Player.Direction = 2 THEN Player.Frame = 4 + Frame1
IF Player.Direction = 3 THEN Player.Frame = 0 + Frame1
IF Player.Direction = 4 THEN Player.Frame = 2 + Frame1

' If the player is attacking flag the proper attack
' sprite according to player's direction.
IF Player.Attack >0 THEN
IF Player.Direction = 1 THEN Player.Frame = 12
IF Player.Direction = 2 THEN Player.Frame = 11
IF Player.Direction = 3 THEN Player.Frame = 10
IF Player.Direction = 4 THEN Player.Frame = 9
END IF

' Pastes the warrior on Player.X and Player.Y coordinates, 
' using sprite number Player.Frame and skips background color(TRANS).
PUT (Player.X, Player.Y), WarriorSprite(Player.Frame, 0), TRANS

' Flag KeyPressed as FALSE(pressing is not locked!) only when
' the player releases SPACE or ENTER.
IF MULTIKEY(SC_ENTER) OR MULTIKEY(SC_SPACE) THEN GOTO skipkeyrestore:
KeyPressed = FALSE
skipkeyrestore:

END SUB

You'll notice one new thing in this code - I implemented sword swinging! In our mini-game we'll control the sword swinging only with one variable - "Attack". When the player presses SPACE "Attack" is set as 10. As long as "Attack" is above 0 we'll treat this as a situation where the warrior is swinging with his sword - attack mode is active! We also must have two lines of code which reduce "Attack" to 0 so we can "time out" the attack. Change 10 to some other number if you want to have a longer or shorter period of swinging. This can be done one more ways. I often use two variables. One that "times" the attack(usually named "AttackTime") and one which flags if attack is TRUE or FALSE. But for the sake of our mini-game we'll use only one variable. With projects where you would have more sprites representing swinging, some even swinging and running you'll need to code this on a slightly different way. But in any game where you have a hero with a short range weapon you must have one main variable which will flag if swinging is happening or not so you can check for collision with the enemies. Also note how I used the "KeyPressed" variable to prevent the player to double press as well as to hold the swing all the time(he must push SPACE repeatedly). This method I use more often on places where I want to prevent double clicking(or double pressing). I recommend you to become familiar with this method since it's a simple and efficient solution for "double press" problems.

The updated "MainLoop" subroutine should look like this:

SUB MainLoop

DO

' Frame1 changes from 1 to 2 or vice versa every
' 16 cycles(set with Frame2 variable).
Frame2 = (Frame2 MOD 16) + 1
IF Frame2 = 10 THEN Frame1 = (Frame1 MOD 2) + 1
IF Player.Move = FALSE OR Frame1 = 0 THEN Frame1 = 1

' Pastes the background.
PUT (0, 0), background1(0), PSET

MoveDrawSheep ' Paste the sheep and move them.
MoveDrawPlayer ' Paste and control the player.

' Copy the work page(page 1) to the visible page(page 0).
SCREENCOPY
SCREENSYNC ' Wait for vertical blank(use always in all the game 
           ' game loops to get 85 FPS).
           
SLEEP 2    ' Statement used to prevent 100% CPU usage(prevents
           ' the program to use up all the computer cycles - useful
           ' and recommended).

LOOP UNTIL MULTIKEY(SC_Q) OR MULTIKEY(SC_ESCAPE) 
' Execute the loop until the user presses Q or ESCAPE.

END SUB

Now the main loop is easier to manage. For example, if you want for the sheep to paste OVER the player you should just place 'MoveDrawSheep' AFTER 'MoveDrawPlayer'. But we'll leave it like this.

The entire code now should look like this: codever3.txt

It's best you copy and paste all of this into FBIDE.

Ok, we have the warrior, we have the sheep, we have implemented swinging. So what now?

Let's first add collision(swing detection) with the sheep. When the player is swinging and a sheep is in range we will kill it(make this sheep's Alive = FALSE). We'll work in the "MoveDrawPlayer" sub now. We should place this code inside the 'IF Player.Attack > 0' clause above other IF clauses. We'll create a FOR loop which will go through all the sheep like in the "MoveDrawSheep" sub and check for distance between the sheep and the warrior according to warriors's direction. The new code is as follows:

' If the player is attacking...
IF Player.Attack >0 THEN

' If the player is swinging check for collision with the sheep.
' In our specific range detector we have 3 main conditions.
' First, the sheep must be alive for us to check collision with
' it. Second, the warrior and the sheep must be less that 15 pixels
' apart in horizontal direction. Third, the warrior and the sheep 
' must be less than 15 pixels apart in vertical direction.
' You can tweak the pixel distances if you want and can get a
' better result. The secondary condition depends on the direction.
' For example, if the warrior is facing right(Direction = 1) sheep
' must be at least one pixel to the right from the warrior.
' Anyway, if all conditions are met the sheep is killed(Alive = FALSE).
FOR checksheep = 1 TO 10
IF Sheep(checksheep).Alive = TRUE AND ABS(Player.X-Sheep(checksheep).X) < 15 AND ABS(Player.Y-Sheep(checksheep).Y) < 15 THEN
IF Player.Direction = 1 AND Sheep(checksheep).X > Player.X THEN Sheep(checksheep).Alive = FALSE
IF Player.Direction = 2 AND Sheep(checksheep).X < Player.X THEN Sheep(checksheep).Alive = FALSE
IF Player.Direction = 3 AND Sheep(checksheep).Y > Player.Y THEN Sheep(checksheep).Alive = FALSE
IF Player.Direction = 4 AND Sheep(checksheep).Y < Player.Y THEN Sheep(checksheep).Alive = FALSE
END IF
NEXT checksheep

' If the player is attacking flag the proper attack
' sprite according to player's direction.
IF Player.Direction = 1 THEN Player.Frame = 12
IF Player.Direction = 2 THEN Player.Frame = 11
IF Player.Direction = 3 THEN Player.Frame = 10
IF Player.Direction = 4 THEN Player.Frame = 9
END IF

I belive this code is enough commented and needs no extra explanation. If you update the "MoveDrawPlayer" sub on this way and compile the code you'll be able to kill the sheep but they will simply disappear off the screen and that's boring.

This is where the real fun starts. I'm going to introduce now the "layering" method I re-invented. I'm using the expression "re-invention" since I know other people used/use something similar but I came up with this method myself. Anyway, I think mine is very user-friendly and versatile. What is this layering method? Well, it's based on two parts. Initiation subs and layer subs. Layer subs paste various particles on the screen(anything from bullets to blood spills) if they are active(a bullet shot out or a blood squired out). They "go through" the particles with a FOR loop like it's done in the "MoveDrawSheep" sub. You can have more particle layers for different types of particles(one for blood, one for bullets, one for explosions, etc.) or place all of them in one layer. Initiation subs INITIATE/SPAWN a free particle(not already activated) on a specific positions with a specific type. You are meant to call this sub on places where you want for a new particle to appear on the screen(monster killed so we need new blood, the player shot a projectile from a weapon, etc.).

We need first to declare our particles. We'll do this with the following line(place it after the player and the sheep declarations):

DIM SHARED Particle(100) AS ObjectType

As you see we connected this array with the "ObjectType" user defined type. We can create a new user defined type especially for the particles but for the sake of this tutorial we won't complicate. With 100 we have set the maximum possible number of particles on the screen. The more demanding your game will be in this perspective you will have to set a higher number. Since our particle layer will have other requirements than the "Sheep" and the "Player" array do we need to add few more variables in the "ObjectType" user defined type. "Typ" will flag the type of the particle and "Duration" generic duration from the duration of the very particle to the duration of its movement(will depend on the particle's type). Updated "ObjectType" user defined type should look like this:

TYPE ObjectType
X          AS SINGLE
Y          AS SINGLE
Speed      AS SINGLE
Frame      AS INTEGER
Direction  AS INTEGER
Move       AS INTEGER
Attack     AS INTEGER
Alive      AS INTEGER
Typ        AS INTEGER
Duration   AS INTEGER
END TYPE

In our mini-game we will feature only two types of particles - bloody meat pieces and the fireball. We'll start with the bloody meat pieces and say that they will be flagged with "Typ" value of 1. "Typ" value of 2 will flag the fireball(later).

We need to declare a new subroutine named "InitiateParticle". We'll declare it on this way(place this line together with other subroutine declarations):


DECLARE SUB InitiateParticle (xpos!, ypos!, parttype, partdirec)

This is our first sub with parameters(variables that are passed to it when it's called). Values that end with '!' are SINGLE and since we are going to pass the particle's position using the warrior's or sheep's positions(flagged with SINGLE variables) we need to declare xpos and ypos AS SINGLE. The easiest way is to put '!' at the end of them. "parttype" will flag the type of the particle we want to initiate(spawn) and "partdirec" its direction(not used with the bloody meat pieces but will be with the fireball). The concept of our mini-game doesn't require more variables to be passes but your project might so don't hesitate to declare this subroutine with more variables. The very "InitiateParticle" sub will seek for a free particle which is flagged with the "Alive" variable. Once a free particle is found its characteristics are set(some of the characteristics are passed with the sub parameters), it's flagged as taken(not free -> Alive = TRUE) and the sub is exited(with 'EXIT SUB'). It's usually better to create a special user defined type for particles where you would declare a variable named "Locked" which then would be used to flag the status of a particle(free or not). But to keep it simple we'll use "Alive" from the "ObjectType" user defined type. Just don't be confused with the way "Alive" is used with the sheep and with how "Alive" is used with the particles.

This is the first version of the "InitiateParticle" sub which for now only manages the bloody meat pieces(place this code at the end of our program):

SUB InitiateParticle (xpos!, ypos!, parttype, partdirec)

' Check the particles for a free one.
FOR countparticle = 1 TO 100

' If the current one is free(Alive = FALSE) activate 
' it and pass certain values to it.
IF Particle(countparticle).Alive = FALSE THEN
    
Particle(countparticle).Alive = TRUE
Particle(countparticle).Typ = parttype ' Pass the particle type
                                       ' from parttype.
Particle(countparticle).X = xpos! ' Pass the particle's position
Particle(countparticle).Y = ypos! ' from xpos! and ypos!

' If the particle is type 1(bloody meat pieces)
' randomize its DIRECTION(from 1 to 8), set
' its DURATION(with bloody meat pieces it flags
' how much the piece will move once it's spawned),
' set its speed(from 0.1 to 1) and its FRAME(sprite
' from ExtraSprite array -> from 9 to 15, check
' LoadGraphics sub).
IF Particle(countparticle).Typ = 1 THEN
Particle(countparticle).Direction = INT(RND * 8) + 1
Particle(countparticle).Duration = 10
Particle(countparticle).Speed = (INT(RND * 10) + 1) / 10
Particle(countparticle).Frame = INT(RND * 6) + 9
END IF
EXIT SUB ' Once the particle is initiated exit this sub.

END IF
    
NEXT countparticle ' If a particle is not free in this slot
                   ' seek in the next.

END SUB

I think the comments say all you need to know at this point. I would just like to point out that the way you will pass values to a particle will depend on your project. What's mandatory in this method is a FOR loop which seeks for a FREE PARTICLE and 3 values you pass into the sub, particle's x and y position and its type. I really doubt you can work without these 3 variables. You will notice that we are not using "parttype" with bloody meat pieces since the direction of a spawned meat piece is randomized. So when you are initiating a bloody meat piece the last value can be any number since it won't be used.

What's also good about this method is that if you have the maximum number of particles already present on the screen(100 in our case) and you try to initiate a new one the program won't crash or interrupt. Simply, a new particle won't be initiated. Of course, this is the situation you should avoid in your programs.

Now we need a sub that will draw and manage(move if needed) activated particles. Place this code at the end of the program:

SUB ParticleLayer

' Go through all the particles...
FOR countparticle = 1 TO 100

' If the current particle is activated(Alive = TRUE)
' manage and draw it.
IF Particle(countparticle).Alive = TRUE THEN

' If the current particle is type 1(bloody meat piece)
' reduce its duration from 10 to 0. While duration is
' above 0 the particle it moved according to its
' direction.
IF Particle(countparticle).Typ = 1 THEN
Particle(countparticle).Duration = Particle(countparticle).Duration - 1
IF Particle(countparticle).Duration < 0 THEN Particle(countparticle).Duration = 0
' While duration is above 0 move the particle
' according to its direction with preset speed.
' Directions span from up(1), up-right(2), right(3), all
' the way to up-left(8).
IF Particle(countparticle).Duration > 0 THEN
SELECT CASE Particle(countparticle).Direction
CASE 1
Particle(countparticle).Y = Particle(countparticle).Y - Particle(countparticle).Speed
CASE 2
Particle(countparticle).Y = Particle(countparticle).Y - Particle(countparticle).Speed
Particle(countparticle).X = Particle(countparticle).X + Particle(countparticle).Speed
CASE 3
Particle(countparticle).X = Particle(countparticle).X + Particle(countparticle).Speed
CASE 4
Particle(countparticle).Y = Particle(countparticle).Y + Particle(countparticle).Speed
Particle(countparticle).X = Particle(countparticle).X + Particle(countparticle).Speed
CASE 5
Particle(countparticle).Y = Particle(countparticle).Y + Particle(countparticle).Speed
CASE 6
Particle(countparticle).Y = Particle(countparticle).Y + Particle(countparticle).Speed
Particle(countparticle).X = Particle(countparticle).X - Particle(countparticle).Speed
CASE 7
Particle(countparticle).X = Particle(countparticle).X - Particle(countparticle).Speed
CASE 8
Particle(countparticle).Y = Particle(countparticle).Y - Particle(countparticle).Speed
Particle(countparticle).X = Particle(countparticle).X - Particle(countparticle).Speed
END SELECT
END IF  ' End if duration is above 0.
END IF  ' End if particle is type 1.

' Draw the current particle on its position with its frame.
PUT (Particle(countparticle).X, Particle(countparticle).Y), ExtraSprite(Particle(countparticle).Frame, 0), TRANS

END IF ' End if particle is activated(Alive = TRUE).

NEXT countparticle ' Check next particle.

END SUB

Again, comments explain all of it. Be sure to declare this subroutine too with:

DECLARE SUB ParticleLayer

For particles to appear on the screen we need to call the "ParticleLayer" sub in the main loop. Place it before "MoveDrawSheep" and "MoveDrawPlayer" sub calls since we want for the warrior and the sheep to walk ON the blood(paste other sprites OVER the blood). Some particle layers need to be pasted over other sprites(for example, explosions). The updated "MainLoop" sub:

SUB MainLoop

DO

' Frame1 changes from 1 to 2 or vice versa every
' 16 cycles(set with Frame2 variable).
Frame2 = (Frame2 MOD 16) + 1
IF Frame2 = 10 THEN Frame1 = (Frame1 MOD 2) + 1
IF Player.Move = FALSE OR Frame1 = 0 THEN Frame1 = 1

' Pastes the background.
PUT (0, 0), background1(0), PSET

ParticleLayer ' Paste the particles.
MoveDrawSheep ' Paste the sheep and move them.
MoveDrawPlayer ' Paste and control the player.

' Copy the work page(page 1) to the visible page(page 0).
SCREENCOPY
SCREENSYNC ' Wait for vertical blank(use always in all the game 
           ' game loops to get 85 FPS).
           
SLEEP 2    ' Statement used to prevent 100% CPU usage(prevents
           ' the program to use up all the computer cycles - useful
           ' and recommended).

LOOP UNTIL MULTIKEY(SC_Q) OR MULTIKEY(SC_ESCAPE) 
' Execute the loop until the user presses Q or ESCAPE.

END SUB

No particles will appear if we don't initiate them. We have decided to initiate bloody meat pieces when a sheep is killed. We will spawn 7 bloody meat pieces every time a sheep is killed from the center of the killed sheep(with few pixels apart in all directions to get a better effect). This change happens in the "MoveDrawPlayer" sub:

' If the player is attacking...
IF Player.Attack >0 THEN

' If the player is swinging check for collision with the sheep.
' In our specific range detector we have 3 main conditions.
' First, the sheep must be alive for us to check collision with
' it. Second, the warrior and the sheep must be less that 15 pixels
' apart in horizontal direction. Third, the warrior and the sheep 
' must be less than 15 pixels apart in vertical direction.
' You can tweak the pixel distances if you want and can get a
' better result. The secondary condition depends on the direction.
' For example, if the warrior is facing right(Direction = 1) sheep
' must be at least one pixel to the right from the warrior.
' Anyway, if all conditions are met the sheep is killed(Alive = FALSE).
FOR checksheep = 1 TO 10
IF Sheep(checksheep).Alive = TRUE AND ABS(Player.X-Sheep(checksheep).X) < 15 AND ABS(Player.Y-Sheep(checksheep).Y) < 15 THEN
IF Player.Direction = 1 AND Sheep(checksheep).X > Player.X THEN Sheep(checksheep).Alive = FALSE
IF Player.Direction = 2 AND Sheep(checksheep).X < Player.X THEN Sheep(checksheep).Alive = FALSE
IF Player.Direction = 3 AND Sheep(checksheep).Y > Player.Y THEN Sheep(checksheep).Alive = FALSE
IF Player.Direction = 4 AND Sheep(checksheep).Y < Player.Y THEN Sheep(checksheep).Alive = FALSE
IF Sheep(checksheep).Alive = FALSE THEN
' If the sheep is killed spawn 7 bloody meat pieces(particle type 1 
' -> third parameter).
InitiateParticle Sheep(checksheep).X+10, Sheep(checksheep).Y+10, 1, 0
InitiateParticle Sheep(checksheep).X+13, Sheep(checksheep).Y+10, 1, 0
InitiateParticle Sheep(checksheep).X+9, Sheep(checksheep).Y+13, 1, 0
InitiateParticle Sheep(checksheep).X+8, Sheep(checksheep).Y+11, 1, 0
InitiateParticle Sheep(checksheep).X+12, Sheep(checksheep).Y+8, 1, 0
InitiateParticle Sheep(checksheep).X+11, Sheep(checksheep).Y+9, 1, 0
InitiateParticle Sheep(checksheep).X+11, Sheep(checksheep).Y+9, 1, 0
END IF
END IF
NEXT checksheep

Note where I placed 7 calls of the "InitiateParticle" sub and how the third parameter is 1(bloody meat piece). The last parameter with type 1 particles can be any number since we are not using it in initiation.

The last version of the entire code: codever4.txt

If you compile this you'll be able to kill the sheep and the blood will squirt out of them. The result is not the best and perhaps we should have implemented sheep corpses too. Still, we are not trying here to win an award. This IS a tutorial.

If you went through the code you might have noticed one more change. I inputted these lines in the "InitVariables" sub:

FOR countparticle = 1 TO 100
Particle(countparticle).Alive = FALSE    
NEXT countparticle

This FOR loops sets all particles as free(not activated!). ALWAYS make sure that you reset all the particles from the last game every time you start a new game. In your case particles' status might be flagged with another variable like "Locked" or whatever you choose.

Next thing we'll do is implement a fireball in the game which will be controlled with the particle layer and which will be able to kill the sheep. This is mainly to show you how particle layers can be used to control projectiles too. First we need to modify the "InitiateParticle" sub by adding the code for particle type 2.

SUB InitiateParticle (xpos!, ypos!, parttype, partdirec)

' Check the particles for a free one.
FOR countparticle = 1 TO 100

' If the current one is free(Alive = FALSE) activate 
' it and pass certain values to it.
IF Particle(countparticle).Alive = FALSE THEN
    
Particle(countparticle).Alive = TRUE
Particle(countparticle).Typ = parttype ' Pass the particle type
                                       ' from parttype.
Particle(countparticle).X = xpos! ' Pass the particle's position
Particle(countparticle).Y = ypos! ' from xpos! and ypos!

' If the particle is type 1(bloody meat pieces)
' randomize its DIRECTION(from 1 to 8), set
' its DURATION(with bloody meat pieces it flags
' how much the piece will move once it's spawned),
' set its speed(from 0.1 to 1) and its FRAME(sprite
' from ExtraSprite array -> from 9 to 15, check
' LoadGraphics sub).
IF Particle(countparticle).Typ = 1 THEN
Particle(countparticle).Direction = INT(RND * 8) + 1
Particle(countparticle).Duration = 10
Particle(countparticle).Speed = (INT(RND * 10) + 1) / 10
Particle(countparticle).Frame = INT(RND * 6) + 9
END IF

' If the particle is type 2(fireball) flag
' its direction according to partdirec, its
' duration and speed(modify this for faster
' or slower fireball) and sprite(only one
' image of fireball in the ExtraSprite array
' placed on position 16).
IF Particle(countparticle).Typ = 2 THEN
Particle(countparticle).Direction = partdirec
Particle(countparticle).Duration = 100
Particle(countparticle).Speed = 2
Particle(countparticle).Frame = 16
END IF

EXIT SUB ' Once the particle is initiated exit this sub.

END IF
    
NEXT countparticle ' If a particle is not free in this slot
                   ' seek in the next.

END SUB

The direction of the fireball we'll pass using the player's direction since the fireball needs to travel in direction where the player is facing. Another update must happen in the "ParticleLayer" sub. Place this code after line 'END IF ' End if particle is type 1.':

' If particle type is 2(fireball)...
IF Particle(countparticle).Typ = 2 THEN
' If the particle's life has expired(duration = 0) kill it(Alive = FALSE).
Particle(countparticle).Duration = Particle(countparticle).Duration - 1
IF Particle(countparticle).Duration < 0 THEN Particle(countparticle).Alive = FALSE
' According to particle's direction move it(right, left, down, up)
' with preset speed.
SELECT CASE Particle(countparticle).Direction
CASE 1
Particle(countparticle).X = Particle(countparticle).X + Particle(countparticle).Speed
CASE 2
Particle(countparticle).X = Particle(countparticle).X - Particle(countparticle).Speed
CASE 3
Particle(countparticle).Y = Particle(countparticle).Y + Particle(countparticle).Speed
CASE 4
Particle(countparticle).Y = Particle(countparticle).Y - Particle(countparticle).Speed
END SELECT

' If the fireball is off the screen kill it.
IF Particle(countparticle).Y < -12 OR Particle(countparticle).Y > 200 OR Particle(countparticle).X < -12 OR Particle(countparticle).X > 320 THEN Particle(countparticle).Alive = FALSE

' Check all sheep if the fireball is in collision with any of them.
' The collision is check from the centers of the sheep and the
' fireball and they need to be less than 11 pixel apart.
FOR checksheep = 1 TO 10
' If the fireball is active(not destroyed upon collision with
' the previous sheep), the current sheep is alive and they are
' in collision kill the fireball and the sheep.
IF Particle(countparticle).Alive = TRUE AND Sheep(checksheep).Alive = TRUE AND ABS(Particle(countparticle).X+5-Sheep(checksheep).X-10) < 11 AND ABS(Particle(countparticle).Y+5-Sheep(checksheep).Y-10) < 11 THEN 
Sheep(checksheep).Alive = FALSE ' Kill the fireball.
Particle(countparticle).Alive = FALSE ' Kill the sheep.
' If the sheep is killed spawn 7 bloody meat pieces(particle type 1 
' -> third parameter).
InitiateParticle Sheep(checksheep).X+10, Sheep(checksheep).Y+10, 1, 0
InitiateParticle Sheep(checksheep).X+13, Sheep(checksheep).Y+10, 1, 0
InitiateParticle Sheep(checksheep).X+9, Sheep(checksheep).Y+13, 1, 0
InitiateParticle Sheep(checksheep).X+8, Sheep(checksheep).Y+11, 1, 0
InitiateParticle Sheep(checksheep).X+12, Sheep(checksheep).Y+8, 1, 0
InitiateParticle Sheep(checksheep).X+11, Sheep(checksheep).Y+9, 1, 0
InitiateParticle Sheep(checksheep).X+11, Sheep(checksheep).Y+9, 1, 0
END IF
NEXT checksheep ' Check next sheep for collision.

END IF ' End if particle is type 2.

The code speaks for itself. There is the code that moves the fireball according to its direction, the code that "kills" it if it's off the screen and the code that checks for collision with the sheep, very similar to the one that checks for collision with the sword. All we need now is the code that spawns the fireball. The fireball will be spawn when the player pushes ENTER. Place this code in the "MoveDrawPlayer" sub above the PUT statement:

' If the player pushes ENTER initiate a fireball but only
' if another one is NOT ACTIVE(flagged with the FireBFree variable).
IF MULTIKEY(SC_ENTER) THEN
FireBFree = TRUE ' By deafult the fireball is free.
' Go through all the particles and check if an active one is
' the fireball.
FOR countparticle = 1 TO 100
IF Particle(countparticle).Alive = TRUE AND Particle(countparticle).Typ = 2 THEN FireBFree = FALSE   
NEXT countparticle
' Note how player's direction is passed into the sub(4th parameter).
IF FireBFree = TRUE THEN InitiateParticle Player.X+4, Player.Y+5, 2, Player.Direction
END IF

As you see I coded this part on the way it prevents the player to fire a fireball if another one is already present on the screen. This is to prevent the abuse of the fireball feature and not to allow the player to fire fireballs one after another. You can solve this "problem" on more ways. Like add another variable which would be set as 100 every time the player would fire a fireball and then reduce it in every loop(like the "Attack" variable). And then the player wouldn't be able to shoot another fireball until this variable reaches 0. Think of this as "reload" feature in games with firearms which can be shorter or longer for different weapons.

We are coming close to finishing the very mini-game. What I still want to do is add a millisecond precise timer and print the playtime so we can "score" the game after all the sheep are killed. The very timer should be placed in the main loop(naturally). Just put it right after 'DO':

' Our timer(millisecond precise).
' starttime variable checks if
' a millisecond has passed
' using the TIMER statement.
' & is used with variables
' you want to return DOUBLE
' PRECISION values. When 10
' milliseconds has passed
' add one seconds and return
' the milliseconds to 0.
IF starttime + 0.1 <= TIMER& THEN
milsec = milsec + 1
IF milsec > 9 THEN
seconds = seconds + 1
milsec = 0
END IF
starttime = TIMER&
END IF

This is a peace of very simple code. The only new thing about this code is that it uses DOUBLE PRECISION variables(they end with & or you declare them as DOUBLE in your program). "seconds" will store the number of seconds passed in the round and "milsec" the number of milliseconds which are used to change seconds every time 10 of them passes(naturally). For this code to work we should declare "starttime", "seconds" and "milsec" on the beginning of our program together with other variable declarations as shared. The code:

DIM SHARED seconds, milsec
DIM SHARED starttime AS DOUBLE

"starttime" needs to be DOUBLE because we are counting MILLISECONDS using the TIMER statement! Also, with every new game the timer needs to be reset so these lines need to be in the "InitVariables" sub:

milsec = 0
seconds = 0

We would like for the playtime to print on the screen while we are playing the game. We'll use the PRINT statement for this. At the end of this tutorial I'll give you a link to a better CUSTOM FONT printing routine but to make this simple we'll use PRINT in our mini-game. Put these two lines before 'SCREENCOPY' in the main loop:

LOCATE 1, 1
PRINT "Playtime: " + STR$(seconds) + "." + STR$(milsec)

LOCATE sets the console cursor to the row and column given(1 and 1 in the above line). You'll only use it when using the PRINT statements. Very handy if you are making an ASCII game but in other situation not really.

The last thing we'll do is add a score screen which will print the playtime(how much seconds it took the player to kill all the sheep) and some message according to this time. We'll create another sub named "PrintScore" which should be declared like all the rest and looks like this:

SUB PrintScore
    
' This sub is executed when a game round 
' is completed.

CLS ' Clear the screen.

' If any of the sheep is alive EXIT this sub since
' the user aborted the game and no sense in
' printing the score.
FOR checksheep = 1 TO 10
IF Sheep(checksheep).Alive = TRUE THEN EXIT SUB   
NEXT checksheep

' Play a loop which ends until the use
' pushes escape.
DO

' Print the number of seconds the round took
' to complete.
LOCATE 2, 1
PRINT "You needed " + STR$(seconds) + "." + STR$(milsec)+" seconds"
LOCATE 3, 1
PRINT "to kill all the sheep."

' According to this time print a different
' message. More time it took the player
' to finish a round print a less
' complimenting message.
message$ = "An ok score...for a granny!"
IF seconds < 16 THEN message$ = "Not bad!"
IF seconds < 11 THEN message$ = "Good job!"
IF seconds < 8 THEN message$ = "Excellent job!"
LOCATE 5, 1
PRINT message$
LOCATE 7, 1
PRINT "Press ESCAPE to return to main menu."

' Standard statements in every loop.
SCREENCOPY
SCREENSYNC
SLEEP 2

' End loop when ESCAPE is pushed.
LOOP UNTIL MULTIKEY(SC_ESCAPE)
    
END SUB

Nothing groundbreaking here and it's all said in the comments. We need to call this sub when the game ends in the main menu sub(after the main loop call). The updated main menu sub:

SUB MainMenu
    
' Will add code here later that calls
' the main loop after the player clicks
' on an option in the menu. For now
' the main loop is called right away.

' Load initial variables(player's position, etc.).
InitVariables
' Call the main game loop.
MainLoop
' Show the score screen if all sheep are killed.
PrintScore

END SUB

We aren't done yet because if you remember the main loop ends only when the player pushes ESCAPE. We need to add another condition. We'll add a variable in the main loop named "GameEnd". We'll input that it's TRUE by default and then right after it add a FOR loop which will check if any of the sheep is alive. If any alive sheep is found "GameEnd" is changed to FALSE. An condition is added to the main DO loop which should end it when "GameEnd" is TRUE. So until all the sheep are dead "GameEnd" will always be changed to FALSE and the loop won't end. The changed end of the "MainLoop" sub:

' Copy the work page(page 1) to the visible page(page 0).
SCREENCOPY
SCREENSYNC ' Wait for vertical blank(use always in all the game 
           ' game loops to get 85 FPS).
           
SLEEP 2    ' Statement used to prevent 100% CPU usage(prevents
           ' the program to use up all the computer cycles - useful
           ' and recommended).

' A round is over by deafult.
GameEnd = TRUE
' Check all the sheep. If any of them is alive the
' game should not end(round not completed).
FOR checksheep = 1 TO 10
IF Sheep(checksheep).Alive = TRUE THEN GameEnd = FALSE   
NEXT checksheep

LOOP UNTIL MULTIKEY(SC_Q) OR MULTIKEY(SC_ESCAPE) OR GameEnd = TRUE
' Execute the loop until the user presses Q or ESCAPE or the game ends.

END SUB

That's it. The mini-game is completed! And I must say, it came out better than I thought. There is actually some play value there. Or not. Not important. Like I already said, this is a tutorial.

The entire code done so far: codever5.txt

The final touches

We could end here now but I won't. I really want to add a main menu. It will contain a bunch of generic code and some new code that uses the mouse routines. It should allow you to start and exit the game and when a round is completed or aborted the program should get back to the main menu again.

For the main menu screen we'll use this image(link). Don't get excited by it. Only two options("Play Sheep Massacre" and "Exit") will be active. Other two mini-games I originally planed for the next lessons but I doubt I'll complete them since I want to keep my sanity.

To store the main menu image we need to declare another memory array(memory buffer).

We can re-dimension the "background1" array and add another dimension but to keep it simple we'll declare another array named "background2". Put this with other variable declarations:

DIM SHARED background2(64004) AS INTEGER

We also need to load this image into memory. Put these lines in the "LoadGraphics" sub:

BLOAD "mainmenu.bmp", 0
GET (0,0)-(319,199), background2(0)

All is ready for the new "MainMenu" sub:

SUB MainMenu

startmloop:
' Default menu position is 1(first from
' the top).
MPos = 1

DO

' If the user pushed up and the key pushed
' last time is released reduce menu
' position by 1. Minimum menu position is 1.
IF MULTIKEY(SC_UP) AND KeyPressed = FALSE THEN 
MPos = MPos - 1
KeyPressed = TRUE 
IF MPos < 1 THEN MPos = 1 
END IF
' If the user pushed down and the key pushed
' last time is released increase menu
' position by 1. Minimum menu position is 1.
IF MULTIKEY(SC_DOWN) AND KeyPressed = FALSE THEN 
MPos = MPos + 1
KeyPressed = TRUE
IF MPos > 4 THEN MPos = 4  
END IF

' If the user pushed enter execute
' the current menu option(flagged
' with MPos).
IF MULTIKEY(SC_ENTER) THEN
SELECT CASE MPos
CASE 1 ' Play Sheep Massacre option
' While ENTER is being hold loop.
WHILE MULTIKEY(SC_ENTER)
SLEEP 2
WEND
' Load initial variables(player's position, etc.).
InitVariables
' Call the main game loop.
MainLoop
' Show the score screen if all sheep are killed.
PrintScore
GOTO startmloop:
CASE 2
' Inactive!
CASE 3
' Inactive!
CASE 4 ' Exit option
END
END SELECT
END IF

' Pastes the menu background.
PUT (0, 0), background2(0), PSET

' Pastes the menu pointer according to MPos. The menu
' pointer is stored on position 18 in the ExtraSprite 
' array.
PUT (88, 75+((MPos-1)*13)), ExtraSprite(18, 0), TRANS

' Key pressing variable won't be restored(key pressing
' unlocked) until the user releases all these keys
' (doesn't hold any of them).
IF MULTIKEY(SC_ENTER) OR MULTIKEY(SC_UP) OR MULTIKEY(SC_DOWN) THEN GOTO skipkeyrestore2:
KeyPressed = FALSE
skipkeyrestore2:

' Standard statements in each loop.
SCREENCOPY
SCREENSYNC 
SLEEP 2    

LOOP

Most of code is explained in the comments. Yet another DO...LOOP. "MPos" is used to flag the active option and "MPos" is changed with UP/DOWN arrow keys. "Play Sheep Massacre" option is under "MPos" value of 1(CASE 1) and "Exit" under "MPos" value of 4(CASE 4). The other two options are inactive(unused). When the user pushes ENTER an option is executed according to "MPos". The final thing I'll do is add mouse control to the menu. This is not NEEDED but I want to show you how to use the GFXlib's mouse routines.

The statement that returns the mouse status is GETMOUSE and you should place it in all the loops where you want to check for the mouse status. Just put this line in the "MainMenu" sub right after 'DO':

GETMOUSE mx, my, , buttons

This line stores mouse cursor x position in "mx", mouse cursor y position in "my" and button status in the "buttons" variable. The last parameter returns 1 for left mouse click and 2 for right mouse click. The third parameter is the mouse wheel counter and it's not used in our menu. Check GFXlib's documentation for more details on this statement.

You should put the following code after the PUT statement that pastes the menu pointer:

' Paste the mouse cursor(image number 17)
PUT (mx, my), ExtraSprite(17, 0), TRANS

' If the mouse cursors is on any of the options
' change the current option to the one
' on which the mouse it.
IF mx > 87 and mx < 250 THEN
IF my > 75 and my < 87 THEN MPos = 1
IF my > 88 and my < 100 THEN MPos = 2
IF my > 101 and my < 113 THEN MPos = 3
IF my > 114 and my < 126 THEN MPos = 4
' If the user has clicked with the left
' mouse button and the cursors is on
' one of the options PAUSE until the
' user releases the click and go to
' the IF clause with SELECT CASE MPos.
IF buttons = 1 AND my > 75 AND my < 126 THEN 
WHILE buttons = 1
GETMOUSE mx, my, , buttons
SLEEP 2
WEND
GOTO optionactivated:
END IF
END IF

The first statement is most important and it draws the mouse cursors using the "mx" and "my" variables. Always import your own custom cursor when developing a mouse controlled game/application. This shows how this is easy to do. The rest of the code simply changes the menu option if the mouse cursor is on any of them. The mouse in our menu is above the keyboard in hierarchy so while the mouse cursor is on any of the options you can't change it with the keyboard. optionactivated: label is placed under 'IF MULTIKEY(SC_ENTER) THEN' so when you click with the mouse it's just like you pushed ENTER. It is recommended that you declare variables returned by GETMOUSE as shared("mx","my" and "buttons").

And that's it. We are really done now with the mini-game! Yippee! But this is not yet the end of the tutorial(aaargh!).

Check the final code of the mini-game here: codever6.txt

I did one final change in the code in the last version. Every 'TO 10' in the sheep FOR loops I changed to 'TO numofsheep', made the "numofsheep" variable shared and set it as 10 in the "InitVariables" sub. I also re-dimensioned the "Sheep" array to hold 100 elements and the "Particle" array to hold 1000 elements(as well as changed all the particle FOR loops to loop to 1000). This change allows us to alter the number of sheep inside the game simply by changing 10 in the line 'numofsheep = 10' to the desired number of the sheep you want in the game. We don't need to go into every sheep FOR loop and change 'TO 10'. Always try to connect as many values in your game with variables since then you can change your game's "characteristics" very easily if needed. Be sure that you don't loop to higher numbers than you dimensioned your arrays with. Like in our mini-game "numofsheep" shouldn't be above 100 as we dimensioned the "Sheep" array to hold 100 elements. Stay in bounds of your arrays! I've re-dimensioned the "Particle" array since in the most extreme situation(100 dead sheep on the screen + the fireball) we would have 701 particle on the screen. Yes, I could dimension the "Particle" array to hold 701 particle but 1000 is a nice round number. It just shouldn't be smaller than the maximum number of particles that might occur in the game. This is a screenshot with 40 sheep(enlarged):

Download the compiled mini-game with the source and all the graphics files here: mini_game.zip

File manipulation in FreeBASIC - A lite tutorial

I feel I should say something about loading and storing data into files since you will most likely use it in any larger project. I don't want to attach this tutorial on the mini-game since it's really unnecessary and I feel this can be explained better in a separate example program.

Stéphane Richard wrote an excellent series about file manipulation(QB Express issues #4, #6 and #8) so if interested in a more deep-through tutorial on this check them out. In this tutorial we'll cover the basics. Simple raw data retrieving and storing from/to plain text files. External data files are a must have with more ambitious projects where you have huge numbers of variables that need to be initiated before every new game. Like NPCs positions on every map/location in the game. Not to mention the very map files that hold the information about tile positions and numbers.

First, let's create a file which will contain these numbers(use Notepad):

50
50
100
100
1
120
120
2
130
155
1
160
150
4

Name it "data.txt".

Now we'll create two objects, "Player" and "NPC" and connect them with a user defined type that will include 3 variables("X", "Y", and "Typ"):

TYPE ObjectType
X    AS INTEGER  ' Will hold the object's X position.
Y    AS INTEGER  ' Will hold the object's Y position.
Typ  AS INTEGER  ' Will flag the object's type.    
END TYPE

DIM SHARED Player AS ObjectType ' A generic player object.
DIM SHARED NPC(4) AS ObjectType ' A generic NPCs array.

Let's say that the first two entries in the file are the player's x and y position and the rest 12 entries hold the NPCs' x and y positions and types(one after another). The way you would load this data into the desired variables is as follows:

' Open data.txt for retrevieng data on
' file handle #1
OPEN "data.txt" FOR INPUT AS #1
INPUT #1, Player.X
INPUT #1, Player.Y
' Loop through 4 NPCs and load
' the variables for each one.
FOR countNPC = 1 TO 4
INPUT #1, NPC(countNPC).X 
INPUT #1, NPC(countNPC).Y 
INPUT #1, NPC(countNPC).Typ
NEXT countNPC
CLOSE #1 ' Close the file handle 
         ' after retrieving data.

When you are LOADING data use "FOR INPUT" when opening a file and then pass the data from the file to variables like it's done in the code above. #1 represents the file handle. Be sure you are not opening one already opened. A good way to avoid this is to close each file after you got the data from it. You can also you the function "FREEFILE" which opens a free file handle.

You save data into files on a very similar way. Instead of "FOR INPUT" you need to use "FOR OUTPUT" and when writting data into a file you need to use "PRINT #filehandle". Like this:

OPEN "data.txt" FOR OUTPUT AS #1
PRINT #1, Player.X
PRINT #1, Player.Y
FOR countNPC = 1 TO 4
PRINT #1, NPC(countNPC).X 
PRINT #1, NPC(countNPC).Y 
PRINT #1, NPC(countNPC).Typ
NEXT countNPC
CLOSE #1

A simple program that illustrates this:

#include "fbgfx.bi" 

TYPE ObjectType
X    AS INTEGER  ' Will hold the object's X position.
Y    AS INTEGER  ' Will hold the object's Y position.
Typ  AS INTEGER  ' Will flag the object's type.    
END TYPE

DIM SHARED Player AS ObjectType ' A generic player object.
DIM SHARED NPC(4) AS ObjectType ' A generic NPCs array.

SCREEN 13, 8, 2, 0

' Open data.txt for retrevieng data on
' file handle #1
OPEN "data.txt" FOR INPUT AS #1
INPUT #1, Player.X
INPUT #1, Player.Y
' Loop through 4 NPCs and load
' the variables for each one.
FOR countNPC = 1 TO 4
INPUT #1, NPC(countNPC).X 
INPUT #1, NPC(countNPC).Y 
INPUT #1, NPC(countNPC).Typ
NEXT countNPC
CLOSE #1 ' Close the file handle 
         ' after retrieving data.

DO

' Print player's x and y position.
LOCATE 1, 1
PRINT "Player's X position: "; Player.X
PRINT "Player's Y position: "; Player.Y

' Print NPC 1 and 2 data.
LOCATE 4, 1
PRINT "NPC 1, X position:" ; NPC(1).X
PRINT "NPC 1, Y position:" ; NPC(1).Y
PRINT "NPC 1, type:" ; NPC(1).Typ
PRINT "NPC 2, X position:" ; NPC(2).X
PRINT "NPC 2, Y position:" ; NPC(2).Y
PRINT "NPC 2, type:" ; NPC(2).Typ

LOCATE 12, 1
PRINT "Use arrow keys to change the player's"
PRINT "position and S to save this new"
PRINT "information into data.txt."
PRINT "Press ESC to end the program."

' Change the player's position according to
' pushed arrow key.
IF MULTIKEY(SC_RIGHT) THEN Player.X = Player.X + 1
IF MULTIKEY(SC_LEFT) THEN Player.X = Player.X - 1
IF MULTIKEY(SC_UP) THEN Player.Y = Player.Y - 1
IF MULTIKEY(SC_DOWN) THEN Player.Y = Player.Y - 1

' If the letter "S" is pushed
' save the new data into
' the same file. Only Player's
' X and Y position can be
' changed.
IF MULTIKEY(SC_S) THEN
WHILE MULTIKEY(SC_S)
SLEEP 2
WEND
OPEN "data.txt" FOR OUTPUT AS #1
PRINT #1, Player.X
PRINT #1, Player.Y
FOR countNPC = 1 TO 4
PRINT #1, NPC(countNPC).X 
PRINT #1, NPC(countNPC).Y 
PRINT #1, NPC(countNPC).Typ
NEXT countNPC
CLOSE #1
END IF

SCREENCOPY
SCREENSYNC
SLEEP 2

LOOP UNTIL MULTIKEY(SC_ESCAPE) ' End loop when ESC is pushed.

END

This program allows you to change the player's x and y position and save this change in "data.txt"(by pushing the letter "S"). If you start the program again you will see that the change is saved. You can't change the NPC data. The NPC array is there just to show you how you can load large amounts of data from files with a FOR loop and store it into arrays. Download this example packed: file_usage.zip

What also wouldn't be bad for you to know is how to convert strings into integers and vice-versa. Something often done when data is being load/stored to files.

To convert an integer into a string use:

YourString$ = STR$(YourInteger)

To convert a string into an integer use:

YourInteger = VAL(YourString$)

Where YourString$ can be "124" or something like that. A string like "dssdsd" would return a 0 when converted into an integer.

Again, this is just the surface of file manipulation. For more information on this like using binary files read Stéphane Richard's tutorials.

A note on compiling

When compiling a graphics application(that's what we are doing) with FreeBASIC you will most likely want to get rid of the console window(that ugly thing behind the program window; you noticed it when running the compiled programs from this tutorial). To get rid of it you need to compile your .bas files with:

fbc yourfile.bas -s gui

In FBIde you set this in the View -> Settings -> FreeBASIC window. The "Compiler command" input box. Just put '-s gui' behind 'filename> '. Omit the apostrophes.

Routines/tools I think you should know about

I will list here few routines/tools that you might find very useful, especially if you are going to stick to using GFXlib.


This is a set of custom font printing routines I wrote some month ago. It allows you to print text in custom fonts in 8 and 16 bit color depth modes. The fonts need to be saved as BMP files in a special format(a grid) so it's very easy to edit them. This package comes with 6 already made fonts of different sizes. The routines are very easy to use and the package comes with documentation as well as with 3 demos. The last time I was online this was the only routine of such type for GFXlib. Highly recommended!


Most likely you will use FMOD sound library(http://www.fmod.org) to play the sound and music in your games. FMOD is easy to use, multi-platform and supports a wide range of music file formats(WAV, MOD, MID, MP3, OGG, ...). Few FMOD-FB tutorials were written but I'm not in the situation where I can look for them(I'm writing this offline). Anyway, many of them might be incompatible with FreeBASIC today because of a change in version 0.15. It's easy to "fix" this incompatibility which is very nicely illustrated in this FMOD example program I wrote. This demo STREAMS a background sound and allows you to play two sound effects at your input. It also allows you to change the master volume. So it includes the basics and most likely all you will use. What I also want to accomplish with this example program is to get people in a habit of STREAMING long music files since they take a lot of memory if stored directly in it. And if you really need to store a music file into memory PLEASE store only one and then switch between them when needed. Don't store all your sound/music files into memory together(hello Syn9!) because that's a disrespect of your user's memory. This package also includes FMOD's official help file(FMOD.chm).


Richard Eric Lope's pixel by pixel scrolling engine ported to FreeBASIC by me in June 2005. It was originally coded in RelLib, a QuickBasic graphics library. Two fixes of the engine were released later so this is the latest version compatible with FreeBASIC ver.0.15 and includes comments why it was not originally compatible. What's specific for this demo is that is loads sprites and tiles(as well as the custom font) from PIXELplus 256's graphic files(known as PUT format). PIXELplus 256 is a sprite/tile editor originally made for QBasic developers in 1995. Very long it was an excellent sprite editor for QBasic developers but today is lacking in many aspects. One single PUT file can't be longer than 64 KB nor it can be managed/saved in 16 bit or higher color depth mode. So all of the flaws of PP256 are therefore the flaws of this scrolling engine. Still, it wouldn't be difficult to port the engine so it would load sprites and tiles from plain BMP images though the pixel perfect collision featured in it would then have to be cut out. I don't currently have the time nor will to do this. The engine is heavily commented so it might be interesting to those who want more after this lesson and don't mind working in 8 bit color depth mode. Also, you will have troubles in finding another FreeBASIC pixel scrolling engine out there, free to use and so well commented. Then again, I might be wrong(I hate being offline).


PIXELplus 256, a sprite/tile editor for QBasic developers but thanks to Richard Eric Lope's PUT routines from the scrolling engine above you can use it with 8 bit color depth FreeBASIC projects. This is a DOS program but runs very sexy and smooth on my PC(with Windows XP installed).


Excellent program for editing audio files. I found it very handy when editing sound effects and converting them to desired formats. A must tool for every game designer. Freeware.


Once more I'm recommending this IDE. I had the opportunity to try out two other FreeBASIC IDEs and they didn't appeal to me like FBIde did. Maybe it's a thing of habit. What's great is that FBIde since the version 0.4.5 includes FreeBASIC Wiki, a wonderful FreeBASIC encyclopedia. And if I'm not mistaken it's still growing.

Final words

Dear God, I completed the tutorial! I though this would never happen. :P

76 KB of pure text. I hope there are people out there who actually need this and will find it useful. Err...I also hope nobody won't mind if I skip "what we learned" section in this edition. I just covered too much and a lot of generic stuff.

I doubt another lesson will ever be written because I feel I said all that needed to be said in the first two lessons. I also don't have any more free time. At least the amount one tutorial of this kind consumes. I really need to hit the books and get heavy on my college project.

But if you are really curious in the next lesson(s) I planned to learn you few more sophisticated methods of using external files. The idea was to reproduce the method I used in Legacy Of Noname General(a project of mine; still incomplete) to show you how you can create point and click environments(adventure game) using data from external files. Nothing new. Just this knowledge enriched. I also planned to code another simple game entitled Choper Attack which wouldn't introduce anything new and would only serve as a practice.

With hopes I opened that "magical door" at least to one person, stay among the living!


Download a copy of this tutorial: How_To_Program_A_Game_2.zip or how_to_program_a_game_2.html


Final Word

...and they all lived happily ever after. The end.

There. That seems like a fitting end to an issue of QB Express.

No? You prefer the normal ending? Awwww, man. Fine. Here you go (but just for old time's sake):

Until next time...END.

P.S.: The deadline for submissions to Issue #21 is: June 15th. At that point, I hope to move the magazine back to its MONTHLY publication period, so it's very important that you submit enough content so that I'll be able to do a full issue. As always, send your stuff to pberg1@gmail.com.

-Pete


Copyright © Pete Berg and contributors, 2006. All rights reserverd.
This design is based loosely on St.ndard Bea.er by Altherac.

QB Top 50 - The best QBasic and QuickBasic Sites