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

select nearest entity

B

Beggar Studios

Guest
Hey guys!

I have a system in my game where if you get close to a chest or npc a button prompt (little hovering A button) spawns above their head. This works fine, but the problem is that when you are in range of multiple entities all entities spawn a button prompt. I want to set it up so that if multiple entities are in range only the closest entity spawns a button prompt. I was thinking I could store all nearby entities in a data structure and use instance_destroy() on the button prompt if they are no longer the closest entity to the player, but I'm not sure. Here is my current code!

scr_move_state (detecting nearby entities and spawning the prompt generator for them)

Code:
// Initialize chest interaction prompts

distance = 30;

var chest_detected = collision_circle(x, y, distance, obj_container_parent, false, true);

if(chest_detected != noone && chest_detected.looted == false){

    chest_prompt = instance_create(chest_detected.x, chest_detected.y, obj_prompt_generator);
    chest_prompt.chestid = chest_detected;
    chest_prompt.context = 'loot';
    chest_prompt.kill_distance = distance;
}

// Initialize NPC interaction prompts

var npc_detected = collision_circle(x, y, distance, obj_npc_parent, false, true)

if(npc_detected != noone){
    global.destination = npc_detected;
    npc_prompt = instance_create(npc_detected.x, npc_detected.y, obj_prompt_generator);
    npc_prompt.npcid = npc_detected;
    npc_prompt.context = 'npc';
    npc_prompt.kill_distance = distance;
}
The problem is this will spawn prompts for every nearby instance

obj_prompt_generator (drawing the prompts and destroying them when no longer near)

Code:
// Draw button prompt based on input selection

if(context == 'loot'){
    if(global.gamepad_input == true){
        draw_sprite(spr_prompt_gamepad, 0, x, y-20);
    } else {
        draw_sprite(spr_prompt_keyboard, 0, x, y-20);
    }
}

if(context == 'npc'){
    if(global.gamepad_input == true){
        draw_sprite(spr_prompt_gamepad, 0, x+12, y-20);
    } else {
        draw_sprite(spr_prompt_keyboard, 0, x+12, y-20);
    }
}

//Destroy the prompt when no longer near

var dis = point_distance(x, y, obj_player.x, obj_player.y);
var in_range = collision_circle(x, y, kill_distance, obj_player, false, true);

if(alpha < 1 && kill = false){
    alpha += 0.01
}

if(in_range == noone){

    kill = true
    
    if(alpha > 0){
        alpha -= 0.01;
    }

    if(alpha = 0){
        instance_destroy();
    }
}
So this is how my system is currently set up. Does someone have an idea of how I could destroy the button prompt generator if the instance is no longer the nearest chest or npc instance to the player?
 
C

Chris

Guest
If you need to find out the closest instance, I would use instance_nearest. I rewrote your script a little bit (it might be a little un-optimized) but I think this should do the trick:
Code:
///scr_move_state

//Setup distance
distance = 30;

//Create a variable to hold the nearest instance
var closestInstance = -1;
var closestInstanceType = "";

//Detect closest chest
var chest_detected = instance_nearest(x, y, obj_container_parent);

//Detect closest npc
var npc_detected = instance_nearest(x, y, obj_npc_parent);

//Get the distances
var distance_to_chest = false;
var distance_to_npc = false;
if (chest_detected != noone) {
    distance_to_chest = distance_to_object(chest_detected);
}
if (npc_detected != noone) {
    distance_to_npc = distance_to_object(npc_detected);
}

//Determine which is closer
if (distance_to_chest != false) && (distance_to_npc != false) {
    if (distance_to_chest < distance_to_npc) {
        closestInstance = chest_detected;
        closestInstanceType = "chest";
    } else {
        closestInstance = npc_detected;
        closestInstanceType = "npc";
    }
} else {
    if (distance_to_chest != false) {
        closestInstance = chest_detected;
        closestInstanceType = "chest";
    } else if (distance_to_npc != false) {
        closestInstance = npc_detected;
        closestInstanceType = "npc";
    }
}

//If there was a closest instance found
if (closestInstance != -1) {
    //And it is in range
    if (distance_to_object(closestInstance) <= distance) {
        //Trigger the prompt
        if (closestInstanceType == "chest") {
            if (closestInstance.looted == false) {
                chest_prompt = instance_create(closestInstance.x, closestInstance.y, obj_prompt_generator);
                chest_prompt.chestid = closestInstance;
                chest_prompt.context = 'loot';
                chest_prompt.kill_distance = distance;
            }
        } else if (closestInstanceType == "npc") {
            global.destination = closestInstance;
            npc_prompt = instance_create(closestInstance.x, closestInstance.y, obj_prompt_generator);
            npc_prompt.npcid = closestInstance;
            npc_prompt.context = 'npc';
            npc_prompt.kill_distance = distance;
        }
    }
}
This will check the nearest instance of each type of object, then compare them to see which is closer, then make sure it's within range. If so, it will trigger the prompt appropriately. This should prevent you from having to create multiple prompts only to destroy some when you don't need them.
 
Last edited by a moderator:
B

Beggar Studios

Guest
Thanks, I'll try that out! I feel stupid now. I was thinking of detecting all instances within a radius, storing those in a DS_LIST, sorting the list absed on point distance to the player and then spawning a prompt for position 0 in the list... I knew about instance nearest, but I kept telling myself that ignored the detection radius and would spawn prompts far away.
 
C

Chris

Guest
No problem! That way of doing it probably would have worked to your credit, but it's probably safe to say that using instance_nearest is easier haha
 
Top