If you can't control a game, you are practically watching a movie. The good news is that Acknex allows you to control what's happening in the level using the keyboard, the mouse, the joystick and simple script instructions. If you want to use other hardware devices with the engine (a light gun, for example) you can use the SDK to develop an interface for them using C++ or Delphi.
Acknex can do three different things when you press a key on your keyboard:
1) Acknex sets a predefined variable to 1 when we press a key on the keyboard. The good news is that these predefined variables have meaningful names, like this:
key_a, key_b, key_shift, key_space, key_pause, key_f1, etc.
You can check if key_a == ON and if this is true, you know for sure that the player has pressed the "A" key.
2) Acknex generates a scan code. That's a simple number, but its value depends on what key you have pressed. You can check the value of the scan code to see what key was pressed, using key_lastpressed. Read the second section of the manual to find more information about these keywords, including a table with all the scan codes.
This method is used in some rare cases, like redefining the keys. You can find a few examples that use scan codes in the Acknex User Magazine (AUM).
3) Acknex is able to run a specific function when we press a key on the keyboard, if we have attached a function to a certain key. I have used an example in one of the previous workshops, the one that talks about pointers:
function move_up()
{
wizard.z = wizard.z
+ 5;
}
...
on_u = move_up;
...
This example runs a previously defined function named "move_up" when we press the "U" key (it doesn't matter if you press "U" or "u". Please note that the function name must be given without parenthesis.
Important tip
I encourage you to read all the AUMs if
you want to learn even more about Acknex and C-Script because the code
inside the articles is explained step by step. Oh, and don't copy and paste
code from the magazine because it is simplified a little - there's a link
to the fully working, downloadable C-Script files on the first page of
every magazine.
Let's get to work! Start WED, open work13, build it and run it and you will see all three keyboard methods listed above in action (the nice sky texture from the standard.wad was created by Mighty Pete). Press W or S to tilt the camera up and down; press A and D to change the pan angle of the camera. Press 1 to make the sky brighter and press 2 to reduce the sky light. Press R to restore the initial camera angles.
I'm sure that you won't be too surprised when you will hear that all these things were created using a small script file:
/////////////////////////////////////////////////////////////////// var video_mode = 7; //////////////////////////////////////////////////////////////////// function bright_lights() { sky_cube_level.blue += 10; sky_cube_level.green += 10; sky_cube_level.red += 10; } function dim_lights() { sky_cube_level.blue -= 10; sky_cube_level.green -= 10; sky_cube_level.red -= 10; } function main() { on_1 = bright_lights; on_2 = dim_lights; level_load ("work13.wmb"); while (1) { if (key_w == ON) { camera.tilt += 1; } if (key_s == ON) { camera.tilt -= 1; } if (key_a == ON) { camera.pan += 1; } if (key_d == ON) { camera.pan -= 1; } if (key_lastpressed == 19) // if [R] is pressed { camera.pan = 0; camera.tilt = 0; sky_cube_level.blue = 128; // medium brightness sky_cube_level.green = 128; sky_cube_level.red = 128; } wait (1); } }
The first thing that needs to be discussed is the while loop:
while (1)
{
if (key_w == on)
{
camera.tilt += 1;
}
if (key_s == on)
{
camera.tilt -=
1;
}
if (key_a == on)
{
camera.pan += 1;
}
if (key_d == on)
{
camera.pan -=
1;
}
if (key_lastpressed
== 19) // if "R" is pressed
{
camera.pan = 0;
camera.tilt = 0;
sky_cube_level.blue
= 128; //
medium brightness
sky_cube_level.green
= 128;
sky_cube_level.red = 128;
}
wait (1);
}
Please note that the loop contains the
necessary "wait (1);" instruction that interrupts it from time to time,
allowing the other functions and actions to run at the same time. Let's
see how the first keyboard method works: if we press the W key,
the code adds 1 degree to camera's tilt angle. If we press the S key,
the code subtracts 1 degree from the tilt angle. Press A to
add 1 degree to camera.pan and D to subtract
1 degree from camera.pan.
I hope that you remember the dot method: object.property. The camera (our view inside the 3D world) is an object too, so we can change its angles, position, ambient, etc using the dot method. Oh, and these simplified instructions:
camera.tilt += 1;
do exactly the same job with their bigger brothers:
camera.tilt = camera.tilt + 1;
You can use the same shortcut for any
other mathematical operator used by the engine: "+", "-",
"*",
"/", "%". Let's take a look at the last part of the loop,
which uses the scan code (the second keyboard method):
if (key_lastpressed == 19) //
if "R" is pressed
{
camera.pan = 0;
camera.tilt = 0;
sky_cube_level.blue
= 128; // medium brightness
sky_cube_level.green = 128;
sky_cube_level.red = 128;
}
The predefined variable named key_lastpressed stores the scan code for the last key that was pressed on the keyboard. Whenever you press R, key_lastpressed will be set to 19 (the scan code that corresponds to the "R" key). The "if" instructions tests if R was pressed and if this is true, it resets the camera (its initial angles are pan = 0, tilt = 0).
The scan codes generated by the engine have nothing to do with the ASCII or ANSI codes, although they can be converted to ASCII / ANSI (don't bother to read the last phrase if you don't know anything about ASCII and ANSI codes). Tip: Check the reference manual to see a table with all the scan codes for every key on the keyboard.
The last 3 lines set the brightness of the sky at a medium value. Again we're using the dot method, but our object this time is not the camera, but the sky. While the camera is a VIEW object, the sky is an ENTITY object that we already know since workshop 9. sky_cube_level is a predefined sprite ENTITY* pointer that is set by the engine to the sky cube image placed in the level.
Every entity has a color defined by its blue, green, and red values. Those values range from 0 to 255, so by setting them at 128 we're getting a medium color and brightness.
Let's now finally take a look at the two functions that run when we press the 1 or 2 key on the keyboard:
function bright_lights()
{
sky_cube_level.blue +=
10;
sky_cube_level.green += 10;
sky_cube_level.red += 10;
}
function dim_lights()
{
sky_cube_level.blue -=
10;
sky_cube_level.green -= 10;
sky_cube_level.red -= 10;
}
...
on_1 = bright_lights;
on_2 = dim_lights;
...
The first function (bright_lights) increases the sky brightness by adding a value to its colors. The second function reduces the sky brightness. Tip: please note the missing parentheses for the two functions in the "on_1 = ..." and "on_2 = ..." lines in the main function. If we placed parentheses behind the function names, the functions bright_light and dim_light would be executed, rather than assigned to the keys!
The keyboard method that works with scan
codes isn't used too often. You should use the "on_x = do_something;" method
(replace "x" with any other key) when you want to run a specific action
or function that executes something and then stops running (opens a door,
turns on the light, loads a game, adds two numbers, etc). Use the "if
(key_x == on)" method and a while loop when you want to control an action or function
that is supposed to run continuously (player's movement, the camera, a
vehicle, a paddle, etc).