Move an object 16 pixels at a time

Hello all,

I am brand new the the GameMaker community, as well as programming in general. I am trying to create a SNES era action RPG. I have been able to setup 4 directional only movement with the code below in my STEP event. I am trying to figure out how to make my character move a minimum of 16 pixels at a time. My character should move as normal as a direction is pushed, then animate and stop at the nearest 16 pixel increment. Currently my character moves one pixel at a time. I need code that when a direction is pressed, he will move in 16 pixel increments smoothly and stop. The character and all other tiles in my game are 32x32, which would mean 1/2 block movement per movement stop. Some other forums talked about the LERP function, but I cannot figure out how to put that into my code to correspond to movement and sprite transitions. I am using GameMaker Version 2.3.7.606. Any help would be greatly appreciated.

GML:
switch (keyboard_key)
{
   case vk_left:
   case ord("A"):
    x += walkSpeed;
    image_speed = walkSpeed;
    sprite_index = spr_Sumo_mvnt_L;
      break;
 
   case vk_right:
   case ord("D"):
    x += walkSpeed;
    image_speed = walkSpeed;
    sprite_index = spr_Sumo_mvnt_R;
      break;
 
   case vk_up:
   case ord("W"):
    y -= walkSpeed;
    image_speed = walkSpeed;
    sprite_index = spr_Sumo_mvnt_U;
      break;
 
   case vk_down :
   case ord("S"):
    y += walkSpeed;
    image_speed = walkSpeed;
    sprite_index = spr_Sumo_mvnt_D;
      break;
 
    default:
        image_speed = 0;
        image_index = 0;
        walkSpeed = 1;
   }
 
Set walkspeed to 16. All the time.
There's your logic:
If a key is pressed on any frame, one of the case will execute, otherwise it will return the default case (in which you set your walkspeed to 1)
Dont forget, the step event runs EVERY FRAME, so it will run the default case if no key is pressed.

So Create event:
GML:
walkspeed = 16;
And default case of switch:
GML:
image_speed = 0;
image_index = 0;
//walkSpeed = 1;     //Remove or comment this out
 
Set walkspeed to 16. All the time.
There's your logic:
If a key is pressed on any frame, one of the case will execute, otherwise it will return the default case (in which you set your walkspeed to 1)
Dont forget, the step event runs EVERY FRAME, so it will run the default case if no key is pressed.

So Create event:
GML:
walkspeed = 16;
And default case of switch:
GML:
image_speed = 0;
image_index = 0;
//walkSpeed = 1;     //Remove or comment this out

Thank you. The problem is that the movement is too fast if I use walk speed of 16. I would have to very quickly press and release a direction to move only 16 pixels. I need the distance of 16 pixels with the speed of 1.
 
Before going too far, are you sure that's really how you want your character to move? You're describing an "Action RPG" and in combination with your user name, I'm expecting something like Link to the Past, which had free movement, one pixel at a time. It likely would have been a very frustrating game with the Pokemon-style movement you're describing - for example, what happens if the player wants to attack, or is attacked, between moves?

If you're sure that's what you want to do, lerp would probably be the best way. You can't just plug it into the existing code, as this style of movement requires an entirely different logic - currently your code constantly updates the position of the character, but you only want to update when the player is not moving. When the player presses a button and the character is not moving, the character begins to move in the indicated direction and further inputs are ignored until the character finishes moving to the new location (unless you're using input buffering, which you'll probably want but is a whole additional subject).

Recap: you need a variable that tracks whether or not the character is moving. Only check for inputs if the character is not moving.

How to handle the actual movement? Let's look at how Lerp works:

Lerp takes two values, A and B, and blends them by a third value between 0 and 1. 0 will make the output value equivalent to value A, 1 will make the output value equivalent to B. 0.5 will return a value exactly between the two, and so on. To smoothly move a character between point A and B, each step you'd use something like:
GML:
pos = lerp(posA,posB,blendAmount);
blendAmount += 0.1;
When blendAmount >= 1, the character has reached the destination position. Increasing blendAmount by 0.1 means it will take 10 frames to complete the move - using a smaller or larger value will cause the animation to take more or less time.

Put it all together: when the character isn't moving and the player presses a button, determine what the character's X and Y positions should be after completing the corresponding move. Store that, along with the current location. Set a blend value to 0.
Each step the character is moving, use lerp to blend the starting x/y positions with the destination x/y positions to get the animated position. Increase the blend value by a small amount. When the blend value is greater than or equal to 1, the character has reached it's destination position and is no longer moving. To be safe, at this point you should manually set the character's X/Y position to the destination position - it's possible to overshoot if blendAmount is greater than 1. The character is no longer moving and is ready to accept further input.

There are some alternatives to lerp - when the player presses a move button you could instantly pop the character to the new position, change the sprite to a 16-frame animation, and prevent additional movements until the animation is complete - but they're all going to hinge on tracking the player's movement state and only accepting input when their character isn't moving. Going the lerp route will give more flexibility, especially if you can get comfortable enough to enhance the straight lerp with animation curves.
 
Last edited:
Before going too far, are you sure that's really how you want your character to move? You're describing an "Action RPG" and in combination with your user name, I'm expecting something like Link to the Past, which had free movement, one pixel at a time. It likely would have been a very frustrating game with the Pokemon-style movement you're describing - for example, what happens if the player wants to attack, or is attacked, between moves?

If you're sure that's what you want to do, lerp would probably be the best way. You can't just plug it into the existing code, as this style of movement requires an entirely different logic - currently your code constantly updates the position of the character, but you only want to update when the player is not moving. When the player presses a button and the character is not moving, the character begins to move in the indicated direction and further inputs are ignored until the character finishes moving to the new location (unless you're using input buffering, which you'll probably want but is a whole additional subject).

Recap: you need a variable that tracks whether or not the character is moving. Only check for inputs if the character is not moving.

How to handle the actual movement? Let's look at how Lerp works:

Lerp takes two values, A and B, and blends them by a third value between 0 and 1. 0 will make the output value equivalent to value A, 1 will make the output value equivalent to B. 0.5 will return a value exactly between the two, and so on. To smoothly move a character between point A and B, each step you'd use something like:
GML:
pos = lerp(posA,posB,blendAmount);
blendAmount += 0.1;
When blendAmount >= 1, the character has reached the destination position. Increasing blendAmount by 0.1 means it will take 10 frames to complete the move - using a smaller or larger value will cause the animation to take more or less time.

Put it all together: when the character isn't moving and the player presses a button, determine what the character's X and Y positions should be after completing the corresponding move. Store that, along with the current location. Set a blend value to 0.
Each step the character is moving, use lerp to blend the starting x/y positions with the destination x/y positions to get the animated position. Increase the blend value by a small amount. When the blend value is greater than or equal to 1, the character has reached it's destination position and is no longer moving. To be safe, at this point you should manually set the character's X/Y position to the destination position - it's possible to overshoot if blendAmount is greater than 1. The character is no longer moving and is ready to accept further input.

There are some alternatives to lerp - when the player presses a move button you could instantly pop the character to the new position, change the sprite to a 16-frame animation, and prevent additional movements until the animation is complete - but they're all going to hinge on tracking the player's movement state and only accepting input when their character isn't moving. Going the lerp route will give more flexibility, especially if you can get comfortable enough to enhance the straight lerp with animation curves.
Thanks for your response. Pokemon movement is a very accurate description for what I am looking for. My inspiration is Final Fantasy Adventure for the Game Boy. 8x8 rooms with 32x32 pixel sprites. Very basic since this is my first game ever.

I am still quite confused as to what actual code goes where to serve the functions you are describing. The attached code is what I was able to put together after reading your post and going to other forums to figure out how to get object position, determine if movement = true, etc. I'm sorry if I come across as a total noob, but math in paragraph form is very hard for me. I understand that you are trying to help me get the code myself, which I appreciate. I'm just not getting it fully. Here is my logic of the code I wrote:

The x position of obj_Sum is stored in xpos variable.
The y position of obj_Sumo is stored in ypos variable.
If the xpos and ypos do equal the previous frames position, the variable moved is set to false.
If moved equals false, do the following if statement
- if keyboard key left is pressed do the following if statement
- store the destination position (xposB) as the current position -16
- use lerp to take the new xpos to equal the xpos and xposB blended to 1

This doesn't cause any movement. I know I am missing a few key takeaways from your post. Thanks again for all of your help so far.

GML:
xpos = obj_Sumo.x;
ypos = obj_Sumo.y;

if xpos == xprevious && ypos == yprevious
{
    moved = false;   
}


if moved = false
{

    if(keyboard_check(vk_left))
    {
        xposB = xpos - 16;
        xpos = lerp(xpos,xposB,1);
    }

}
 
Good instincts just doing one direction first! However, it does seem like I didn't do a great job of explaining the logic of how this all will work.

Let's start with the basics: we'll track if obj_Sumo is currently moving with the variable moving. In the creation event, set moving to false. Also initialize the variables prevX, prevY, targetX, and targetY to obj_Sumo's x and y positions. Don't use xprevious or yprevious: those track where it was on the last step. We don't care where it was last step, we care where it was at the start of the animation, and where it will be at the end of the animation. Initialize animBlend to 0.

If obj_Sumo is NOT moving, check if any keys are pressed. If a key is pressed, moving is true, we set prevX and prevY to the current x/y position, and calculate targetX and targetY, the position we want obj_Sumo to have once the animation is complete.

See if you can get all that in code first, then move on to lerp. I'll give you a hint there in advance: lerp(xpos,xposB,1) will always return an exact copy of xposB. The last value, the blend value, needs to change every step.

I'm not going to write the code out - this is fairly basic stuff, and lots of other stuff in your game is going to hinge on it. You need to fully understand how it works if you're going to build other code off it.
 
Last edited:
Good instincts just doing one direction first! However, it does seem like I didn't do a great job of explaining the logic of how this all will work.

Let's start with the basics: we'll track if obj_Sumo is currently moving with the variable moving. In the creation event, set moving to false. Also initialize the variables prevX, prevY, targetX, and targetY to obj_Sumo's x and y positions. Don't use xprevious or yprevious: those track where it was on the last step. We don't care where it was last step, we care where it was at the start of the animation, and where it will be at the end of the animation. Initialize animBlend to 0.

If obj_Sumo is NOT moving, check if any keys are pressed. If a key is pressed, moving is true, we set prevX and prevY to the current x/y position, and calculate targetX and targetY, the position we want obj_Sumo to have once the animation is complete.

See if you can get all that in code first, then move on to lerp. I'll give you a hint there in advance: lerp(xpos,xposB,1) will always return an exact copy of xposB. The last value, the blend value, needs to change every step.

I'm not going to write the code out - this is fairly basic stuff, and lots of other stuff in your game is going to hinge on it. You need to fully understand how it works if you're going to build other code off it.
I think I am getting closer. Here's what I have so far. I still am not sure what the value of the of lerp() should be. What this currently does is tell Sumo to look left, move exactly 16 pixels to the left and stop. If I add a Sumomove = false; after the x = targetX, the movement is smooth but very fast. I have very quickly hit the left arrow to get Sumo move the 16 pixels. Am I on the right track?

GML:
//Create

SumoMoving = false;
prevX = obj_Sumo.x
prevY = obj_Sumo.y;
targetX = obj_Sumo.x;
targetY = obj_Sumo.y;
animBlend = 0;
image_speed = 0;

// Step
if SumoMoving = false and keyboard_check(vk_left)
    {
    SumoMoving = true;
    prevX = obj_Sumo.x;
    targetX = obj_Sumo.x - 16;
    x = targetX
    image_speed = 1;
    image_index = 0;
    sprite_index = spr_Sumo_mvnt_L;
    }
 
Yeah, you're getting there.

Going back to what lerp does, imagine a ruler. On one end is 0 inches, the other end is 12 inches. You want the number in the middle of the ruler, lerp(0,12,0.5) = 6. You want the number 25 percent of the way across the ruler, lerp(0,12,0.25) = 3. You want the number 75 percent of the way, lerp(0,12,0.75) = 9. You can use a yardstick instead of a ruler, in which case lerp(0,36,0.75) = 27. If you had half a ruler, you could still use lerp to get the number in the middle: lerp(6,12,0.75) = 10.5.

To smoothly move Sumo between the start point and end point, you'll add a little bit to animBlend each step of the movement animation. If you want the movement animation to take 16 steps, you'll add 1/16th to animBlend each step, and use it as the blend value in lerp to get the desired x position between prevX and targetX. This means you won't change Sumo's x position when the key is pressed - you'll simply set moving to true, and calculate the final move position. The new position will be set with lerp() in the code block ran when Sumo is moving.

What you're doing with lerp is saying, "Make the X position this much between the starting X position and the finishing X position." Each step, you update how much this much is, until it's all the way across.
 
Last edited:
Yeah, you're getting there.

Going back to what lerp does, imagine a ruler. On one end is 0 inches, the other end is 12 inches. You want the number in the middle of the ruler, lerp(0,12,0.5) = 6. You want the number 25 percent of the way across the ruler, lerp(0,12,0.25) = 3. You want the number 75 percent of the way, lerp(0,12,0.75) = 9. You can use a yardstick instead of a ruler, in which case lerp(0,36,0.75) = 27. If you had half a ruler, you could still use lerp to get the number in the middle: lerp(6,12,0.75) = 10.5.

To smoothly move Sumo between the start point and end point, you'll add a little bit to animBlend each step of the movement animation. If you want the movement animation to take 16 steps, you'll add 1/16th to animBlend each step, and use it as the blend value in lerp to get the desired x position between prevX and targetX. This means you won't change Sumo's x position when the key is pressed - you'll simply set moving to true, and calculate the final move position. The new position will be set with lerp() in the code block ran when Sumo is moving.

What you're doing with lerp is saying, "Make the X position this much between the starting X position and the finishing X position." Each step, you update how much this much is, until it's all the way across.

I do get the point of lerps function. I have tried the code below, but it acts like a slow movement speed with per pixel movement. I also understand how getting the animBlend = 0 again will help trigger the movement via keypress to not be constant, and to wait for the amiBend to hit 0 before another key press will be allowed to control the next 16 pixels of movement. What I am having a hard time visualizing is the animBlend being a variable. I have tried just making it 1/16 as a fraction, but it just creates the slow movement described. I have tried variations of prevX /16 or targetX *.0625 to make it a variable to no avail. I'm just not getting the animBlend part of the lerp function. If I can figure out how the blend actually works, I think I'll be able to get this working. Thanks again for being patient with me as I figure this out.

GML:
if SumoMoving = false and keyboard_check(vk_left)
    {
    SumoMoving = true;
    prevX = obj_Sumo.x;
    targetX = obj_Sumo.x - 16;
    animBlend = .0625;
    x = lerp(prevX, targetX, animBlend);
    image_speed = 1;
    image_index = 0;
    sprite_index = spr_Sumo_mvnt_L;
    SumoMoving = false;

    }
 
I'm just not getting the animBlend part of the lerp function. If I can figure out how the blend actually works, I think I'll be able to get this working. Thanks again for being patient with me as I figure this out.
Lerp

the <AnimBlend>, as you named it, is just the percentage of the way you will 'travel'.
E.g.:
GML:
n = lerp(0, 10, 0.5) ;             // n will be 5, because (10-0)*0.5 = 5
n = lerp(10, 30, 2)                // n will be 20, because (30-10)*2 = 50
*****************************************************************
Most useful tip ever:
Middle mouse-click on any function you're not sure about in the IDE.
*****************************************************************
 

Macaco

Member
I do get the point of lerps function. I have tried the code below, but it acts like a slow movement speed with per pixel movement. I also understand how getting the animBlend = 0 again will help trigger the movement via keypress to not be constant, and to wait for the amiBend to hit 0 before another key press will be allowed to control the next 16 pixels of movement. What I am having a hard time visualizing is the animBlend being a variable. I have tried just making it 1/16 as a fraction, but it just creates the slow movement described. I have tried variations of prevX /16 or targetX *.0625 to make it a variable to no avail. I'm just not getting the animBlend part of the lerp function. If I can figure out how the blend actually works, I think I'll be able to get this working. Thanks again for being patient with me as I figure this out.

GML:
if SumoMoving = false and keyboard_check(vk_left)
    {
    SumoMoving = true;
    prevX = obj_Sumo.x;
    targetX = obj_Sumo.x - 16;
    animBlend = .0625;
    x = lerp(prevX, targetX, animBlend);
    image_speed = 1;
    image_index = 0;
    sprite_index = spr_Sumo_mvnt_L;
    SumoMoving = false;

    }
You initialized correctly, but you forgot to say SumoMoving = true; Later you have to go to the other part:

Code:
if SumoMoving == true {
    //--moviment here
    animBlend += 0.0625;
    x = lerp(prevX, targetX, animBlend);

   //--Condition to exit SumoMoving == true

   //--...
}
In the condition you can do in two ways: by space or by time.

By space it checks it is already where it should be.
By time it checks it moved long enough. You sad it walks 1 pixel/frame, so it takes 16 frames to get there.

I prefer the second one, but it is up to you.

Be careful to keep the movement longer if the key is still pressed.
 

chamaeleon

Member
GML:
if SumoMoving = false and keyboard_check(vk_left)
    {
    SumoMoving = true;
    prevX = obj_Sumo.x;
    targetX = obj_Sumo.x - 16;
    animBlend = .0625;
    x = lerp(prevX, targetX, animBlend);
    image_speed = 1;
    image_index = 0;
    sprite_index = spr_Sumo_mvnt_L;
    SumoMoving = false;
    }
GML:
if (some_variable == false) {
    some_variable = true;
    ...
    some_variable = false;
}
This code will most certainly not do what you want. Writing code this way would seem to indicate you are unfamiliar with the event model, and how all code in an event will be executed in the current step (unless one skips some of it or exit out of the event. You don't set up variables and hope GMS does what you want (unless you are explicitly working with the built-in variables like speed, direction, hspeed, vspeed, etc.) You need to write your code in such a way that you handle all required state changes (in this case the variables representing whether movement currently taking place, how far it has to move, etc.) and update this information step after step.
GML:
if (!SumoMoving && keyboard_check(vk_left)) { // or keyboard_check_pressed() if one has to stop pressing and press again to move the next 16 pixels
    SumoMoving = true;
    startX = x;
    targetX = x - 16;
    animBlend = 0;
} else if (SumoMoving) {
    animBlend += 0.0625;
    x = lerp(startX, targetX, animBlend);
    if (x <= targetX) {
        x = targetX;
        SumoMoving = false;
    }
}
Every step, if the instance not in the movement state, if not moving and the key was pressed, set up the starting state data and switch to the movement state.
Every step, if the instance is in the movement state, it will update the fraction for the lerp() computation, and if x has reached or moved past the target, switch to the non-movement state.
 
GML:
if (some_variable == false) {
    some_variable = true;
    ...
    some_variable = false;
}
This code will most certainly not do what you want. Writing code this way would seem to indicate you are unfamiliar with the event model, and how all code in an event will be executed in the current step (unless one skips some of it or exit out of the event. You don't set up variables and hope GMS does what you want (unless you are explicitly working with the built-in variables like speed, direction, hspeed, vspeed, etc.) You need to write your code in such a way that you handle all required state changes (in this case the variables representing whether movement currently taking place, how far it has to move, etc.) and update this information step after step.
GML:
if (!SumoMoving && keyboard_check(vk_left)) { // or keyboard_check_pressed() if one has to stop pressing and press again to move the next 16 pixels
    SumoMoving = true;
    startX = x;
    targetX = x - 16;
    animBlend = 0;
} else if (SumoMoving) {
    animBlend += 0.0625;
    x = lerp(startX, targetX, animBlend);
    if (x <= targetX) {
        x = targetX;
        SumoMoving = false;
    }
}
Every step, if the instance not in the movement state, if not moving and the key was pressed, set up the starting state data and switch to the movement state.
Every step, if the instance is in the movement state, it will update the fraction for the lerp() computation, and if x has reached or moved past the target, switch to the non-movement state.

Thank you for your response. You are correct. As the first post indicates, I am brand new to coding. I didn't realize the movement I was going for was going to be so complicated vs the standard 360 movement that most people will use in their games.

I am starting to get a fuller picture of what the code is doing, and why it is doing it. The animBlend += 0 was what I was missing. I needed to a 0.0625 per frame which is how it is "variable". I knew an if statement was needed to complete the stop movement, but without understanding what/why to put into the animBlend value, I was stuck.

I tried testing with both left and right movements with some modification to the right movement, but the left/right movement code now seem to interfere with each other. I think it is because of how the if statements are arranged. If I comment out the left movement if statement, the right works. If I comment out the right, the left works.



GML:
if (!SumoMoving && keyboard_check(vk_left)) { // or keyboard_check_pressed() if one has to stop pressing and press again to move the next 16 pixels
    SumoMoving = true;
    startX = x;
    targetX = x - 16;
    animBlend = 0;
    sprite_index = spr_Sumo_mvnt_L;
    image_speed = 1;
} else if (SumoMoving) {
    animBlend += 0.0625;
    x = lerp(startX, targetX, animBlend);
    if (x <= targetX) {
        x = targetX;
        SumoMoving = false;
        image_speed = 0;
    }
}

if (!SumoMoving && keyboard_check(vk_right))
{ // or keyboard_check_pressed() if one has to stop pressing and press again to move the next 16 pixels
    SumoMoving = true;
    startX = x;
    targetX = x + 16;
    animBlend = 0;
    sprite_index = spr_Sumo_mvnt_R;
    image_speed = 1;
} else if (SumoMoving) {
    animBlend += 0.0625;
    x = lerp(startX, targetX, animBlend);
    if (x >= targetX) {
        x = targetX;
        SumoMoving = false;
        image_speed = 0;
    }
}
 

chamaeleon

Member
Try to reuse code for both movements instead of duplicating. Right now, the code is going to move right if it is moving left (since the condition over SumoMoving is the same for both left and right). Instead of "hard coding" direction into different code blocks, perhaps you can code direction using the variables instead.
GML:
var dir = keyboard_check(vk_right) - keyboard_check(vk_left); // 1 if only vk_right, -1 if only vk_left, 0 if both or neither
if (!SumoMoving && dir != 0) {
    SumoMoving = true;
    startX = x;
    targetX = x + 16 * dir;
    animBlend = 0;
    sprite_index = spr_Sumo_mvnt_L;
    image_speed = 1;
} else if (SumoMoving) {
    animBlend += 0.0625;
    x = lerp(startX, targetX, animBlend);
    if (animBlend >= 1) { // fixed to account for approaching from both left and right
        x = targetX;
        SumoMoving = false;
        image_speed = 0;
    }
}
Edit: The alternative would be to have two different booleans, SumoMovingLeft and SumoMovingRight, to allow the code blocks to not interfere with each other, and only allow one of them to be true at a time, etc.
 
Last edited:
GML:
var dir = keyboard_check(vk_right) - keyboard_check(vk_left); // 1 if only vk_right, -1 if only vk_left, 0 if both or neither
if (!SumoMoving && dir != 0) {
    SumoMoving = true;
    startX = x;
    targetX = x + 16 * dir;
    animBlend = 0;
    sprite_index = spr_Sumo_mvnt_L;
    image_speed = 1;
} else if (SumoMoving) {
    animBlend += 0.0625;
    x = lerp(startX, targetX, animBlend);
    if (animBlend >= 1) { // fixed to account for approaching from both left and right
        x = targetX;
        SumoMoving = false;
        image_speed = 0;
    }
}
Couple things for @hyrule_3333 to improve on once it's working:

- With this exact code, the character won't move if the player is pressing a key. It won't start until the player releases the key, and if the player presses a key during movement, the character will stop. sorry, nevermind, long day.

- Additionally, there will be a delay of at least one step between the player pressing the button, and the movement starting. It would feel a little snappier, especially for an action game, if the movement started on the same step. You could fix both by checking both "if" statements independently. This will result in some wasted checks each step, but only enough to bug CS nerds, not enough to actually affect performance in any way.

- The code that moves the character left and right can also move the character up and down with a minor addition.
 

TheouAegis

Member
FFA didn't move 16 pixels at a time. You could stop mid-tile. That's why the whip made you shift slightly. I think the charged sword also shifted you. FFA was as freestyled as LoZ and Bomberman were (but not as free as Pac-man). The only tricky aspect of movement in any of those games is rounding corners.
 
FFA didn't move 16 pixels at a time. You could stop mid-tile. That's why the whip made you shift slightly. I think the charged sword also shifted you. FFA was as freestyled as LoZ and Bomberman were (but not as free as Pac-man). The only tricky aspect of movement in any of those games is rounding corners.
That would be 16 pixels. One tile is 32x32 in my color and upscaled version of the game. By allowing him to stop mid tile is a 16-pixel movement.
 
Try to reuse code for both movements instead of duplicating. Right now, the code is going to move right if it is moving left (since the condition over SumoMoving is the same for both left and right). Instead of "hard coding" direction into different code blocks, perhaps you can code direction using the variables instead.
GML:
var dir = keyboard_check(vk_right) - keyboard_check(vk_left); // 1 if only vk_right, -1 if only vk_left, 0 if both or neither
if (!SumoMoving && dir != 0) {
    SumoMoving = true;
    startX = x;
    targetX = x + 16 * dir;
    animBlend = 0;
    sprite_index = spr_Sumo_mvnt_L;
    image_speed = 1;
} else if (SumoMoving) {
    animBlend += 0.0625;
    x = lerp(startX, targetX, animBlend);
    if (animBlend >= 1) { // fixed to account for approaching from both left and right
        x = targetX;
        SumoMoving = false;
        image_speed = 0;
    }
}
Edit: The alternative would be to have two different booleans, SumoMovingLeft and SumoMovingRight, to allow the code blocks to not interfere with each other, and only allow one of them to be true at a time, etc.
Thank you. I also have to figure out up/down as well as how to get the sprite movement to match the direction. By combining the two directions, it is making it harder for me to figure out how to accomplish these two actions. Because I am a total beginner, I am more comfortable with each direction having its own code that doesn't rely other directional code. I am still digesting this code and trying to figure out the logic as well as what GameMaker is doing as the code is executed. If I try to use the left/right code to make up and down code with minor adjustments, Sumo starts to wobble up/down or left/right vs going straight up/down or left/right.

GML:
var dir = keyboard_check(vk_right) - keyboard_check(vk_left); // 1 if only vk_right, -1 if only vk_left, 0 if both or neither
if (!SumoMoving && dir != 0) {
    SumoMoving = true;
    startX = x;
    targetX = x + 16 * dir;
    animBlend = 0;
    
}

    
 else if (SumoMoving) {
    animBlend += 0.15;
    x = lerp(startX, targetX, animBlend);
    if (animBlend >= 1) { // fixed to account for approaching from both left and right
        x = targetX;
        SumoMoving = false;
        image_speed = 0;
    }
}

if (targetX > startX)
{
    sprite_index = spr_Sumo_mvnt_R;
    image_speed = 1;
}
    else if (targetX < startX)
    {
    sprite_index = spr_Sumo_mvnt_L;
    image_speed = 1;
    }
    
    else if ( x = targetX)
    {
    image_speed = 0;   
    }

    
var dir2 = keyboard_check(vk_down) - keyboard_check(vk_up); // 1 if only vk_right, -1 if only vk_left, 0 if both or neither
if (!SumoMoving2 && dir2 != 0) {
    SumoMoving2 = true;
    startY = y;
    targetY = y + 16 * dir2;
    animBlend2 = 0;
    
}

    
 else if (SumoMoving2) {
    animBlend2 += 0.15;
    y = lerp(startY, targetY, animBlend2);
    if (animBlend2 >= 1) { // fixed to account for approaching from both left and right
        y = targetY;
        SumoMoving2 = false;
        image_speed = 0;
    }
}
if (targetY > startY)
{
    sprite_index = spr_Sumo_mvnt_D;
    image_speed = 1;
}
    else if (targetY < startY)
    {
    sprite_index = spr_Sumo_mvnt_U;
    image_speed = 1;
    }
    
    else if ( y = targetY)
    {
    image_speed = 0;   
    }
 

TheouAegis

Member
You may want to merge the targetX>startX et al and targetY>startY et al blocks. Arre your Sprites even animating when you walk? It looks to me like image_speed will always be 0 when moving horizontally. Also if moving left or right, you may want to exit the code, or at least tell it to ignore the vertical code if moving horizontally.

And your SumoMoving check in the horizontal code is what is resetting your vertical movement every step.
 
Top