• 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!

How To Make An NPC Face You During Interactions?

aisdjioad

Member
I'm trying to use this code but it doesn't work since the x position of my player is ALWAYS lower or higher than the NPC's one. So the code reads it first and doesn't care about the Y position (which is supposed to make the NPC looks up and down).

GML:
if (keyboard_check_pressed(ord("Z"))) && (_check == false)
    {
        if (x < oPlayer.x)
        {
            image_index = 1;       
        }
        else if (x > oPlayer.x)
        {
            image_index = 3;   
        }
        else if (y < oPlayer.y)
        {
            image_index = 2;   
        }
        else if (y > oPlayer.y)
        {
            image_index = 0;   
        }
 

aisdjioad

Member
^^^ so you already know your problem

so just check the Y first and if its the same as the player's check the left and right
But then I'm gonna have the same problem, won't I? It's gonna read the Y position first, not caring about the X position...
This way, the NPC will always look up or down... :/

^^^ so you already know your problem

so just check the Y first and if its the same as the player's check the left and right
Uhm... I'm sorry about the last reply, I got it now. But you see...
My player's Y position is not always gonna be exactly the same as the NPC's one.

^^^ so you already know your problem

so just check the Y first and if its the same as the player's check the left and right
There isn't any function that returns a all values between two values? i mean something like: [function](1, 5) returning: 1, 2, 3, 4, 4,1 ...)
 

TailBit

Member
I usually have a variable in player telling what direction he face, going from 0-3 so it can be multiplied with 90 if I need the direction in degrees.. and update it when you press a direction button.

You could then just hand that over to the npc and add 2 to it to make it face the opposite way, so when you press:
image_index = (oPlayer.facing + 2) mod 4;
or
GML:
image_index = oPlayer.facing + 2;
if(image_index>3) image_index-=4;
 
I would suggest something like this:
GML:
//first, find the direction from this object's position pointing to the player object's position
var dir = point_direction(x,y,oPlayer.x,oPlayer.y);
//then, divide that angle by 90 degrees (since we have 4 image directions at 0, 90, 180, 270 degrees
var index = dir / 90;
//then round that index so that it's either 0, 1, 2, 3, 4
index = round(index)
//if the index is larger than 3 (because it's close to 360 degrees), set the index back to 0
if index > 3 index = 0
//set our image_index to the index variable
image_index = index
Shortened/combined version:
GML:
image_index = round(point_direction(x,y,oPlayer.x,oPlayer.y) / 90);
if image_index > 3 image_index = 0
Then just make sure the image_index of your npc sprite is set as follows:
  1. Facing right
  2. Facing up
  3. Facing left
  4. Facing down
 

TheouAegis

Member
Code:
var H = oPlayer.x - x, V = oPlayer.y ‐ y;
if abs(V) < abs(H)
    if H
        image_index = 1;
    else
        inage_index = 3;
else
    if V
        image_index = 2;
    else
        image_index = 0;
Would need some tweaking. Chessmaster above suggestion is probably easier to grasp.
 

CMAllen

Member
If it's a sidescroller check, 2 directions:
Code:
target_direction = (point_direction(my_x, my_y, target_x, target_y)-180)/180;
If(target_direction > 0) direction = left;
else direction = right;
If it's a top-down check, 4 directions:
Code:
target_direction = ceil(point_direction(my_x, my_y, target_x, target_y) / 90)
switch (target_direction)
{
  case 1: direction = up; break;
  case 2: direction = left; break;
  case 3: direction = down; break;
  default: direction = right; break;
}
If it's a top-down check, 8 directions:
Code:
target_direction = ceil(point_direction(my_x, my_y, target_x, target_y) / 90)
switch (target_direction)
{
  case 1: direction = upright; break;
  case 2: direction = up; break;
  case 3: direction = upleft; break;
  case 4: direction = left; break;
  case 5: direction = downleft; break;
  case 6: direction = down; break;
  case 7: direction = downright; break;
  default: direction = right; break;
}
 

aisdjioad

Member
JUST DID IT RIGHT NOW GUYS!

I just used the collision_line to "draw" one line for each direction (Up, Down, Left, Right). And check which one the player was colliding to.

Thanks for your time!41.png
 
JUST DID IT RIGHT NOW GUYS!

I just used the collision_line to "draw" one line for each direction (Up, Down, Left, Right). And check which one the player was colliding to.

Thanks for your time!View attachment 43612
That is not really a good way to solve your problem. First, collision line checks are expensive calls (and entirely unnecessary for your problem). Second, if the player is diagonal to the NPC, there will be no collisions (not sure if this is an issue as I'm not sure if your player can interact diagonally). The three solutions posted above solve your problem more accurately and efficiently.
 

GMWolf

aka fel666
Check which of the cardinal direction the player is furthest along.
If it's more to the right than upwards, then face right. If it's more upwards that to the right, face up.

GML:
var dx = player.x - x; // difference in X
var dy = player.y - y; // difference in Y

if (abs(dx) > abs(dy)) //if the distance along X is greater than distance along Y
{
  if (dx > 0) //to the right
   {
        sprite_index = spr_right;
    }
    else // to the left
   {
        sprite_index = spr_left;
   }
}
else // distance along Y is greater (or equal to) distance along X
{
    if(dy > 0) //downwards
    {
        sprite_index = spr_down;
    }
    else //upwards
    {
        sprite_index = spr_up;
    }
}
Please ask if anything is unclear about this method :)
Hope it helps

[edit]
oh I see @TheouAegis already posted this solution.
I think it's overall the simplest and most effective solution for 4 directions.
 
Last edited:
Top