Undertale-like movements

M

mickabrig7

Guest
Hello everyone,

I've been trying to reproduce the Undertale engine as an exercise for GML coding, but something is driving me crazy.
I've seen this in many games but I don't know what causes this : when pressing up / down or left / right at the same time, depending on the first pressed key, the character will either keep moving in the initial direction or start moving in the opposite direction.
For example, if you run Undertale, hold up and press down while holding up, you will keep on walking upwards. But if you do the opposite, you will change direction and walk upwards ! It's as if the up direction has some kind of priority, and the same thing happens with the left direction.

Since adding if statements for these special conditions would cause many problems and feel stupid, I'd like to know if anyone here could explain what causes this.
I'm pretty sure Toby didn't add a ton of conditions one after the other, I think this is caused by a function or a way of handling movements, but I couldn't find anything in any of the tutorials I've watched.
 
M

mickabrig7

Guest
I don't mean that using if statements is stupid, just that it would feel weird if Toby added this exact behavior on purpose, it looks more like something generated by a certain way of handling code.
Besides, this behavior is found in many other games, for example Unturned.
 

jazzzar

Member
"Since adding if statements for these special conditions would cause many problems and feel stupid"
do it using if statements and if it works,it's all good :)
 

Alice

Darts addict
Forum Staff
Moderator
I can't speak for Toby, but I think such movement is not really something out of ordinary.
I mean, typical movement code might look like this:
"if you hold left, go left, else if you hold right, go right"
"if you hold up, go up, else if you hold down, go down"

It is somewhat intuitive mechanic to implement and it explains the "up" side taking priority - basically, the up button is checked before the "up". One could try to account for pressing up/down simultaneously, but I guess it's just easier to assume if one side of the given axis is pressed, the other side is ignored. ^^'
 

jazzzar

Member
I can't speak for Toby, but I think such movement is not really something out of ordinary.
I mean, typical movement code might look like this:
"if you hold left, go left, else if you hold right, go right"
"if you hold up, go up, else if you hold down, go down"

It is somewhat intuitive mechanic to implement and it explains the "up" side taking priority - basically, the up button is checked before the "up". One could try to account for pressing up/down simultaneously, but I guess it's just easier to assume if one side of the given axis is pressed, the other side is ignored. ^^'
exactly,so if statements are what he needs ;)
 

Phil Strahl

Member
Since most devs stick to the first movement commands they get working, this is a common characteristic since, yes, it all comes down to the order of flags unless you put in special handling for each of these special cases.

E.g. here's a quick example for movement code that looks fine on first glance, and it works ... half of the time: When right is held down, and left is triggered, the instance will move left until released, but when left is held down and right is pressed, it gets ignored. The reason is the order of the move_left / move_right flags.

Code:
  var key_up = ord('W');
  var key_down = ord('S');
  var key_left = ord('A');
  var key_right = ord('D');
 
 
  // key down checks
  if (keyboard_check(key_up))
  {
  move_up = true;
  move_down = false;
  }
 
  if (keyboard_check(key_down))
  {
  move_up = false;
  move_down = true;
  }
  if (keyboard_check(key_right))
  {
  move_right = true;
  move_left  = false;
  }
 
  if (keyboard_check(key_left))
  {
  move_right = false;
  move_left  = true;
  }

 
  // stop moving
  if (keyboard_check_released(key_up))
  {
  move_up = false;
  }
  if (keyboard_check_released(key_down))
  {
  move_down = false;
  }
  if (keyboard_check_released(key_right))
  {
  move_right = false;
  }
  if (keyboard_check_released(key_left))
  {
  move_left = false;
  }
 
 
  // actual movement
  if move_left
  {
  x = x - 2;
  }
 
  if move_right
  {
  x = x + 2;
  }
 
  if move_up
  {
  y = y - 2;
  }
 
  if move_down
  {
  y = y + 2;
  }
[code]
 
M

mickabrig7

Guest
exactly,so if statements are what he needs ;)
I told you that I didn't think if statements were useless in this case, I just thought that writing a code for movement and then adding several if statements after it to add such special and precise behavior felt weird for me.

Since most devs stick to the first movement commands they get working, this is a common characteristic since, yes, it all comes down to the order of flags unless you put in special handling for each of these special cases.

E.g. here's a quick example for movement code that looks fine on first glance, and it works ... half of the time: When right is held down, and left is triggered, the instance will move left until released, but when left is held down and right is pressed, it gets ignored. The reason is the order of the move_left / move_right flags.
Thanks a lot Phil, I'm changing my code right now :)
 

TheouAegis

Member
I'm with Phil. That was actually the very first thing that popped into my head. At first I thought it was going to be some tricky code, but when you said UP had priority every time and LEFT had priority every time, then it was immediately clear that the programmer just did

if RIGHT ...
if LEFT ...
if DOWN ...
if UP ...

Instead of what he should have done, which is

if RIGHT ...
else if LEFT ...
if DOWN ...
else if UP ...

Or if he programmed in ASM, he probably used a JSR instead of B?? to change subroutines.

See what happens if you press LEFT and UP at the same time.


The popular movement engine around here would cancel movement when opposing keys are pressed, which for most people is a more logical manner of movement.
 
M

mickabrig7

Guest
That's actually what I was getting at first with my code, but I was curious about what caused this priority and wanted to recreate it.
 
C

Christopher Rosa

Guest
What you want so your key pressed priority is always the last key you've pressed is an input buffer:
Code:
///Create_event of obj_player



inputs[0] = vk_right;

inputs[1] = vk_up;

inputs[2] = vk_left;

inputs[3] = vk_down;



input_buffer = ds_list_create();



///Step_event of obj_player



var _dir = input_buffer[| 0];



if(_dir == 2) {hsp = -1;}//Left_key



if(_dir == 0) {hsp = 1;}//Right_key



if(_dir == 3) {vsp = 1;}//Up_Down



if(_dir == 1){vsp = -1;}//Up_key





///Begin_step_event of obj_player



for(var _i = 0; _i < 4; _i++) {

    var _input = inputs[_i];

  

    //check released

    if(keyboard_check_released(_input)) {

        var _index = ds_list_find_index(input_buffer, _i);

        if(_index >= 0) { ds_list_delete(input_buffer, _index); }

    }

    //check pressed

    else if(keyboard_check_pressed(_input)) {

        if(ds_list_find_index(input_buffer, _i) < 0) {

            ds_list_insert(input_buffer, 0, _i);

        }

    }


///Don't forget to clean up ds_list in the clean_up_event
 

Yal

🐧 *penguin noises*
GMC Elder
I'm stoked to hear about their project to replicate the Siren Head sound design and Five Nights at Freddy's power management system without using if statements 🦈
 
To jump in on the thread revival, I think this line:
I'm pretty sure Toby didn't add a ton of conditions one after the other
Is kinda hilarious, because I seem to remember the Undertale code being full of long lists of if statements that are generally considered bad practice. But maybe I'm remembering wrong.
 

woods

Member
long lists of if statements that are generally considered bad practice.



if (not_broken = true)
{
fix_it = 0;
}
 
Top