Welcome back! In our previous tutorial we set up our project and programmed our basic display routines, and in this lesson we will get mouse routines working. Let's dive right in!
Ensure your main routine looks like the following image then compile/execute it; this will make sure our code from the last tutorial still works. Remember to substitute the display mode your display supports in the Display_Mode_Exist() and Display_Mode_Set() calls. If you don't see a black screen or window with the screen resolution and color depth displayed, go back and complete the first tutorial.
If this works, delete lines 9 and 10 because we won't need them. Now add the code in the following image to your main routine:
Lines 2 and 3 set the sync rate our program will run at as well as enable sync. Sync rate is the frequency our game will write to our display; it is equivalent to Frames Per Second (FPS). If we set a sync rate of 30, our program will attempt to allow updates the display 30 times a second. A sync rate of zero tells our program to allow display updates as many times per second as possible. Note that these commands don't update the display, but perform timing related to accomplishing display updates.
Line 13 creates a 3D object; we are creating a sphere with an object ID of 1 and size of 100. Creating or loading any 3D object also causes our program to switch to 3D rendering mode rather than the 2D mode we have been operating in.
Lines 15 and 18 set up what is called our "main program loop", line 15 tells our program to continue executing all code between it and line 18. Statements such as "while" in line 15 are called "opening" statements because they open a loop or section of code; meanwhile, statements like "endwhile" in line 18 are called "closing" statements because they close a previously opened section of code.
Line 16 simply reads the current mouse position and prints it on the display at location 10, 10.
Finally, line 17 tells our program to update the display. Without this command our program will perform everything we instruct it to but we will never see the results because the screen isn't being updated. Compile/execute your program and you should see a blue screen, gray sphere, and coordinates in the upper left of the screen which change as you move your mouse.
Now that we have a main loop, let's start working with the mouse. Add the following code to you main routine:
Lines 17 through 21 check for a mouse click, and if there is a click, increments a counter which increments with each click. If there is no click the counter is cleared. Compile/execute your program, play with various mouse buttons, and observe the changes in the data in the upper left of the screen as you do so.
If you were observant you should have noticed the mouseclick() command returned results regardless of which button was clicked and also returned inconsistent click counts. Even clicking once as fast as is humanly possible the command causes more than a single click to be counted. Why is this, and more importantly how do we fix it?
The cause is that the mouseclick() command isn't named correctly; it should be called a "mousedown()" or perhaps "mousepress()". The command returns a non-zero value if any mouse button is pressed when the command executes. The value returned by the command is dependent on which buttons are pressed; see the help file for further information.
Once we understand the cause we can see there is no problem to fix, but we do need to implement a function we can simply call to check if a specific mouse button has been clicked. By clicked we mean it has been pressed for a very short amount of time then released. But exactly how short is this "short amount of time?"
Let's measure it ourselves using some code! Enter the following code into your main routine:
We won't dissect the code now, but Compile/Execute and click the left mouse button as you normally would when browsing the internet or working in a program. The code takes an average of all your clicks so make sure to do 10 or 15; my average was about 100 and the greatest was 135. This is measured in milliseconds, so this means my average click is 100ms in length from when I press the button down to when I release it.
It's time to create a new source file called "Mouse" and add it to our project. When you have done that enter the following code into the new file:
Lines 2 through 5 define a data type for a position in 2D space. In lines 7 through 13 we define a data type which will hold all information, such as timers and flags, we need to process a click. Next, in lines 15 - 18, we define a data type to hold information we need to process a single button. As can be seen, this type includes the previously defined data type. We define a fourth data type in lines 20 through 25 to hold all mouse-related data by defining four buttons having the attributes we previously defined. Finally we create a function to initialize our mouse, or more specifically, the array used to hold all data needed to process mouse input. We also assign a value to each button's threshold. Breaking aspects of the mouse down in this manner makes it easier to add additional functionality and buttons to our mouse routines if we wish to do so later. Compile/Execute your code to ensure there are no errors, and if there are, correct them. Next we will start to build functions to process single clicks. Begin by typing the following into the the file containing our mouse routines:
While there is a great deal of code here, much of it is merely the same logic applied to the four different mouse buttons. We need only to examine code handling the left button to learn how it operates, so let's do that by looking at lines 181 - 208.
Let's further break these lines down by function:
- Line 181 executes lines 182-193 if the button is down, otherwise executes lines 195-206
- Line 182 executes lines 183-188 if the button was down during the previous call to the mouse update routine; otherwise lines 190-192 are executed.
- Line 195 executes lines 196-203 if the button was down during the previous call to the mouse update routine
Now that we have major functions broken down let's take a look at what each does.
Lines 183-186 calculate the number of milliseconds which have elapsed since the previous call to the mouse update routine. To prevent a negative value due to the system timer overflowing during the execution of our program, lines 184-186 convert any possible negative value to positive. Line 187 adds the elapsed time to the button's timer, while line 188 copies the current system timer value into the button's data structure to be used the next time lines 183-186 are executed.
Line 190-192 are executed upon the detection of the button transition from up to down. Line 190 sets the button's down flag, 191 copies the current system timer value to the button's data structure, and 192 clears the button's timer.
Line 196 clears the button's down flag because the button is no longer down. Line 197 determines whether lines which set the button's clicked flag and click position (198-200) are executed or if line 202 which clears the clicked flag is executed.
With our update routine written we now need functions our other routines can use to easily determine if click events for specific buttons have occurred. Enter the following code into the file containing our mouse routines:
These functions check to see if their respective button's clicked flag is set and return the X or Y position where the click was registered if the flag is indeed set. It it's not set they return -1. This allows future routines to simply read position data without first checking for clicks and discard if equal to -1.
To test our code, go back to the main routine and enter the following:
Compile/Execute and experiment with clicking the left and right buttons. Notice our program doesn't recognize clicks which have been held down for longer than the thresholds we set during mouse initialization? There are occasions when we merely want to test for a mouse click and don't really care about the position, to handle those enter the following into the file containing our mouse routines:
The Mouse_Click() function returns true if any buttons have registered a click, while the Mouse_Click_Left() function returns true if the left button has registered a click. To add this functionality to other buttons simply copy and paste the Mouse_Click_Left() function, changing each instance of "Left" to the name of the proper button. To test our new code, enter the following (note that each image includes the source file it is located in near the top of the image):
Compile/Execute and observe what happens when you click various buttons.
Congratulations! You have written routines which will greatly aid in testing and debugging functions we will write in the future, as well as aid in some aspects of interacting with our game's future content. Continue to experiment with the code and read the DarkBasic help file entries on keywords we have used if you don't understand them.
Thanks for following along!
Are you into game developement?
I was one of the primary content/IP creators for a game which was in development but never completed, and also dabbled in some of the programming for it. However, my expertise lies more in microprocessor design and embedded/high-reliability systems development. Various versions of Assembly are my primary programming language.
I see you are developing a game for Steemit; are you new to game programming or have you done it for some time?
Great! I have developed some games . You can find it here : https://play.google.com/store/apps/developer?id=VmadeiT