distance_to_object - Help Me Understand *SOLVED*

M

Mandarieno

Guest
Hello,

I have written a script for my npc's to make them always face the player by using the built in function "point_direction". I am happy with how this works but now I want them only to face the player when he is in a specific range to them.

I use "distance_to_object" for this and that also works fine except for one glitch that I don't seem to understand.
At the corners of the detection of "distance_to_object", the npc's always jump from their facing sprite to their default sprite (default sprite is used for when the player is not in range) and back in a loop.

I don't understand why this happens. This means at that x and y point, the game can not decide if the player is in range or not? Or rather both cases are true?

I hope you guys can help me understand why this happens and maybe help me solve the problem :)


Code:
///NPC FACING SCRIPT

dir = point_direction( x, y, player.x, player.y );

if (distance_to_object(player) <= 16)
{
    if(dir > 45 && dir <= 135)
    {
      sprite_index = spr_n;
    }
  
    else if(dir > 135 && dir <= 225)
    {
      sprite_index = spr_w; image_xscale = 1;
    }
  
    else if(dir > 225 && dir <= 315)
    {
      sprite_index = spr_s;
    }
  
    else if(dir > 315 || dir <= 45)
    {
      sprite_index = spr_w; image_xscale = -1;
    }
}
else if (distance_to_object(player) > 16)
{
    sprite_index = spr_d;
    if (spr_flip == true) image_xscale = -1;
    else{ image_xscale = 1; }
}
 

Roderick

Member
From distance_to_object:
This function calculates the distance from the edge of the bounding box of the calling instance to the nearest edge of the nearest instance of the object specified.
I'm guessing that your object's origin isn't perfectly centered in the bounding box, making it so that when it turns around, it's no longer in range, but when it turns back, it is, and so on.
Remember that if, for example, your sprite is 8 pixels wide, and the origin is at 4, there are 4 pixels (0 to 3) to the left, and only 3 (5 through 7) to the right. When the image flips, 4 stays put, and you now have 3 to the left and 4 to the right.

Try using point_distance.
Code:
point_distance(x, y, player.x, player.y)
 

andulvar

Member
It's likely a problem with the origin on the sprite itself. is the origin 0,0 or centered? It should be centered, since if the sprite changes facing the origin is likely in range so it changes facing, but the the new origin is out of range so it changes back making an infinite loop.

Edit: Roderick beat me to it. ;)
 
Not sure if it will help with the jitterring, but one thing you could do is instead of actually flipping the instance with 'image_xscale', instead, draw the instance flipped by replacing your use of 'image_xscale' with your own variable. For an example, we'll call it 'facing'. So, to use one instance of your code as an example:

Code:
else if(dir > 135 && dir <= 225)
   {
      sprite_index = spr_w; facing = 1; // For left, use '-1' just like 'image_xscale'
    }
... Then in the draw event:
Code:
// You could also use draw_sprite_ext, but this is much faster to type out in my opinion
image_xscale = facing;
draw_self();
image_xscale = 1;
 
M

Mandarieno

Guest
I'm guessing that your object's origin isn't perfectly centered in the bounding box
It's likely a problem with the origin on the sprite itself. is the origin 0,0 or centered?
The origin was centered but I saw that the collision masks for the face-left/right sprites were 16x14 and not 16x16 like the other sprites. So yes, when the npc changed its sprite to face the player, it lost 1 pixel in width on both sides and was out range again. So it went back and forth because one sprite was in range and the other not.

I didn't think about that because the sprites themselfs are all 16x16, the mask was just set to automatic.

Thank you guys for the help, I'm glad I can move on with my game now! :D
 
With the code I posted for the draw event, the image scale is only briefly changed to draw the instance, then flipped back to normal, thus preventing changes to the bounding box. It's more of a time saving hack then anything. The alternative code would be this:

Draw event
Code:
draw_sprite_ext(sprite_index, image_index, x, y, facing, image_yscale, image_angle, image_blend, image_alpha);
For me, it's just a lot simpler to temporarily set the xscale value, use draw self, then set it back to normal.
 
Top