SOLVED Walk Sprites into Idle Sprites with Correct Directions

ERK

Member
I started following this tutorial and wanted to resolve something before continuing.


Around the 3:46 mark, she mentions that if you're using a different sprite for idle, then to use another switch statement.

So, I tried this and my player always faces to the right when going idle.

GML:
// Movement
hInput = keyRight - keyLeft;
vInput = keyDown - keyUp;

dir = point_direction(0,0,hInput,vInput);

if (hInput != 0 or vInput != 0)
{
    moveX = lengthdir_x(spd, dir);
    moveY = lengthdir_y(spd, dir);
 
    x += moveX;
    y += moveY;
 
    // Set Sprite
    switch(dir)
    {
        case 0: sprite_index = sPlayer_Walk_R; break;
        case 90: sprite_index = sPlayer_Walk_U; break;
        case 180: sprite_index = sPlayer_Walk_L; break;
        case 270: sprite_index = sPlayer_Walk_D; break;
    }
 
    image_speed = 0.4;
}

else
{
    // Set Sprite
    switch(dir)
    {
        case 0: sprite_index = sPlayer_Idle_R; break;
        case 90: sprite_index = sPlayer_Idle_U; break;
        case 180: sprite_index = sPlayer_Idle_L; break;
        case 270: sprite_index = sPlayer_Idle_D; break;
    }
 
    image_speed = 0.4;
}
Any ideas, why the idle switch statement isn't working? Thank you!
 
Last edited:

ERK

Member
I tried it like this, with the same result.


GML:
// Movement
hInput = keyRight - keyLeft;
vInput = keyDown - keyUp;

if (hInput != 0 or vInput != 0)
{
    dir = point_direction(0,0,hInput,vInput);
    moveX = lengthdir_x(spd, dir);
    moveY = lengthdir_y(spd, dir);
    
    x += moveX;
    y += moveY;
    
    // Set Sprite
    switch(dir)
    {
        case 0: sprite_index = sPlayer_Walk_R; break;
        case 90: sprite_index = sPlayer_Walk_U; break;
        case 180: sprite_index = sPlayer_Walk_L; break;
        case 270: sprite_index = sPlayer_Walk_D; break;
    }
    
    image_speed = 0.4;
}

else
{   
    dir = point_direction(0,0,0,0);
    
    // Set Sprite
    switch(dir)
    {
        case 0: sprite_index = sPlayer_Idle_R; break;
        case 90: sprite_index = sPlayer_Idle_U; break;
        case 180: sprite_index = sPlayer_Idle_L; break;
        case 270: sprite_index = sPlayer_Idle_D; break;
    }
    
    image_speed = 0.4;
}
 

ERK

Member
Got it working! Just had to store the last direction before going into the idle.


GML:
// Movement
hInput = keyRight - keyLeft;
vInput = keyDown - keyUp;

if (hInput != 0 or vInput != 0)
{
    dir = point_direction(0,0,hInput,vInput);
    moveX = lengthdir_x(spd, dir);
    moveY = lengthdir_y(spd, dir);
    
    x += moveX;
    y += moveY;
    
    // Set Sprite
    switch(dir)
    {
        case 0: sprite_index = sPlayer_Walk_R; lastdir = "right"; break;
        case 90: sprite_index = sPlayer_Walk_U; lastdir = "up"; break;
        case 180: sprite_index = sPlayer_Walk_L; lastdir = "left"; break;
        case 270: sprite_index = sPlayer_Walk_D; lastdir = "down"; break;
    }
    
    image_speed = 0.2;
}

else
{   
    // Set Sprite
    switch(lastdir)
    {
        case "right": sprite_index = sPlayer_Idle_R; break;
        case "up": sprite_index = sPlayer_Idle_U; break;
        case "left": sprite_index = sPlayer_Idle_L; break;
        case "down": sprite_index = sPlayer_Idle_D; break;
    }
    
    image_speed = 0.4;
}
And in the Create Event
lastdir = "right";
 

ERK

Member
So, I noticed a new problem!

If you quickly press the keys to walk in a diagonal, the character will slide.
For example, pressing the Right and Up arrow keys at the same time, or the Right and Down. Same thing with the Left arrow and Up or Down.
 

Nidoking

Member
dir = point_direction(0,0,0,0);
No. You don't do this at all. All you had to do was not this. Take it out from your second post. Why are you doing it? You have to understand what you're doing if you want to accomplish something. The whole "lastdir" thing is meaningless. Get rid of it.

If you quickly press the keys to walk in a diagonal, the character will slide.
What does this mean? What is "slide" in this context? What does the character do, and what do you want it to do instead?
 

ERK

Member
I misunderstood your first reply to the problem.

The original problem, was that when the player stops walking, the idle sprite was always facing to the right and not in the last direction the player was moving.

By "slide" I mean that the player gets stuck in it's idle sprite even though the player is moving at a diagonal. Everything seems to work great, until you press Right and Up arrow keys at the same exact time.
Right and Down arrow keys do the same thing, along with Left arrow and Up or Down.

So, I'm back to the start. How can I modify her script to use a different sprite for idle? In my case I have 4 idle sprites (Right, Up, Left, Down).
 

Nidoking

Member
switch(dir) { case 0: sprite_index = sPlayer_Walk_R; lastdir = "right"; break; case 90: sprite_index = sPlayer_Walk_U; lastdir = "up"; break; case 180: sprite_index = sPlayer_Walk_L; lastdir = "left"; break; case 270: sprite_index = sPlayer_Walk_D; lastdir = "down"; break; }
So, here, you've got cases for if the direction is exactly equal to 0, 90, 180, or 270. What is the direction if the player is moving diagonally? What sprite do you want to use?
 

ERK

Member
That makes sense, it's working when using arrow keys or a dpad on a gamepad. However, when using an analog stick, you're able to get outside those degrees and can still cause the "slide" look.


GML:
if (hInput != 0 or vInput != 0)
    {
        dir = point_direction(0,0,hInput,vInput);
        moveX = lengthdir_x(spd, dir);
        moveY = lengthdir_y(spd, dir);
    
        x += moveX;
        y += moveY;
    
        // Set Sprite
        switch(dir)
        {
            case 0: sprite_index = sPlayer_Walk_R; break;
            case 45: sprite_index = sPlayer_Walk_R; break;
            case 90: sprite_index = sPlayer_Walk_U; break;
            case 135: sprite_index = sPlayer_Walk_L; break;
            case 180: sprite_index = sPlayer_Walk_L; break;
            case 225: sprite_index = sPlayer_Walk_L; break;
            case 270: sprite_index = sPlayer_Walk_D; break;
            case 315: sprite_index = sPlayer_Walk_R; break;
        }
        
        image_speed = 0.2;
    }
    
    if !(hInput != 0 or vInput != 0)
    {       
        // Set Sprite
        switch(dir)
        {
            case 0: sprite_index = sPlayer_Idle_R; break;
            case 45: sprite_index = sPlayer_Idle_R; break;
            case 90: sprite_index = sPlayer_Idle_U; break;
            case 135: sprite_index = sPlayer_Idle_L; break;
            case 180: sprite_index = sPlayer_Idle_L; break;
            case 225: sprite_index = sPlayer_Idle_L; break;
            case 270: sprite_index = sPlayer_Idle_D; break;
            case 315: sprite_index = sPlayer_Idle_R; break;
        }
        
        image_speed = 0.2;
    }
So now I'm wondering if there's a way to make the cases to be something like 0>=89 use the Right Sprite, if 90>=179 use the Up Sprite, etc.
 

Padouk

Member
You are so close to your solution!

How about floor(direction/45) your 45,90,134,180 etc into an index?
You can switch case on that... or manage your sprites using an array
1612115338760.png


GML:
sprites_idle    = [spr_Idle_e,   spr_Idle_ne,   spr_Idle_n,   spr_Idle_nw,   spr_Idle_w,   spr_Idle_sw,   spr_Idle_s,   spr_Idle_se];
sprites_walk   = [spr_Walk_e,   spr_Walk_ne,   spr_Walk_n,   spr_Walk_nw,   spr_Walk_w,   spr_Walk_sw,   spr_Walk_s,   spr_Walk_se];

cardinal_direction= floor(((direction+36000+22.5) % 360)/45);

if(walking) {
  //...
  sprite_index = sprites_walk[cardinal_direction];
}
else if(idle) {
  //...
  sprite_index = sprites_idle[cardinal_direction];
}
 
Last edited:
  • Like
Reactions: ERK

ERK

Member
Just to mark this as solved, here's what I ended up going with, in place of the switch statements above.

GML:
if (dir > 45 && dir < 135)
{
    sprite_index = sPlayer_Idle_U;
}
if (dir >= 135 && dir <= 225)
{
    sprite_index = sPlayer_Idle_L;
}
if (dir > 225 && dir < 315)
{
    sprite_index = sPlayer_Idle_D;
}
if ((dir >= 315 && dir < 360) || (dir >= 0 && dir <= 45))
{
    sprite_index = sPlayer_Idle_R;
}
 
Last edited:
Top