Legacy GM Instance_nearest BUT not me?

MIchael PS

Member
Hi!!!

I use instance_nearest to check for an object. But the object I am searching for is the same object type as the object calling the "instance_nearest". So it finds itself as the nearest object. How can I fix it so that it checks for all the others instances instead of its own? (Note that I can't -don't want to- make it a different object)

Thank you for your time,
Michael
 

Kyon

Member
These are some scripts I found for you on google, haven't tested it but looks fine! :)


#1 A function that returns the nth nearest instance. Simply input 2 to get the nearest instance excluding yourself:
Code:
///instance_nth_nearest(object, x, y, n);

var arg_obj = argument[0];
var arg_x = argument[1];
var arg_y = argument[2];
var arg_n = argument[3];

var list = ds_priority_create();
arg_n = clamp(arg_n, 1, instance_number(arg_obj));
var nearest = noone;

with (arg_obj)
{
ds_priority_add(list, id, distance_to_point(arg_x, arg_y));
}

repeat (arg_n)
{
nearest = ds_priority_delete_min(list);
}

ds_priority_destroy(list);
return nearest;

#2:
Code:
//instance_nearest_notme(x, y, obj) 
var xx, yy, obj, nearest; xx = argument[0]; yy = argument[1];
obj = argument[2];
nearest = noone;
dist = -1;
for (ii=0; ii<instance_number(obj); ii+=1) {
      var o, d; 
      o = instance_find(obj, ii);
      d = point_distance(xx, yy, o.x, o.y);
      if (o != id) {
               if (nearest == noone || d < dist) { nearest = o; dist = d; }
      }  
}
return nearest;
 

MIchael PS

Member
These are some scripts I found for you on google, haven't tested it but looks fine! :)


#1 A function that returns the nth nearest instance. Simply input 2 to get the nearest instance excluding yourself:
Code:
///instance_nth_nearest(object, x, y, n);

var arg_obj = argument[0];
var arg_x = argument[1];
var arg_y = argument[2];
var arg_n = argument[3];

var list = ds_priority_create();
arg_n = clamp(arg_n, 1, instance_number(arg_obj));
var nearest = noone;

with (arg_obj)
{
ds_priority_add(list, id, distance_to_point(arg_x, arg_y));
}

repeat (arg_n)
{
nearest = ds_priority_delete_min(list);
}

ds_priority_destroy(list);
return nearest;

#2:
Code:
//instance_nearest_notme(x, y, obj)
var xx, yy, obj, nearest; xx = argument[0]; yy = argument[1];
obj = argument[2];
nearest = noone;
dist = -1;
for (ii=0; ii<instance_number(obj); ii+=1) {
      var o, d;
      o = instance_find(obj, ii);
      d = point_distance(xx, yy, o.x, o.y);
      if (o != id) {
               if (nearest == noone || d < dist) { nearest = o; dist = d; }
      } 
}
return nearest;
Thank you I think it will help!!
 

FrostyCat

Redemption Seeker
I'm not a fan of the data structure churn in #1 (which is necessary in the general case but unnecessary for your minimum-only use case) or the instance_find() loop in #2. This is what I'd do:
Code:
///instance_nearest_notme(x, y, obj)
{
var inst_nearest = noone,
    dist_nearest = undefined;
with (argument2) {
  if (id != other.id) {
    var dist = distance_to_object(other);
    if (inst_nearest == noone || dist < dist_nearest) {
      inst_nearest = id;
      dist_nearest = dist;
    }
  }
}
return inst_nearest;
}
This is a direct adaptation of the not-me and lowest property value patterns from my with Block Recipe Cards article.
 

TheouAegis

Member
Other than an aversion to having to choose some questionably arbitrary distance, why did you make your code be be concerned with if no instance was found yet? With short circuiting, the code will be super fast on the first instance, but from the second instance onward it will then have to check both expressions rather than just the distance-based expression. The distance expression is relevant for all instances checked, but the noone expression is only relevant for one instance only.
 
There's also a simple method by moving the calling instance:
Code:
/// instance_nearest_notme();

x += 100000; var _ins = instance_nearest(x-100000,y,object_index); x -= 100000;

if (_ins != id)
return _ins;
return noone;
 

Joe Ellis

Member
You could just put after the check stage, if id != other.id
Ah no, sorry that doesn't work with instance nearest

I'd do it with "with", and manually measure the distance, and then add that if id != other.id check

Or, check that the distance is not 0, cus itself will be 0 away from itself, obv,
ah but that doesnt really work with that function,
the instance_nearest function is really designed around different object types checking each other,
I think if your gonna use this function, you need to make the calling instance a different object to the ones its checking for.. If you dont want that just do it manually with point_distance
 
Last edited:

FrostyCat

Redemption Seeker
Other than an aversion to having to choose some questionably arbitrary distance, why did you make your code be be concerned with if no instance was found yet? With short circuiting, the code will be super fast on the first instance, but from the second instance onward it will then have to check both expressions rather than just the distance-based expression. The distance expression is relevant for all instances checked, but the noone expression is only relevant for one instance only.
That's because I have no information on the scale of distances in the original poster's project. I've seen once someone on the old GMC breaking the magic distance of 100000 on instance_nearest() with a huge room, and I stopped taking it for granted.

Having said that, there are certain bounds that you can place on the starting value if certain conditions are known. For example, if everything will always be within room boundaries, point_distance(0, 0, room_width, room_height) is the theoretical max distance. If you want a slight margin outside room boundaries or just something computationally cheaper than the preceding, room_width+room_height would do as well.
 

Joe Ellis

Member
That's because I have no information on the scale of distances in the original poster's project. I've seen once someone on the old GMC breaking the magic distance of 100000 on instance_nearest() with a huge room, and I stopped taking it for granted.

Having said that, there are certain bounds that you can place on the starting value if certain conditions are known. For example, if everything will always be within room boundaries, point_distance(0, 0, room_width, room_height) is the theoretical max distance. If you want a slight margin outside room boundaries or just something computationally cheaper than the preceding, room_width+room_height would do as well.
Thats kind of clever cus room_width+room_height is more than the distance from 0,0 to room_width, room_height, its a good rough and cheap approximation

its something like 0.5656 for diagonal stuff
 
Last edited:

Bentley

Member
Thought I'd contribute. Wrote it fast so don't be too harsh.
Code:
var nearest_inst, nearest_dist, dist;

nearest_inst = noone;
nearest_dist = -1;

with (object_index)
{
    if (id != other.id)
    {
        dist = point_distance(x, y, other.x, other.y);
     
        // First instance in the with loop
        if (nearest_inst == noone)
        {
            nearest_inst = id;
            nearest_dist = dist;
        }
        else
        {
            if (dist < nearest_dist)
            {
                nearest_inst = id;
                nearest_dist = dist;
            }
        }
    }
}
 
Last edited:
Top