• Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

Windows [CLOSED] Finding nth nearest object (GMS2)

I am struggling to find a working code that returns the nth nearest of a specific object.

I want to create a piece of code for obj_predator to hunt for prey that fit its requirements, the loop will check the nearest of obj_animal and then see if its variable values match the requirements for the obj_predator if they don't the loop will check the next nearest and keep repeating until it finds a valid target. I have the following code that is from GMS but it doesn't work for GMS2.

This is put into a script and the nth nearest id is returned

  1. Code:
    /// instance_nth_nearest(x,y,obj,n)
    [*]//
    [*]// Returns the id of the nth nearest instance of an object
    [*]// to a given point or noone if none is found.
    [*]//
    [*]// x,y point coordinates, real
    [*]// obj object index (or all), real
    [*]// n proximity, real
    [*]//
    [*]/// GMLscripts.com/license
    [*]{
    [*]var pointx,pointy,object,n,list,nearest;
    [*]pointx = argument0;
    [*]pointy = argument1;
    [*]object = argument2;
    [*]n = argument3;
    [*]n = min(max(1,n),instance_number(object));
    [*]list = ds_priority_create();
    [*]nearest = noone;
    [*]with (object) ds_priority_add(list,id,distance_to_point(pointx,pointy));
    [*]repeat (n) nearest = ds_priority_delete_min(list);
    [*]ds_priority_destroy(list);
    [*]return nearest;
    [*]
 
Last edited:

FrostyCat

Redemption Seeker
First of all, don't post your code in list or normal text form. Put it between [code] and [/code] tags.

If you want to add an additional condition for acceptance, put it inside the with block from instance_nth_nearest so that only acceptable instances get into the priority queue.
Code:
...
with (object) {
  if (condition) {
    ds_priority_add(list, id, distance_to_point(pointx,pointy));
  }
}
...
 
First of all, don't post your code in list or normal text form. Put it between [code] and [/code] tags.

If you want to add an additional condition for acceptance, put it inside the with block from instance_nth_nearest so that only acceptable instances get into the priority queue.
Code:
...
with (object) {
  if (condition) {
    ds_priority_add(list, id, distance_to_point(pointx,pointy));
  }
}
...
Thank you, I've edited the original post into code, that helps with the overall equation but the code I posted doesn't work in GMS 2 and was asking if anyone knew a different method or why it doesn't work,
thanks
 

FrostyCat

Redemption Seeker
Thank you, I've edited the original post into code, that helps with the overall equation but the code I posted doesn't work in GMS 2 and was asking if anyone knew a different method or why it doesn't work,
thanks
Define "doesn't work". Is it crashing outright, or is it returning undefined all the time?

One thing you can try is changing is the repeat loop:
Code:
repeat (n) {
  nearest = ds_priority_find_min(list);
  ds_priority_delete_min(list);
}
 
Define "doesn't work". Is it crashing outright, or is it returning undefined all the time?

One thing you can try is changing is the repeat loop:
Code:
repeat (n) {
  nearest = ds_priority_find_min(list);
  ds_priority_delete_min(list);
}
Its returning noone I think, even though there should be valid targets. In all honesty I am unsure of this code as I have copied it from a GMS1 post and tried to use it myself and not had much luck.

What I need to do is create a list of instances that fall into the right category e.g var size = 3 and var threat = 2 and distance to object < than obj_predator.range and then order that list with the nearest to obj_predator.x and obj_predator.y then return the nearest.

But I'm lost at how to do this, I've tried looking up ordering lists, ordering arrays and ordering ds_maps and cannot find what I'm after.
 

FrostyCat

Redemption Seeker
Its returning noone I think, even though there should be valid targets. In all honesty I am unsure of this code as I have copied it from a GMS1 post and tried to use it myself and not had much luck.

What I need to do is create a list of instances that fall into the right category e.g var size = 3 and var threat = 2 and distance to object < than obj_predator.range and then order that list with the nearest to obj_predator.x and obj_predator.y then return the nearest.

But I'm lost at how to do this, I've tried looking up ordering lists, ordering arrays and ordering ds_maps and cannot find what I'm after.
Data structures and with blocks have not changed between GMS 1 and GMS 2, so anything that breaks is likely to have been already broken in GMS 1.

One potential problem is how you referenced things like obj_predator.range, obj_predator.x and obj_predator.y in your description. If you understand the difference between objects and instances, you should know within a second of seeing it that this is a huge no-no. Having these in the filtering condition (which you never showed in exact form) means the comparison would be invalid, as would the contents of the priority queue.
NEVER access a single instance by object ID if multiple instances of the object exist. This includes attempts to reference or set object.variable (which is inconsistent across exports) and using with (object) to apply actions to it (this encompasses all instances of the object instead of just the one you want). Verbally, "Dog's colour" makes sense with one dog, but not with multiple dogs.

Corollary: NEVER set or use an instance's own variables with object.variable. An instance's own variables can be referenced as-is without dot prefixes. DO NOT use self. If multiple instances of the object exists, you might end up setting the value for all instances or for some other instance (depending on the export).
 

Neptune

Member
I didn't test this, but it gives you an idea of whats going on, and is in script form. You could do this with whatever data structures you want... In this case a ds_grid.
So you'd send in the object, and number of closest instance you'd want. (Add arguments for the x,y to measure from too!)
Like:
Code:
var some_inst = scr_closest(obj_enemy,5);
var obj = argument[0];
var nth_distance = argument[1];

//GET DATA
var data_grid = ds_grid_create(2,0);
var count = 0;
with(obj)
{
ds_grid_resize(data_grid,2,count+1);
data_grid[# 0,count] = id;
data_grid[# 1,count] = point_distance(x,y,other.x,other.y);
count += 1;
}

//SORT
var furthest_dist = -1000;
var furthest_row = noone;
var sort_grid = ds_grid_create(2,count);
for(var i = 0; i < count; i++)
{
for(var z = 0; z < count; z++)
{
if data_grid[# 0,z] != noone && data_grid[# 1,z] > furthest_dist
{
furthest_row = z;
}
}
sort_grid[# 0,count-(1 + i)] = data_grid[# 0,z];
sort_grid[# 1,count-(1 + i)] = data_grid[# 1,z];
data_grid[# 0,z] = noone;
data_grid[# 1,z] = noone;
}

//nth DIST
if (nth_distance - 1) < count
{
var nth_inst = sort_grid[# 0,nth_distance-1];
}
else
{
var nth_inst = sort_grid[# 0,count-1]; //IN CASE THERE ARENT THAT MANY INSTANCES...
}

//CLEANUP
ds_grid_destroy(data_grid);
ds_grid_destroy(sort_grid);

return(nth_inst);
 
Last edited:
Top