GML Global Variables Not Working Correctly

R

RetroNuva10

Guest
I've been having trouble with a, so far, very simple game. The object Player, when vk_left or vk_right is pressed, is supposed to move left/right.

The object Player has a create event and step event:
Code:
///Create Event

spd = 20;
Code:
///Step Event

if (global.right) Player.x += spd;
if (global.left) Player.x -= spd;
I have an object Controls which contains the following Create event:
Code:
///Create Event

global.right = keyboard_check(vk_right);
global.left = keyboard_check(vk_left);
global.space = keyboard_check(vk_space);
global.spacePress = keyboard_check_pressed(vk_space);
I have no usage of the built-in physics system. I've checked, and both Controls and Player have an instance within the room that is being loaded. For some reason, the only event in which I can place the global variables that allows it to work correctly is within the Player Step Event. Placing them in any other event doesn't allow the Player to move from the pressing of vk_left or vk_right.
 

Maximiliano

Member
The code in the create event of the control object (or any object) only executes one time (when it's created). Try changing the create event to a step event and it should work.
 
R

RetroNuva10

Guest
This works, but I'm not understanding why it works. In the create event, those global variables are declared and initialized once. They should continue existing without the need to be reassigned to the keyboard checks every step/frame. Am I correct, or no?
 
L

Laurent57

Guest
keyboard_check is a real time function, you need to check it every step else you just assign the variables at the moment 0.
When you assign your global variables, their values are probably 0. If you don't
check the buttons permanently they'll never change.
 
R

RetroNuva10

Guest
keyboard_check is a real time function, you need to check it every step else you just assign the variables at the moment 0.
Oh! I see. I was thinking, for example, global.right was being set to a function (I thought this because GML has multiple added features for ease of access and simplicity that other languages don't), and every time global.right was checked, the assigned function was executed. However, it seems as if global.right is being assigned to the result of the function.
 

TheouAegis

Member
Ideally, input fetches should be put in the Begin Step Event (which has been in place since GM8). This is also when the built-in input fetches happen. That way all input states will be available by the Step event for any instances that need it.

And while I do use inputs in the player object when doing quick little mock-ups, I personally feel all input fetches should be handled by a separate controller object or at least stored in a global variable. That way, for example, even a boss enemy would have access to the player's controls to decide if it should block an incoming attack.
 

Bentley

Member
Ideally, input fetches should be put in the Begin Step Event. This is also when the built-in input fetches happen.
That way all input states will be available by the Step event for any instances that need it.
Hey, I know I'm a bit off topic, but I was just wondering if you would mind sharing more of your thoughts on this. Do you mean that you store what keys were pressed in the Begin Step, and then, in the Step, react to those inputs?

I'm currently trying to figure out how to make a platformer. Specifically, I'm trying to learn how to best organize everything: inputs, movement and collision, state changes, and so forth.

I know my question is a bit unclear, so I apologize for that, but any of your thoughts would be greatly appreciated.
 

TheouAegis

Member
Do you mean that you store what keys were pressed in the Begin Step, and then, in the Step, react to those inputs?
Well, you can react on them whenever you want, but yeah. If you use the built-in input events, that's already what you're doing essentially. All of the keyboard and mouse events happen between the Begin Step and the Step events. GM runs on an event-by-event order, not instance-by-instance order, so GM will not run the Step Event until all instances have run their Begin Step events.

Now, going off the boss enemy example...

If the player had its input events and the boss had an input event for the player's attack button, then when the attack key is pressed, both events would run. One input check, two events executed. This is adequate. But if we didn't use the input events, then you'd have the player checking for the attack button and the boss also checking the attack button. So the input check is handled by GM, then the player's input check code is handled, then the enemy's input check code is handled. That's three input checks and two executions, as opposed to just one input check and two executions. If we used the input event in just the player saved to a global or in a control object, then have the player and the boss check the value of that variable, then it'd be one input check and one input event.

But what about the code that needs to be run if the attack key is pressed? In the first method, the player could execute his attack code from the key event; likewise, the boss could activate his defense code from the key event. However, the more common scenario is the key events would set variables in each of the instances and that variable would be referenced in the Step event. And that in and of itself requires additional code to work properly (which is why people rarely do this anymore).
Code:
///Begin Step
key_attack = false;

///Attack Key Input
global.key_attack = true;

///Step
if key_attack {
blahblahblah
}
The Begin Step code would need to be in the boss too. So that's 6 event calls when it could easily just be 4.
Code:
///Control object or Player object (if single-player) Begin Step
global.key_attack = false;

///Control object or Player object (if single-player) Attack Key Input
global.key_attack = true;

///Player and Boss Step
if global.key_attack
{
blahblahblah
}
It gets even more important when you start dealing with multiple inputs. And if you are using gamepads, you don't even have events (or maybe you do in Studio 2? I dunno, I use S1). In those scenarios, the fewer input calls you make, the better. What if the attack input is configurable so that it could be either the mouse or the keyboard, or both?
Code:
key_attack = 0;
if input_attack = enums.keyboard
    key_attack = keyboard_check(io_attack);
else
    key_attack = mouse_check_button(io_attack);
You'd need to run that for both the player and the boss, or you make key_attack a shared variable and only run that code once in a Begin Step. You wouldn't be running any input events in this case.

You can further condense things by using a single variable to hold all input states (via bit manipulation), but you'd be sacrificing some speed to save on the array size.
 
Last edited:

Bentley

Member
Well, you can react on them whenever you want, but yeah. If you use the built-in input events, that's already what you're doing essentially. All of the keyboard and mouse events happen between the Begin Step and the Step events. GM runs on an event-by-event order, not instance-by-instance order, so GM will not run the Step Event until all instances have run their Begin Step events.

Now, going off the boss enemy example...

If the player had its input events and the boss had an input event for the player's attack button, then when the attack key is pressed, both events would run. One input check, two events executed. This is adequate. But if we didn't use the input events, then you'd have the player checking for the attack button and the boss also checking the attack button. So the input check is handled by GM, then the player's input check code is handled, then the enemy's input check code is handled. That's three input checks and two executions, as opposed to just one input check and two executions. If we used the input event in just the player saved to a global or in a control object, then have the player and the boss check the value of that variable, then it'd be one input check and one input event.

But what about the code that needs to be run if the attack key is pressed? In the first method, the player could execute his attack code from the key event; likewise, the boss could activate his defense code from the key event. However, the more common scenario is the key events would set variables in each of the instances and that variable would be referenced in the Step event. And that in and of itself requires additional code to work properly (which is why people rarely do this anymore).
Code:
///Begin Step
key_attack = false;

///Attack Key Input
global.key_attack = true;

///Step
if key_attack {
blahblahblah
}
The Begin Step code would need to be in the boss too. So that's 6 event calls when it could easily just be 4.
Code:
///Control object or Player object (if single-player) Begin Step
key_attack = false;

///Control object or Player object (if single-player) Attack Key Input
key_attack = true;

///Player and Boss Step
if global.key_attack
{
blahblahblah
}
It gets even more important when you start dealing with multiple inputs. And if you are using gamepads, you don't even have events (or maybe you do in Studio 2? I dunno, I use S1). In those scenarios, the fewer input calls you make, the better. What if the attack input is configurable so that it could be either the mouse or the keyboard, or both?
Code:
key_attack = 0;
if input_attack = enums.keyboard
    key_attack = keyboard_check(io_attack);
else
    key_attack = mouse_check_button(io_attack);
You'd need to run that for both the player and the boss, or you make key_attack a shared variable and only run that code once in a Begin Step. You wouldn't be running any input events in this case.

You can further condense things by using a single variable to hold all input states (via bit manipulation), but you'd be sacrificing some speed to save on the array size.
Thanks a lot for the explanation : )
 
Top