• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GameMaker Chaging sprite based on direction [SOLVED]

PlayerOne

Member
Can't tell you how many times I've read this over and over again but for some reason it wont work; It's rather straight forward. Looking to change the sprite based on the direction its moving.

Code:
    switch(point_direction(xprevious,yprevious,x,y))
    {
    
        case 0:   sprite_index=sPlayerRight_Outfit0;    shooting=0;    break;
        case 90:  sprite_index=sPlayerUp_Outfit0;       shooting=90;   break;
        case 180: sprite_index=sPlayerLeft_Outfit0;     shooting=180;  break;
        case 270: sprite_index=sPlayerDown_Outfit0;     shooting=270;  break;
        
        
        case 225: sprite_index=sPlayerDownLeft_Outfit0;  shooting=225; break;
        case 135: sprite_index=sPlayerUpLeft_Outfit0;    shooting=135; break;
        case 315: sprite_index=sPlayerDownright_Outfit0; shooting=315; break;
        case 45:  sprite_index=sPlayerUpRight_Outfit0;   shooting=45;  break;
        
        default: sprite_index=sFire_VeryBig; shooting=360 break;
    }
Why wont this snippet of code change the sprite when moving?
 

Pixel-Team

Master of Pixel-Fu
You can start by using show_debug-message() to show what point_direction is actually being passed in. It could be that it is none in your case statement.
 

PlayerOne

Member
You can start by using show_debug-message() to show what point_direction is actually being passed in. It could be that it is none in your case statement.
I did one better. I used the draw_text() function to tell me where the direction of the object is going. Again it points in the correct direction when moving but wont change sprite regardless of movement.

Edit: Used debug message and it showed the direction but wont change sprites.
 

Pixel-Team

Master of Pixel-Fu
Assuming it's passing in the correct direction, also make sure that the image_index is within the range of the specified sprite index's frame count. I've had problems switching sprites without setting the image index. Try setting the image index to 1 just to make sure.
 

PlayerOne

Member
Assuming it's passing in the correct direction, also make sure that the image_index is within the range of the specified sprite index's frame count. I've had problems switching sprites without setting the image index. Try setting the image index to 1 just to make sure.
I'm using test sprites, single image only. Don't see how image_index could be the problem there.

Edit: Tried setting it to 0. Nothing.
 

Pixel-Team

Master of Pixel-Fu
In the spirit of playing 20 questions rather than seeing your game project, here are a couple more:

Have you put a breakpoint on one of your case statements to make sure it's firing?

Do you have any other scripts that may be overriding this script's setting of the sprite index?

The default case statement looks suspicious. Have you tried to remove it and see what happens?
 

TheouAegis

Member
switch round(point_direction(xprevious,yprevious,x,y))

Make sure you're actually getting an integer returned. if even after this edit it still doesn't work, that suggests you have code somewhere else in your project that is resetting the Sprite after that switch has run.

Also, that code needs to be run in the End Step event or the Predraw Event.
 

PlayerOne

Member
In the spirit of playing 20 questions rather than seeing your game project, here are a couple more:

Have you put a breakpoint on one of your case statements to make sure it's firing?

Do you have any other scripts that may be overriding this script's setting of the sprite index?

The default case statement looks suspicious. Have you tried to remove it and see what happens?
1) Yes. It's what I posted (see original post)
2) New project. No Scripts.
3) Default statement is something for debugging and doesn't have issue.
 

PlayerOne

Member
switch round(point_direction(xprevious,yprevious,x,y))

Make sure you're actually getting an integer returned. if even after this edit it still doesn't work, that suggests you have code somewhere else in your project that is resetting the Sprite after that switch has run.

Also, that code needs to be run in the End Step event or the Predraw Event.
I checked for any sprite indexes in the code and mind this is a new project I just now started to work on the player character. I used round like you suggested and no it didn't work.

Whats odd is that the default case in the switch statement isn't being used since round is in the code which indicates that only 0 (case right) is being inputted into the switch statement and nothing else.

EDIT 1: I should also mention there 9 uses of sprite_index and there ALL in the player object specifically in the switch statement.

EDIT 2: I put the point_direction into an object variable and continues to return 0. I don't understand why this is.
 
Last edited:

TheouAegis

Member
I checked for any sprite indexes in the code and mind this is a new project I just now started to work on the player character. I used round like you suggested and no it didn't work.

Whats odd is that the default case in the switch statement isn't being used since round is in the code which indicates that only 0 (case right) is being inputted into the switch statement and nothing else.

EDIT 1: I should also mention there 9 uses of sprite_index and there ALL in the player object specifically in the switch statement.

EDIT 2: I put the point_direction into an object variable and continues to return 0. I don't understand why this is.
Did you put it in the END STEP EVENT like I said?
 

Pixel-Team

Master of Pixel-Fu
1) Yes. It's what I posted (see original post)
What I meant by breakpoint is not what you showed in your original post, but perhaps opening up one of your case statements into a couple lines, and putting a DEBUG breakpoint on one of those lines, so that the game will hit that line and pause on it. The run the game in debug mode, (F6) and try to press up and get the debugger to break on that line. Like this.

GML:
case 90:
sprite_index=sPlayerUp_Outfit0; //put a breakpoint on this line
shooting=90;  
break;
If you push up, and the debugger does not stop on that line, that would rule out a problem with switching sprites, and you could focus more on how you calculate direction. Actually, if you did this with every case, you could see if any of them are being hit.
 

Nidoking

Member
Put xprevious, yprevious, x, and y in your debug print. Make sure you're actually calculating based on some actual movement.
 

PlayerOne

Member
Did you put it in the END STEP EVENT like I said?
Yes and didn't make a difference.

What I meant by breakpoint is not what you showed in your original post, but perhaps opening up one of your case statements into a couple lines, and putting a DEBUG breakpoint on one of those lines, so that the game will hit that line and pause on it. The run the game in debug mode, (F6) and try to press up and get the debugger to break on that line. Like this.

GML:
case 90:
sprite_index=sPlayerUp_Outfit0; //put a breakpoint on this line
shooting=90; 
break;
If you push up, and the debugger does not stop on that line, that would rule out a problem with switching sprites, and you could focus more on how you calculate direction. Actually, if you did this with every case, you could see if any of them are being hit.
I put a break point in the switch and nothing happened it didn't stop the game when running in debug mode.
 

TheouAegis

Member
Yes and didn't make a difference.



I put a break point in the switch and nothing happened it didn't stop the game when running in debug mode.
Does your object have any Draw events? If so, what's in those Draw events?


Breakdown (before I head to work):
The variables xprevious and yprevious are set to x and y respectively in the Begin Step event, so they can be referenced any time after you change x or y. The easiest way to ensure this happens is to only modify x and y in the Step event and only read xprevious and yprevious in the End Step event or Predraw Event (in the case that further modifications are made in the End Step event, such as following instances).

If you are drawing the sprite in the Draw events using any of the draw_sprite* functions, make sure you use sprite_index for the first argument.
 

PlayerOne

Member
Does your object have any Draw events? If so, what's in those Draw events?
This is all there is:

Code:
draw_self();

draw_text(x+0,y+0,string("_dir:  ")+string(_dir))
draw_text(x+0,y+25,string("Move:  ")+string(point_direction(xprevious,yprevious,x,y)))
draw_text(x+0,y+50,string("Xprev:  ")+string(xprevious))
draw_text(x+0,y+75,string("Yprev:  ")+string(yprevious))
draw_text(x+0,y+100,string("XX:  ")+string(x))
draw_text(x+0,y+125,string("YY:  ")+string(y))
This is a new project. No scripts or anything that can get in the way of the switch statement.
 

TheouAegis

Member
Ok, draw_self() is fine.

Try this for the switch condition:

switch (point_direction(xprevious,yprevious,x,y) div 45 * 45)

And make sure it's still in the End Step or Predraw events.
 
L

Lunnig149

Guest
Had a similar problem once. Maybe try the following:

1) Prob you already checked for but sometimes it's the obvious stuff xD. How do you know that the compination of two points (x , y) and (xprevious , yprevious ) leads to one of the angle you have defined?)

Make sure to "round" your angle to one of the values you have cases for AND that the angle is has not an addend of 360 in it:
Code:
           var _angle = point_direction(xprevious, yprevious , x , y);
                _angle = (((360 + 0.5*45 + _angle) div 45) * 45; /// the section (360 + 0.5 * 45 + _angle) can be written as (382.5 + _angle) but that is not as conclusive as the idea behind the calculation
                _angle = _angle mod 360;

switch (_angle) {
   case   0: {...} break;
   case  45: {...} break;
   case  90: {...} break;
etc.
.
.
.
}

2) Use set variables for xprevious and yprevious at custom points right before the movement is done in the specific frame. (Since resetting xprevious and yprevious is possible with custom variables and usally done at before the begin step event)

Let's see your movement code.
+1 on that show the code :) add the section of xprevious and yprevious as well.
 

PlayerOne

Member
Ok, draw_self() is fine.

Try this for the switch condition:

switch (point_direction(xprevious,yprevious,x,y) div 45 * 45)

And make sure it's still in the End Step or Predraw events.
Here is the thing: In the draw event there 2 strings if you look at _dir in the strings to states that it returns 0.

Code:
draw_text(x+0,y+0,string("_dir:  ")+string(_dir)) // <<< _dir returns 0.
draw_text(x+0,y+25,string("Move:  ")+string(point_direction(xprevious,yprevious,x,y))) // <<< This returns a number. always.
//=======================================


Let's see your movement code.
Here.

Code:
if global.player_hp>=0
{

//Movement (left or right)
key_left = -max(0,keyboard_check(vk_left),keyboard_check(ord("A")));
key_right =  max(0,keyboard_check(vk_right),keyboard_check(ord("D")));
key_up =  -max(0,keyboard_check(vk_up),keyboard_check(ord("W")));
key_down = max(0,keyboard_check(vk_down),keyboard_check(ord("S")));

move_hsp=(key_left)+(key_right)
move_vsp=(key_up)+(key_down)
      
//Movement
hsp=move_hsp*movespeed;
vsp=move_vsp*movespeed;

_dir=(point_direction(xprevious,yprevious,x,y)) // This returns 0 for some reason.

}
//===========================================

Had a similar problem once. Maybe try the following:

1) Prob you already checked for but sometimes it's the obvious stuff xD. How do you know that the compination of two points (x , y) and (xprevious , yprevious ) leads to one of the angle you have defined?)

Make sure to "round" your angle to one of the values you have cases for AND that the angle is has not an addend of 360 in it:
Code:
           var _angle = point_direction(xprevious, yprevious , x , y);
                _angle = (((360 + 0.5*45 + _angle) div 45) * 45; /// the section (360 + 0.5 * 45 + _angle) can be written as (382.5 + _angle) but that is not as conclusive as the idea behind the calculation
                _angle = _angle mod 360;

switch (_angle) {
   case   0: {...} break;
   case  45: {...} break;
   case  90: {...} break;
etc.
.
.
.
}

2) Use set variables for xprevious and yprevious at custom points right before the movement is done in the specific frame. (Since resetting xprevious and yprevious is possible with custom variables and usally done at before the begin step event)


+1 on that show the code :) add the section of xprevious and yprevious as well.
Tried it and it returns 0.


Just using point_direction(xprevious, yprevious , x , y) in the step event returns 0, with the exception in the draw event.
 

TheouAegis

Member
You missed my edit...


Breakdown (before I head to work):
The variables xprevious and yprevious are set to x and y respectively in the Begin Step event, so they can be referenced any time after you change x or y. The easiest way to ensure this happens is to only modify x and y in the Step event and only read xprevious and yprevious in the End Step event or Predraw Event (in the case that further modifications are made in the End Step event, such as following instances).
Just use point_direction(0,0,hsp,vsp)
 

Yal

🐧 *penguin noises*
GMC Elder
Even better than just int:ing the direction, divide it by 45, round that, and then multiply by 45. Now you're guaranteed the direction is one of the 45-degree increments you're using in the switch statement.
 

TheouAegis

Member
We tried rounded division (twice) and he said it didn't work for some reason.

He's trying to base the sprite on the direction he's moving, which as can be seen in his last code he posted, is defined by the vectors hsp and vsp. So all he needs to do is set the sprite based on those two vectors.

point_direction(0,0,hsp,vsp)
 

Yal

🐧 *penguin noises*
GMC Elder
There's a pretty wide spectrum of "it doesn't work" between "results are slightly off" and "running the code makes your entire town die from radiation poisoning" so knowing how it doesn't work would've been handy.

One thing that comes to mind is that the division results will snap to your rounding thresholds instead of the center (where the interesting angles are) so you could add half the value and use an unidirectional rounding to solve this:

roundang = 45*( (ang + 22.5) div 45 );
 

PlayerOne

Member
This code works:

Code:
 var _angle = point_direction(xprevious, yprevious , x , y);
_angle = (((360 + 0.5*45 + _angle) div 45) * 45;)
_angle = _angle mod 360;
This code works with paths. thanks @Lunnig149 !!!
 
Top