March 10th, 2001
Welcome to issue #2 of the QB Chronicles!
Well I think the first issue was well recieved in the QB world. We got a lot of readers in the first month, and that, obviously, is a good thing. Special thanks to Jordan of Future Software for putting up the news about the first issue of the mag on his site and on QQN which helped alot (I got about 100 unique visitors form QQN alone).
Well this month we've got the second part to the XMS article, we've got an article I wrote on the basics of using the palette, which goes over such things as fading and changing colour's for your game's purposes. As well we've got a new monthly feature on rants. This month's rant gives possible reasons why people never finish their projects in QB. Also I've continued the RPG article, this month we delve more into NPC's and how to make 'em move. Check it out!
And as you've probably noticed (if not you will), the look of the mag has been changed! The first issue was sort of a simple layout and now I hope you will grow to like this design. Anyways hope you enjoy and please be sure to tell me what you think!
-Fling-master, editor of the QB Chronicles
This is obviously a new section of the mag where I'll put e-mails in general that I receive regarding the QB Chronicles. If you send me an e-mail (which is not a news submittion, or an e-mail with an article attached or something else that shouldn't be printed here) then I'll put your e-mail here with a comment or response. Here's one e-mail I recieved about issue 1:
I want to congratulate you on starting a cool new QB magazine! The articles are well-written and shows advanced knowledge of QB and design techniques.
I liked how you covered both medium and advanced stuff in your articles. That's the best way to get a large QB audience. I like the explanation then short code segment writing style, which keeps the reader involved in the program exploration. I also like the question and answer style, in which you telepathically anticipated what the reader would want to know next. Also, the formatting is simple and elegant, and very readable.
Here are some minor errors I've caught in the first issue.
1) Microsoft FrontPage 4.0 forgot to update the Letter from the Editor internal link from file:///C:/GERED/site/qbchronicles/issue1.html#letter to #letter.
2) You don't need to do z=INT(x\y) when x, y, and z are integers. All you need is z=x\y, which is faster and shorter.
I wish you luck in your next issue-- I'll try hard to write a tutorial article as good as yours.
Thanks for the feedback! I'm
glad you liked issue #1. I worked hard on it and wasn't sure how the QB
community would take another new magazine. About the writing style I used: I
like doing sort of a Q&A style article because it addresses questions the
readers might have (hopefully). I also like showing code segments and not just
one line of code. It sort of gives the reader an idea of how to incorporate the
technique or whatever into their programs.
And thanks for picking up the error's! The first one is how I have it set up at home and, like you said, I guess Frontpage forgot to update the link. And I have no idea what I was thinking when I used INT. Thanks for picking both up! Hope you enjoy this issue!!
These are the QB Chronicles editor's Top 10 downloads. These are superb programs/games which any QB'er should have. In this issue and future issues, you'll be able to vote for your favourite QB program. So submit your opinion below!
Submit your vote!
|Site URL:||http://qbtalk.zext.net (QB Talk)||N/A|
|Graphics:||There aren't many graphics, and the ones which're there aren't that good....||3/10|
|Content:||Rants, rambles, comics and mini games! I like coming to this site just to read something interesting. The webmaster has written a bunch of rants on different subjects. Check them all out (if you have time to read 'em all).||19/20|
|Layout:||The layout isn't to special. Just a few tables with text in 'em. Although the site is easy to navigate so that puts it up.||7/10|
|Downloads:||Not the main focus of the site but the download which are there are interesting to say the least.||4/5|
And finally here's part two of the XMS tutorial!!! I say finally because I originally submitted the first article to the QB Times, then they stopped making new issues. =( Anyways it's finally here and now we'll finish this small series off.
Last issue we covered the bare essentials of XMS. From those routines presented you can make other routines to do just about anything with XMS. One thing I've done with XMS is make a routine to read a map which I've saved in it. All I have to pass to the routine is the x and y position I want to read and the function returns the tile number at that offset. Another thing to use it for is to store graphics. No, not off screen buffers but the PUT/GET compatible arrays. This alone will save you loads of memory depending on your program. There are lots of uses for XMS, I'll leave you to discover your own. So lets get started.
What I didn't show you how to do last month was to use above 64MB of memory. Well now I will show you how to do that in a few of the functions from last month. To do this we need to use the Super Extended Memory support functions. These will make use of 32-bit registers. The funtions we'll be changing are XMSInfo, XMSAlloc, and XMSReAlloc, from last month. You might have thought that XMSPut and XMSGet needed to be changed as well, but no. So the best place to start is with XMSInfo. We'll change it to return long-integer values about the free memory.
XMSInfo PROC freemem:DWORD, totalmem:DWORD mov ah,88h ;Use function 88h call [XMSControl] ;Call the API mov bx,totalmem ;Put the value in EDX in totalmem. mov [bx],edx mov bx,freemem ;Put the value of EAX in freemem mov [bx],eax ret ENDP XMSInfo
This will return values of up to 4GB in size (all in KB). What we did was use EAX, and EDX and change function 08h to 88h.
Now lets change XMSAllocate routine. This is also really simple:
XMSAlloc PROC kb:DWORD mov ah,89h ;Use function 89h mov edx,kb ;Move kb into EDX. call [XMSControl] ;Call the API cmp ax,0001h ;Is AX = 0001h? If it is then it worked! jne AllocErr ;If it isn't then . . . too bad! =P mov ax,dx ;Move the handle into AX so its returned. ret AllocErr: ;Since we can't get a handle if it didn't work we don't ret ;want DX to get into AX. ENDP XMSAlloc
What we did there was change 09h to 89h and change DX to EDX since we want a 32-bit value for our handle size. Really for all the functions we're changing only the size of the registers and the function numbers.
Now lets change the XMSReAllocate function around:
XMSReAlloc proc handle:WORD, kb:DWORD mov ah,8Fh ;Use subfunction 8Fh mov bx,handle ;Get the handle to deallocate into DX. mov dx,[bx] mov ebx,kb ;Get the new amount to resize the handle to into EBX. call [XMSControl] ;Call the API. mov bx,handle ;Return the handle to QB. mov [bx],ax endp XMSReAlloc
And there we go! That's it. Now you can allocate and use up to 4GB of memory. Now to use this lib you should put all the functions in one .ASM file and assemble it using an assembler (I used TASM to do the above functions). Then you should link the .OBJ file into a library. I'm not going to explain in detail how to do this, there are other utilities, and tutorials to do that. The include file you need should look something like this:
DEFINT A-Z '$DYNAMIC DECLARE FUNCTION XMSInit% () DECLARE SUB XMSInfo (free&, total&) DECLARE FUNCTION XMSAlloc% (BYVAL kb&) DECLARE SUB XMSDeAlloc (handle%) DECLARE SUB XMSReAlloc (handle%, BYVAL kb&) DECLARE FUNCTION Move2XMS% (BYVAL handle%, BYVAL segm%, BYVAL offs%, BYVAL bytes&, BYVAL XMSoffs&) DECLARE FUNCTION Move2Var% (BYVAL handle%, BYVAL segm%, BYVAL offs%, BYVAL bytes&, BYVAL XMSoffs&)
And there you go! XMS fo QB!! If you still don't understand this then you might want to contact me then I can (hopefully) explain it to you. If you find any mistakes for this then also please contact me. I just hate having error's in my tutorials. =) Hope you enjoyed!
This article was written by: Fling-master - http://www.qbrpgs.com
Welcome to part two of my series! Last issue we went over how to create the basic engine, which of course, included such things as movement, collision detectiom, and drawing the map. This time we'll delve deeper into the world of NPCs. We'll create the beginnings of an object system, that will allow us to incorporate enemies with very small modification. And it will allow us to make the player shoot with also very small modification. So before I get too ahead of myself, let's begin!
Before we start coding the object handler to move our NPCs we need to plan out the data structure to hold the required information. What will we need to include in this? Well, you should definitly include things like the NPCs x and y position, the direction its moving, and how much distance it has left to move before it should start moving again. Another thing which'll come in handy later is whether it's active or not. This allows us to 'kill' NPCs. These are just some of the things to include. You might even go so far as to track separate variables to see what items the NPC has so you could trade with them. Something I don't like doing is keeping the text the NPC is going to say in the data structure. This more limits the scripting capabilities of your RPG. But of course we'll get into that later.
So here's out basic data structure:
TYPE NPCType 'Holds NPC data x AS INTEGER 'X coord y AS INTEGER 'Y coord Dir AS INTEGER 'The direction Moving AS INTEGER 'If its moving and the amount left Active AS INTEGER 'Is it active? END TYPE
DIM SHARED NPC(50) AS NPCType
I think that's pretty self-explanatory. Add that into the engine we made last month after the Engine Type declaration.
Now then, we need to write a sub to update the NPCs since we don't want 'em to just stand there! We want them to move, run, etc. We're going to implement a random movement system which will check for collision with walls and other NPCs. This is probably the simplest form of handling NPCs. A more advanced one would maybe make them able to activate scripts or make some run around in circles, etc. Here's the subroutine:
SUB UpdateNPCs FOR i = 0 TO Engine.MaxNPCs 'Update all the NPCs IF NPC(i).Moving = 0 THEN 'Is it moving? IF RND * 50 = 5 THEN 'Find out if it "wants" to move NPC(i).Moving = 16 'Set Moving to 16 (one tile width) ELSE GOTO StartIt 'Goto the next NPC END IF NPC(i).Dir = RND * 4 'Pick a direction SELECT CASE NPC(i).Dir CASE North 'Moving north 'Do collision. We don't want 'em moving into walls and such =) tile = map(NPC(i).x \ 16, (NPC(i).y - 1) \ 16).Collision tile2 = map((NPC(i).x + 15) \ 16), (NPC(i).y - 1) \ 16).Collision IF tile <> 2 AND tile2 <> 2 THEN 'Is it passible? ELSE NPC(i).Moving = 0 'If the tile is unwalkable the NPC stops END IF FOR sw = 0 TO Engine.MaxNPCs 'We also don't want 'em walking onto NPCs IF NPC(i).x \ 16 = NPC(sw).x \ 16 AND (NPC(i).y \ 16) - 1 = NPC(sw).y \ 16 THEN NPC(i).Moving = 0 'If there's a NPC stop. END IF NEXT sw CASE South 'Moving South 'Do collision. We don't want 'em moving into walls and such =) tile = map(NPC(i).x \ 16, (NPC(i).y + 16) \ 16).Collision tile2 = map((NPC(i).x + 15) \ 16, (NPC(i).y + 16) \ 16).Collision IF tile <> 2 AND tile2 <> 2 THEN 'Is it passible? ELSE NPC(i).Moving = 0 'If the tile is unwalkable the NPC stops END IF FOR sw = 0 TO Engine.MaxNPCs 'We also don't want 'em walking onto NPCs IF NPC(i).x \ 16 = NPC(sw).x \ 16 AND (NPC(i).y \ 16) + 1 = NPC(sw).y \ 16 THEN NPC(i).Moving = 0 'If there's a NPC stop. END IF NEXT sw CASE East 'Moving East 'Do collision. We don't want 'em moving into walls and such =) tile = map((NPC(i).x + 16) \ 16, NPC(i).y \ 16).Collision tile2 = map((NPC(i).x + 16) \ 16, (NPC(i).y + 15) \ 16).Collision IF tile <> 2 AND tile2 <> 2 THEN 'Is it passible? ELSE NPC(i).Moving = 0 'If the tile is unwalkable the NPC stops END IF FOR sw = 0 TO Engine.MaxNPCs 'We also don't want 'em walking onto NPCs IF (NPC(i).x \ 16) + 1 = NPC(sw).x \ 16 AND NPC(i).y \ 16 = NPC(sw).y \ 16 THEN NPC(i).Moving = 0 'If there's a NPC stop. END IF NEXT sw CASE West 'Moving West 'Do collision. We don't want 'em moving into walls and such =) tile = map((NPC(i).x - 1) \ 16, NPC(i).y \ 16).Collision tile2 = map((NPC(i).x - 1) \ 16, (NPC(i).y + 15) \ 16).Collision IF tile <> 2 AND tile2 <> 2 THEN 'Is it passible? ELSE NPC(i).Moving = 0 'If the tile is unwalkable the NPC stops END IF FOR sw = 0 TO Engine.MaxNPCs 'We also don't want 'em walking onto NPCs IF (NPC(i).x \ 16) - 1 = NPC(sw).x \ 16 AND NPC(i).y \ 16 = NPC(sw).y \ 16 THEN NPC(i).Moving = 0 'If there's a NPC stop. END IF NEXT sw END SELECT END IF 'If the NPC is moving then update the current position its at. IF NPC(i).Moving > 0 THEN NPC(i).Moving = NPC(i).Moving - 1 SELECT CASE NPC(i).Dir CASE North NPC(i).y = NPC(i).y - 1 CASE South NPC(i).y = NPC(i).y + 1 CASE East NPC(i).x = NPC(i).x + 1 CASE West NPC(i).x = NPC(i).x - 1 END SELECT END IF StartIt: 'This is where we go to goto the next NPC. NEXT i END SUB
Hopefully you understand that! =) What it does is check if the current NPC is moving, if not then find out if it "wants" to move by picking a random number. If it does "want" to then we pick a random direction, check for collision and set it on its way. If the NPC was already moving then we simply find out which way it was heading then we update the x,y position accordingly. Simple? Yes! (Well I hope 'Yes!')
So now we've got out NPC handler, and that's fine, BUT how do we display them? Well that is actually quite simple! The routine to draw the NPC's is really small and the bonus here is that when we add other objects like enemies and items, etc. this routine will draw them too! Excellent! So here's the code:
SUB DrawNPCs FOR i = 0 TO Engine.MaxNPCs IF NPC(i).Active = False THEN GOTO NextNPC 'Is the NPC Active? Xpos = NPC(i).x - CameraX 'Get the coords to draw the NPC Ypos = NPC(i).y - CameraY 'at on the screen NPCpic = (NPC(i).Dir * 2) - 1 'Get the frame the NPC is in Put VARSEG(buffer(0)), Xpos, Ypos, PlayerGFX(0, NPCpic) 'Draw it NextNPC: 'Process the next NPC NEXT i Xpos = Engine.x - CameraX 'Now get the player's coords Ypos = Engine.y - CameraY 'to draw PlayerPic = ((Engine.Direction * 2) - 1) 'Get frame Put VARSEG(buffer(0)), Xpos, Ypos, PlayerGFX(0, PlayerPic) 'Draw it END SUB
There we go! That will also draw the player onscreen too so you can get rid of the lines which draw the player in the DrawMap sub from last issue and replace it with a call to this routine. Also note that the player is always drawn on top of everything (which will change when we start paying more attention to layers). This is so that you don't get him being below anything and can always see him. What this routine really needs is animation but I forgot the formula to do that, I'll show you it next issue though ;).
Well that just about covers it. But one last thing is probably on your mind: How do I initialize NPCs so they appear on the map? Well this is simple but I'll still show you how to do it:
NPC(i).x = <where-ever-you-want> NPC(i).y = <where-ever-you-want> NPC(i).Dir = South NPC(i).Active = True 'This is something I forgot to give you last issue. It initializes some of the Engine's required variables. Engine.x = <where-ever-you-want> 'Our starting position Engine.y = <where-ever-you-want> Engine.Direction = South 'We'll face south Engine.MaxNPCs = 10 'Maximum NPCs is 5 skip = 1 'Frame skip
The top four lines will initialize one NPC (you have to substitute your NPCs starting co-ordinates). It also sets it to face south and to be active. Also as you can see we've got 5 extra lines which deal with the Engine data structure. Well these setup some variables required by the engine. The 'skip=1' down at the bottom is the frame skip. You can set it so that when you move the players x,y position decrease/increases by skip. This will later allow us to make the player run if you have a multiple keypress handler (all you'd have to do is make skip=2 or something when the player holds the run key down). A word of warning: don't set skip to an odd number. If you do you will eventually skip tiles and mess the collision detection up. Always make it either 2,4,8 or 16.
And that cover's everything I wanted to say about NPCs for this issue. Next month we'll go into scripting because I'm not quite ready for explaining my battle system yet. We'll also give those NPCs something to say! See you next month!
This article was written by: Fling-master - http://www.qbrpgs.com
It is a well known fact that a large percentage of QB projects flop. In other words, most QB projects are never completed before the creator or creators of the project abandon this project or worse, quit QB programming altogether. I know of many good examples, the most recent major abandonment being the "QPower" project by Nekrophidus. I have abandoned many of my programs in the past, most notable the text side-scrolling platform game called The Heart Machine. If you have no idea what I am referring to, check out this engine at the programs I have done so far at my website QBTalk. I'm hoping someone will continue with this, but let us not digress any further. The topic for today is: why doesn't everyone finish their QB projects, even those which people have spent many hours planning every single detail?
Let me start on my own experience. The main reason for abandoning My Heart Machine, which looked impressive enough (quote: "CS" on the Future Software board - "It's the coolest thing I've ever seen!") as a platform engine is the horrors of stale code. I repeat this point: the horrors of stale code. Code you've written when you're half drunk. Code you've written on a sudden flash of inspiration. Code you've never dreamt that you have the capability to write. Code that will sting, code that will stun. Code that makes you forget what it means 10 minutes after creating it. Code that makes you say, "How did I do that?". Code that makes you say, "What exactly does it mean?" even with the comments on it. Yup, I think you've got it. You write some brilliant piece of code, and when you realize some days later that you have to change some portions of this code to put in something new, you find out that, in spite of your comments (not that there were many comments in The Heart Machine anyway), you forgot what your code means. To understanding chunks and chucks of stale code is a horror. The horrification level can only be matched by the "power-bugs" mentioned below. Usually, what I would do is to persevere, but the code for The Heart Machine is really too lethal to be touched by me. I wish any more experienced programmer who fiddles with it good luck (then again, experienced programmers would be able to write something better than that with the boost of ASM)
The next most important reason why I gave up The Heart Machine is the level of tedious programming I did not expect. All was well when I programmed the side scrolling effect, implemented multiples walls and floors, water and clouds, and even when implemented 3 different kinds of shooting (I thought I would have a problem here). The only problem remains: what about monsters to shoot at? I wrote down an extensive planning process, about the coordinates of the monsters, how the monsters will behave (monster AI), whether monster will shoot or not, and what they look like on the screen, and whether they will slow the whole game down drastically. Plans after plans of implementing monsters are drawn and scrapped, and after planning this for one whole week without any result in getting rid of the obvious speed problems, and I found out that nothing would be achieved even if I continue this way. Furthermore, there were bosses to think about. All these pile together and they require extremely long periods of programming and tweaking. I cannot imagine the debugging process of this. That's why I gave up The Heart Machine. Very large projects should not be done by one or two people alone, as they are most likely to fall prey on the tedious programming obstacle.
That was two reasons using myself as a case study. There are quite a few more rather major obstacles to completing a project. If you trip upon these obstacles, you may not be able to finish your QB project. One of the most serious problem is the "power-bugs" problem, which can also be called the "brick-wall syndrome".
"Power bugs" refer to those bugs that just wouldn't go away no matter how you try to extract the bug. Examining the code in every corner would not work; neither does stepping through the program and watching all your variables at every instant. When you step to the line where it errors, you just cannot find out why the program screw up. The worse case of "power bugs" is the case where you cannot even run your program. "Out of string space", "Out of data space", "Out of stack space" all these are potentially mean "power bugs" that occur when you start. Worth mentioning is the "Do without loop" bugs, as they could mean that your control statements (IF and SELECT CASE) are not closed. Other than these cases, "Subscript out of range" is a very irritating "power bug", especially you have some complex formulae for the subscripts of your array. In that case, you have to watch all your variables carefully, and see which are the ones that are getting the wrong manipulation. This problem is also called the "brick-wall syndrome" because it is said that since you cannot continue programming the project until after you vanquish the bug, you get your face smashed against a brick wall, and there is no way to continue. Power bugs are horrific. Take note of this.
Sometimes though, it is not the case of power bugs. For some programmers, especially newbies, they will find that the biggest obstacle to completing programs is the lack of programming capability and experience. This is another major problem that arrives especially you you did not do adequate planning when you begin your programs. Most less experienced programmers nose- dive into the programming portion of the project without even planning how your code should be structured, what tools and algorithms you need, and what data you need to create. This is a serious error. At the risk of sounding like an old nag, I have to say planning of a program, even if it is just a rough sketch, is important. At most, it acts as a valuable guide to programming and can certainly reduce the debugging time by reducing the possibility of "power bugs" and other less serious one. At the very least, it helps you gain confidence that you know roughly how to do the program or let you realize that you don't know enough to write such a program and let you bail out before actually starting on the programming. Less experienced programmers generally have less experience with debugging, so, when met with a bug that appears to be a "power bug" to them, they will bail out, thus turning the program into a flop. Therefore, the lack of experience and programming capability is a major hindrance of completing a QB project.
We cannot forget the fact that QB programmers have a social life too (well, at least most of them do...). Due to some additional commitments in their school / work life, the expanding of the social circle as well as maybe some family matters, some QB programmers find that it is impossible to juggle social life and programming projects together. Thus, they choose to give up the less important one: programming projects. Some hardcore programmers think that their social life is less important and consequently, gave that up. These are what we can truly call the "geeks". Anyway, QB programmers may not be able to finish their project because of this. They are not really to be blamed.
All in all, many QB programmers don't finish their QB projects. It's a fact, and we should live with it. Maybe one day, you will look back at some of your projects and decide to continue it. So whatever you do, don't ever delete the source files of your abandoned projects away. Save them in a backup disk, put them somewhere else, whatever you do, don't just trash it. You might want to continue.
This article was written by: Singsong - http://qbtalk.zext.net
Ahh yes the palette. Your best friend when making a game. Well, it can be anyway. The palette in SCREEN 13 can be quite important, mostly because the default one is really quite crap unless you're adventurous. So your first order of business should be to change it around to what you want.
Most people find that when making a palette it helps to use gradients. A gradient is of course a series of colours which go from either a dark shade to a light or vice-versa. Anyway, how does one change the palette? Well I'm here to answer that question and some. =)
The first thing we'll cover is changing the RGB values for colours. RGB stands for red, green, blue. If you don't already know every colour on your screen is made up of different values of red green and blue. By mixing different amounts of these three colours you can get basically any colour you want. Now I'm not going to go over "rules" for palette creation, that's for another article. So anyway, we can change the value by first OUTing to port 3C8h the colour we want to change. Then we OUT to 3C9h the red, green, and blue values of the new colour. An example:
SCREEN 13 'We'll use mode 13h for this COLOR 1 'Colour blue for the text OUT &H3C8, 0 'Let's change the background colour OUT &H3C9, 63 'Change the red value OUT &H3C9, 63 '...and the green OUT &H3C9, 63 '...and the blue PRINT "Colour 0 is now white!"
In case you didn't read the last line, this example changes colour zero to white. Colour zero is the background colour so you'll notice something different. =) Now, white is made up of 63 for R, G and B. Black is 0 for R, G and B. Bright green would be R=0, G=63, and B=0. I think now you understand.
OK so what if you wanted to get the RGB values of a certain colour? Just what do you do? Well first you OUT the colour whoes values you want to read to port 3C7h. Then you INP from port 3C9h the red, green, then blue values. Simple? Yes I thought so too. Here's an example:
SCREEN 13 OUT &H3C7, 100 'Get the colours for colour 100 r = INP(&H3C9) 'Get the red value g = INP(&H3C9) '... and the green b = INP(&H3C9) '... and the blue PRINT "Red:", r 'Now show the values of that colour PRINT "Green:", g PRINT "Blue:", b
That will display, on screen, the RGB values of colour 100. So what can we do with this knowledge? Well we can do interesting stuff like fades. Or we could make a fully featured palette editor. I think the best example is something which modifies the palette in some way. So lets make a fading routine. This will work in SCREEN 13. Here's the commented code:
change = 50 'We're gonna darken the palette by 50 shades FOR c = 0 TO 255 'Go thru all the colours OUT &H3C7, c r = INP(&H3C9) 'Get the red value g = INP(&H3C9) 'green b = INP(&H3C9) 'blue FOR i = 1 TO change 'Loop through as many times as shades we want to darken IF r > 0 THEN r = r - 1 'If any of the RGB values is below 0 we don't IF g > 0 THEN g = g - 1 'want to change 'em. IF b > 0 THEN b = b - 1 OUT &H3C8, c 'Now we want to make the changes to the palette OUT &H3C9, r OUT &H3C9, g OUT &H3C9, b NEXT NEXT 'Goto the next colour in the palette.
This doesn't fade the screen smoothly. It just does an 'instant fade' sorta thing. To make it more smooth you should do some timing in one of the loops (not sure which one.... it's late, give me some credit =). You could also make this routine work with textmode. All you gotta do is change the FOR c = 0 TO 255 to FOR c = 0 TO 15 (for 16-colour modes).
Another neat thing you can do is translucencies. When used properly in games, etc, you can get many "Ooooooh"'s and "Aaaaahhh"'s from the users =). We aren't going do something like "alpha-blending". We are going do something which is both memory efficient and speedy. Our translucent pixel routine will make use of an array with 256 integers in it. Here's the code:
DEFINT A-Z DIM SHARED TransData(256) 'Our translucency data SCREEN 13 'Use mode 13h 'Here we're gonna initialize the translucent data. You only need to do this 'once at the starting of your program. FOR i = 0 TO 255 'Go thru all the colours done = 0 'A tracker variable to see if we've 'done something this time thru the loop OUT &H3C7, i 'Get the RGB values for the current r = INP(&H3C9) 'colour g = INP(&H3C9) b = INP(&H3C9) 'Now we want to find the highest of the RGB values and add 'em to the array 'At the end of the loop our translucency data array will be filled with 'numbers from 0-15. IF r >= b AND r >= g THEN 'Is red highest? TransData(i) = r / 4 done = 1 END IF IF b >= g AND done <> 1 THEN 'Is blue highest? TransData(i) = b / 4 done = 1 END IF IF done <> 1 THEN TransData(i) = g / 4 'Is green highest? NEXT
'Here "colr" is the colour of the pixel which we're plotting the translucent 'pixel over. Then what we want to do is find out where the gradient of the 'shade we want to put starts and use that colour. DEF SEG = &HA000 colr = POINT(x, y) POKE y * 320& + x, TransData(colr) + start_of_desired_shade DEF SEG
The above routine would be much speedier in asm. That is the simplest form of translucency, and is also the fastest that I know of. Something like alpha blending works best in 16-bit and above colour modes. You technically can use alpha blending in 256 colour modes but its not worth it especially when you can do the above.
Anyway thats my article on the palette in QB. Hope you enjoyed it. If you don't understand something then please e-mail me. If you see an error e-mail me too!
This article was written by: Fling-master - http://www.qbrpgs.com
Well thanks for reading this issue! I hope you enjoyed this collection of tutorials, news, and rants. The next issue is due to be out around April 7th. In it we'll have part 3 of the RPG Creation 101 series. We'll also most likely have an article on using EMS. And we'll have another rant for your reading pleasure.
Until next time!
|All site content is © Copyright 2001, HyperRealistic Games. This excludes content submitted by other people.|