If you find this tutorial helpful, please consider showing support by trying my latest game
Insane Number Run
***
This tutorial assumes you have some experience with Game Maker’s scripting language, GML.
However, even if you are unfamiliar with it, you should still be able to follow along and find this useful if you take the time to understand it.
Controlling a character in any game should be as intuitive as possible for the player.
Thus, control should function in a predictable manner and avoid any little quirks that could arise and leave your player falling down an endless pit.
One small quirk I’d like to address here revolves around 4 direction character control, and the issue of key direction input/release dominance.
To help illustrate this issue, play around with the character in this example:
BAD CONTROL EXAMPLE
Take note of what happens when you have one direction held and then press down another while holding on to the first direction. Then, try holding down the second direction first and press down the original direction afterwards. Do you notice anything odd?
If you play around with the rest of the directions, trying the different combinations of starting with one direction and then pressing and holding another, you will find there are keys with dominance over other keys. It doesn’t care which key was pressed last, but only which key returns true. But if more than one key direction returns true, it simply takes the first key returning true and uses it.
We will now look at one solution for this issue.
Note: This solution includes both ARROW/WASD key movement.
1) Start a game maker project and create an object called obj_input and set it as persistent
2) Inside obj_input, add Event -> Create
3) Inside the Create event, add -> Code for initializing a few global variables
globalvar
g_keyDirection, // holds value for active direction key pressed
g_keyDirectionIsPressed, // is true when direction key first pressed down
g_keyDirectionIsReleased; // is true when direction key is released
g_keyDirection = -1; // initialize as -1 to ensure no initial false input
g_keyDirectionIsPressed = false;
g_keyDirectionIsReleased = false;
4) Inside obj_input, add Event -> Begin Step
5) In this event, add -> Code to check for the last direction pressed and set g_keyDirection/g_keyDirectionPressed accordingly:
// First, clear global Pressed/Released states
g_keyDirectionIsPressed = false;
g_keyDirectionIsReleased = false;
// Second, Check for ARROW or WASD presses
if (keyboard_check_pressed(vk_right)
or keyboard_check_pressed(ord('D')))
{
g_keyDirection = 0;
g_keyDirectionIsPressed = true;
}
else
if (keyboard_check_pressed(vk_up)
or keyboard_check_pressed(ord('W')))
{
g_keyDirection = 90;
g_keyDirectionIsPressed = true;
}
else
if (keyboard_check_pressed(vk_left)
or keyboard_check_pressed(ord('A')))
{
g_keyDirection = 180;
g_keyDirectionIsPressed = true;
}
else
if (keyboard_check_pressed(vk_down)
or keyboard_check_pressed(ord('S')))
{
g_keyDirection = 270;
g_keyDirectionIsPressed = true;
}
Okay, this is great, but what about key release variances? If a player has two keys pressed and releases one of them, it should always return the direction to the remaining key held.
6) Add the following code below the code we just wrote in the Begin Step event
// Third, Check for ARROW or WASD releases
if (keyboard_check_released(vk_right) // Arrow keys
or keyboard_check_released(vk_up)
or keyboard_check_released(vk_left)
or keyboard_check_released(vk_down)
or keyboard_check_released(ord('D')) // WASD keys
or keyboard_check_released(ord('W'))
or keyboard_check_released(ord('A'))
or keyboard_check_released(ord('S')))
{
g_keyDirectionIsReleased = true;
g_keyDirection = -1; // Make sure to clear this first
if (keyboard_check(vk_right)) g_keyDirection = 0; else
if (keyboard_check(vk_up)) g_keyDirection = 90; else
if (keyboard_check(vk_left)) g_keyDirection = 180; else
if (keyboard_check(vk_down)) g_keyDirection = 270; else
if (keyboard_check(ord('D'))) g_keyDirection = 0; else
if (keyboard_check(ord('W'))) g_keyDirection = 90; else
if (keyboard_check(ord('A'))) g_keyDirection = 180; else
if (keyboard_check(ord('S'))) g_keyDirection = 270;
}
There, once you have added obj_input to your game’s starting room (remember to make it persistent!), you should now be able to have any object in your game access the g_keyDirection variable and set its movement accordingly. You also have access to g_keyDirectionIsPressed and g_keyDirectionIsReleased for when you need to use those states.
For example,
7) Create an object called obj_player
8) Inside obj_player, add Event-> Step containing -> Code for moving the player accordingly
// Set speed and direction when key pressed
if (g_keyDirectionIsPressed)
{
speed = 4;
if (g_keyDirection == 0) direction = 0;
if (g_keyDirection == 90) direction = 90;
if (g_keyDirection == 180) direction = 180;
if (g_keyDirection == 270) direction = 270;
// Or simply...
// direction = g_keyDirection;
}
// Set speed and direction when key released
if (g_keyDirectionIsReleased)
{
if (g_keyDirection == -1) speed = 0; // Stop if no direction pressed
else if (g_keyDirection == 0) direction = 0;
else if (g_keyDirection == 90) direction = 90;
else if (g_keyDirection == 180) direction = 180;
else if (g_keyDirection == 270) direction = 270;
}
Now, the second direction key pressed will always be dominate when two keys are pressed down, and when a direction key is released, the remaining key pressed will take over as one would hope.
The character movement should now be like this:
BETTER CONTROL EXAMPLE
Again, notice the difference when compared with the BAD CONTROL EXAMPLE
You can download the completed example gmk for Game Maker here:
[Windows Version]
DOWNLOAD
[Mac Version]
DOWNLOAD
If you have any questions or comments, feel free to contact me!