Introduction:
One of the topics I've not covered yet is page flipping and page blitting. Although if you've followed my previous articles you've certainly seen it in action, I haven't really delved into what it's all about. So I'll touch on that in here.
Also, seeing that you'll want a way to get your users to move images and such around the screen, I figured a talking about input devices would be in order. This will cover the fundamentals on keyboard, mouse, and joystick usage. They are super simple to use, so this won't be a massive article.
It's recommended that you download the source code so you can see all this in action.
Screen Blit Animation
This form of animation actually allows you to write to the screen's buffer real-time. This used to be the way that games were made, especially at 320x200 resolutions, but it's not as common today. The idea is that the monitor is refreshed n number of times per second. If we catch the monitor half-way through it's refresh phase, we'll see flickering in our images. This looks bad.
BB provides a function called VWait which basically tells your program not to do anything until the Vertical Sync is on. In other words, when the monitor has completed refreshing the screen and is going back up top to start it's refresh again, BB will know this and will tell your program to quickly draw everything.
You can find the full source for Blit animation inside the blitimage.bb file, but here's the main While loop to show you how it's used:
; loop until the player hits the ESC key While Not KeyHit(1) ; check to see if the arrow keys are pressed CheckKeys() ; Tell BB to wait for the Verticle Retrace VWait ; clear the Screen Cls ; draw the current Ship Frame on the center of the Screen DrawImage(imgShipFrames(iCurrentFrame),iShipX,iShipY) Wend ; end the program, return control to Windows End |
Page Flip Animation
Page flipping is utilized most often in today's games because it's a way to ensure you're not going to get flicker. The concept is to have a piece of memory set aside (preferably video memory, for speed reasons) that is laid out exactly like your primary video memory (or screen buffer). So, you'd have a primary (front) buffer and a secondary (back) buffer. The back buffer, again, is simply a duplicate layout of the primary buffer. The primary buffer is also known as the front buffer.
Now, the idea is that while your front buffer is displayed to the user you are busy drawing on the back buffer. This way you are not drawing anything to the main screen while the user watches. When you have completed your drawing you simply Flip the two pages. So, now your front becomes your back buffer and your back buffer becomes your front. Since this simply tells the video card to point to a new place in video memory when doing it's refresh, it's instant. Plus I'm sure that BB (or more likely, DirectX) makes sure the Verticle Retrace is accounted for when doing the Flip.
There are three functions that you'll need to use in order to do page flip animation. They are the SetBuffer, BackBuffer, and the Flip commands. The SettBuffer command tells BB where to draw. BackBuffer returns a pointer to the back buffer we discussed above. The Flip command tells BB that we're ready to swap our front and back buffers.
You can find the full source for Page Flip animation inside the flipimage.bb file, but here's the set up code and the main While loop to show you how it's used:
Const iScreenWidth=800 ;what's our screen width? Const iScreenHeight=600 ;what's our screen height? ; Initialize BB's Graphics using our constants Graphics iScreenWidth, iScreenHeight ; Set up our primary drawing surface to be the BackBuffer ; this is to allow for page-flip animation SetBuffer BackBuffer() ; loop until the player hits the ESC key While Not KeyHit(1) ; check to see if any keys were hit CheckKeys() ; clear the BackBuffer Cls ; draw the current Ship Frame on the center of the BackBuffer DrawImage(imgShipFrames(iCurrentFrame),iShipX,iShipY) ; Flip the BackBuffer to the Display Flip Wend ; end the program, return control to Windows End |
Using the Keyboard
When moving a ship around, firing, etc. you'll want to use a keyboard routine that keeps track of when a key is held down. While you can certainly use the KeyHit command for checking on one-time hit keys such as ESC, you'll need something a little more robust for real-time stuff.
This is where the KeyDown function comes in. All this function does is return a true or false response when asked if a particular key is being held down. In order for you to send it a particular key to check, you'll need to know the scancode. This is a code that the computer recognizes the key by. Generally what I do is find the code (using BB's help area, under "Keyboard Scancodes") and make a constant with a recognizable name. Like this:
; Setup Keyboard Constants (Arrows, KeyPad Arrows) Const LeftArrow=203, RightArrow=205 Const LeftKPArrow=75, RightKPArrow=77 |
Now I know that all I have to do is remember "RightArrow", not 205. Makes it easier to read code that way, don't ya think?
The following code is a snippet from the kbinp.bb file. It's a function that I called CheckKeys() and all it does is checks to see if the left or right arrow is being held down and then spins the ship accordingly:
Function CheckKeys() If KeyDown(LeftArrow) Or KeyDown(LeftKPArrow) Then ; change the current frame (spin it to the left) iCurrentFrame = iCurrentFrame - 1 ; if the current frame counter is less than 0 ; reset it to the number of rotations - 1 If iCurrentFrame < 0 iCurrentFrame = iNumRotations - 1 EndIf EndIf If KeyDown(RightArrow) Or KeyDown(RightKPArrow) Then ; change the current frame (spin it to the right) iCurrentFrame = iCurrentFrame + 1 ; if the current frame counter goes past our number of ; allowable rotations, reset it to 0 If iCurrentFrame > iNumRotations - 1 iCurrentFrame = 0 EndIf EndIf End Function |
Using the Mouse
The next device I'll touch on is the mouse. Since the mouse has waaaaaaay fewer codes to worry about, it's a little easier to check on. However, you may still need a little trickery to get things done.
Let's say that we wanted to duplicate our keyboard routine using the mouse. If the mouse is being run to the left, spin the ship left. If to the right, spin it right. This sounds like a simple little thing to do, and it is if you know a tiny trick.
First let's look at the problem. If you check the mouse coordinates using MouseX and MouseY you'll find that they will be locked to the screen resolution. This is cool if you are going to button clicks and such on a screen. But since we want to spin the ship left as the mouse moves left, we'll need to see if the current mouse position is different from the previous check. Since you'll eventually get a MouseX postiion of 0, you'll find after a while that the ship will stop spinning.
To solve this we use the MouseMove function (thanks to "shockman" on the BB messageboards for getting me this function name!) to re-center our mouse after each check. This will ensure that we will always either be equal to, greater than, or less than our last check.
The following code is a snippet from the mouseinp.bb file. It's a function that I called CheckMouse() and all it does is checks to see if the mouse is moving left or right and spins the ship accordingly. Note that the section before Function CheckMouse() is really located at the top of the program, it's here for reference only:
; center the mouse on the screen MoveMouse iScreenWidth/2, iScreenHeight/2 ;Save our mouse position for X Global iCurrentMouseX=MouseX() Function CheckMouse() If MouseX() < iCurrentMouseX Then ; change the current frame (spin it to the left) iCurrentFrame = iCurrentFrame - 1 ; if the current frame counter is less than 0 ; reset it to the number of rotations - 1 If iCurrentFrame < 0 iCurrentFrame = iNumRotations - 1 EndIf EndIf If MouseX() > iCurrentMouseX Then ; change the current frame (spin it to the right) iCurrentFrame = iCurrentFrame + 1 ; if the current frame counter goes past our number of ; allowable rotations, reset it to 0 If iCurrentFrame > iNumRotations - 1 iCurrentFrame = 0 EndIf EndIf ; reset the mouse to be at the center of the screen MoveMouse iScreenWidth/2, iScreenHeight/2 ; reset iCurrentMouseX to be at the center of the screen iCurrentMouseX = MouseX() End Function |
Using the Joystick
The final input device I'll talk about is the Joystick. This is probably the easiest of all since it has a function that pretty much does what we want already. This function, JoyXDir, tells us if the X direction of the Joystick is -1 (left), 0 (centered), or 1 (right). That's all we need to do this little diddy. Now you can commands that will allow you to see how far you are pushing the stick in a direction, but for the scope of this tutorial JoyXDir will suffice.
There's really not much to explain with this piece of code. I'm simply checking to see if the stick is being push left or right and spinning the ship accordingly. This is a snippet from the joyinp.bb file.
Function CheckJoystick() ; call the JoyXDir() function to see if ; the stick is being pushed left If JoyXDir() < 0 Then ; change the current frame (spin it to the left) iCurrentFrame = iCurrentFrame - 1 ; if the current frame counter is less than 0 ; reset it to the number of rotations - 1 If iCurrentFrame < 0 iCurrentFrame = iNumRotations - 1 EndIf EndIf ; call the JoyXDir() function to see if ; the stick is being pushed right If JoyXDir() > 0 Then ; change the current frame (spin it to the right) iCurrentFrame = iCurrentFrame + 1 ; if the current frame counter goes past our number of ; allowable rotations, reset it to 0 If iCurrentFrame > iNumRotations - 1 iCurrentFrame = 0 EndIf EndIf End Function |
Conclusion:
I know that I didn't touch on button-clicks and such with the mouse and Joystick, but if you look under "Input Device Commands" in the BB help section you should be able to start incorporating those easily. Part of getting the game coding and such down is to start tinkering with things on your own, so I purposely avoided covering every input command. Get that hacker mentality going...try things and see what happens! That's all part of becoming a game programmer ;)
As an exercise you should consider putting all of the input functions into one file and check to see if any of them are being used in your main While loop. Also, why not check out the various scancodes to connect to your keys?
Until next time...cya!
This tutorial is by Christian Coders>