Previous: Using the mouse. Events

Using the joystick

If you plan to create a flight simulator and you expect it to be sold, you'd better add support for joysticks too! The good news is that the code that allows you to do that is simple. Ok, there's some bad news too: you need to have a joystick if you want to test this workshop. Don't worry if you don't have a joystick yet; you can test this project later, when you get one.

Ok, so how do we get started? First of all, you need to plug your joystick in its corresponding plug. Then, open Windows' control panel:

That's Windows XP's control panel, so you will see a slightly different picture if you are using a different version of the O.S. Double click "Game Controllers" ("Gaming Options" in Windows 2000) to open it:

You can see that my good old trusty joystick appears to be "OK". Click "Add" to add your joystick if you've never done that before. The installation should be easy and most joysticks will work ok with the drivers that come with Windows. Wait for the installation to finish, click "Properties" and then "Test" and you will see a window that looks like this:

As you might have guessed, your picture will be different, depending on your joystick type. The "Test" page allows us to set the X and Y axis offset and to test the buttons. Adjust the controls on the joystick until the crosshair is placed close to the center of the white square.

The joystick is now set up correctly; you won't need to go through all these settings again until you reinstall Windows. This joystick setup process has nothing to do with the Acknex engine; if you have ever used a joystick you went through all these settings already!

Ok, let's get back to our beloved lite-C: open the workshop15 folder, and then load script15.c and run it:

It's the same good old house, but this time we can move the camera using the joystick! Use the first joystick button to increase the height of the camera (z) and the second button to decrease it. Press both buttons at the same time to move the camera back to its initial position.

All this stuff sounds pretty complicated, so I expect the code inside the script15.c file to be really simple:

////////////////////////////////////////////////////////////////////
#include <acknex.h>
#include <default.c>
////////////////////////////////////////////////////////////////////

function main()
{
    video_mode = 7;
    level_load ("work15.wmb");
    wait (2);
   camera.pan = 0;
    while(1)
    {
        camera.y -= joy_force.x;
        camera.x += joy_force.y;
        if (joy_1) camera.z += 1;
        if (joy_2) camera.z -= 1;
        if (joy_1 && joy_2)
        {
            camera.x = 0;
            camera.y = 0;
            camera.z = 0;
        }
        wait(1);
    }
}

The code is simple indeed! Let's see what function main does: it sets the screen resolution to 800 x 600 pixels, loads the level, waits for 2 frames and then it sets camera.pan to 0 degrees. That's a good camera angle for this level; it instructs the camera to look at the house.

That was the easy part. Now let's discuss the code inside the while (1) loop:

while(1)
{
    camera.y
-= joy_force.x;
    camera.x += joy_force.y;
    if (joy_1) camera.z += 1;
    if (joy_2) camera.z -= 1;
    if (joy_1 && joy_2)
    {
        camera.x = 0;
        camera.y = 0;
        camera.z = 0;
    }
    wait(1);
}

The previous workshop has taught us about mouse_force.x and mouse_force.y; well, joy_force.x and joy_force.y do the same thing: their values change from -1 to 1 depending on the speed with which we move the joystick. When we don't move the joystick, joy_force.x and joy_force.y are set to zero, so they don't move the camera at all.

I thought that it will be more fun to move the camera (instead of rotating it), so joy_force.x and joy_force.y change the y and x positions of the camera. No, it's not a mistake:joy_force.x changes the y position of the camera, while joy_force.y changes the x position of the camera. Let's see why that is happening...

When camera's pan angle is set to zero, we are looking in direction of the x axis. However when we move the joystick forward and backward we're changing joy_force.y. Thus we need joy_force.y to move us forward and backward, i.e. change our x position. In a similar way, we need joy_force.x to move sideways, i.e. change our y position. If you want to reverse the movement directions on the x and y axis of the joystick, replace "-=" with "+=" and "+=" with "-=" in one or both lines of code from above.

Do you remember what I've told you when we have studied the keyboard and the mouse? Each key or mouse button has an associated variable that can be set to "true" (non-zero) if the key / button is pressed. We can check if a certain key is pressed using a single line of code:

if (key_t)
{
    // do some stuff if the "T" key is pressed
}

The same method can be used for the joystick:

if (joy_1)
{
    // do something when the first joystick button is pressed
}

You won't be surprised to hear that Acknex can control one or two joysticks, each of them having up to 12 buttons. The snippet posted above does something if the first joystick button was pressed.

Ok, so the first two joystick buttons (joy_1 and joy_2) control the height (the z) of the camera, which is nice, because the joystick itself controls the x and y of the camera, using joy_force.x and joy_force.y. However, the last few lines of code inside the while loop give me a headache:

if (joy_1 && joy_2)
{
    camera.x = 0;
    camera.y = 0;
    camera.z = 0;
}

These are the lines of code that move the camera at its initial position (x = 0, y = 0, z = 0) - there's no doubt about that. Wait a minute; this happens when we press both joystick buttons at the same time, so (joy_1 && joy_2) must mean "joy_1 is true AND joy_2 is true ", both joystick buttons are pressed at the same time! Am I smart or what?

Those of you that remember a thing or two about vec_set know that we could have also used something like this, right?

if (joy_1 && joy_2)
  vec_set (camera.x, vector(0, 0, 0));

Do you remember those nested "if" instructions? They are nothing more than "if" instructions placed inside other "if" instructions.

if (joy_1)
{
    if (joy_2)
    {
        if (joy_3)
        {
            if (joy_4)
            {
                // do something when the first four buttons of the joystick are pressed at the same time
            }
        }
    }
}

Now let's rewrite the ugly code above using the "AND" && operator:

if (joy_1 && joy_2 && joy_3 && joy_4)
{
    // do something when the first four buttons of the joystick are pressed at the same time
}

I know, I know... The code is cleaner, shorter, nicer, and so on. That's why this "AND" operator was invented and you should use it whenever you can.

If "AND" has impressed you, I've got some more good news: "AND" has a brother named "OR". This "OR" || operator is used when something is true OR something else is true OR... Let's assume that you want to shut down the engine when a certain var named gold is set to 1000 or 2000 or 3000. You could write the code this way:

function some_function()
{
    if (gold == 1000)
    {
        sys_exit(NULL);
    }
    if (gold == 2000)
    {
        sys_exit(NULL);
    }
    if (gold == 3000)
    {
        sys_exit(NULL);
    }
}

What can I say? The code would work ok but the "OR" operator makes it look so much more simple:

function some_function()
{
    if ((gold == 1000) || (gold == 2000) || (gold == 3000))
    {
        sys_exit(NULL);
    }
}

 !!  If your joystick isn't calibrated properly the camera can start to spin when you are running a game (yours or somebody else's project). Unplug the joystick if you don't need it or make sure that it is calibrated properly.

 !!  IIf you are checking several expressions at the same time (using && or ||) you need to use separate parenthesis for every expression and another pair of parenthesis that encloses them all, just like in the example below:

Problem:
If a = 2 and b = 3 shut down the engine.

Solution:
if ((a == 2) && (b == 3))
{
    sys_exit(NULL);
}

We are coming close to the end of the workshop so cheer up! Here's your homework: how would you rewrite the code inside script15.c if you would want the player to be able to change the height of the camera (its z) using the two joystick buttons OR the "A" (move up) and "Z" (move down) keys?


Solution: Replace two lines of code inside function main:

if (joy_1) must be replaced with if (joy_1 || key_a)
if (joy_2)
must be replaced with if ((joy_2 || key_z)


Next: Using the debugging tools