Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Selecting Closest Item To Pick Up

Discussion in 'Editor & General Support' started by the_terrible, Apr 12, 2019.

  1. the_terrible

    the_terrible

    Joined:
    Nov 4, 2015
    Posts:
    40
    Hi all,

    I'm trying to create functionality that will find a "selected object" within a game so that I can add effects to that object. There's no cursor so it's really just any object that can be "picked-up" that is within range of the player. When multiple objects are within reach of the player, I want the closest one of the bunch to be "selected".

    I've created a trigger collider for the player that will identify whenever an object with the tag "Pickup" enters the trigger. My plan is to add the game objects that enter the collider to an empty list, and remove them from the list anytime they leave the collider. The list would then calculate the distance of each object to the player and return the closest one each frame.

    Is this the best way of achieving something like this? If so, how do I do it?

    Here is what I have so far in the Player object's script. I have float "dist" picking up the distance for each object from the player, but now I'm not entirely sure how to proceed. In fact, I'm confused how one float variable could have more than one distance assigned to it:
    Code (csharp):
    1. List<GameObject> pickupsInRange = new List<GameObject>();
    2. void OnTriggerEnter(Collider collision)
    3.     {
    4.         switch (collision.gameObject.tag)
    5.         {
    6.             case "Pickup":
    7.                 pickupsInRange.Add(collision.gameObject);
    8.                 break;
    9.         }
    10.     }
    11.     void OnTriggerStay(Collider collision)
    12.     {
    13.         switch (collision.gameObject.tag)
    14.         {
    15.             case "Pickup":
    16.                 foreach (GameObject pickup in pickupsInRange)
    17.                 {
    18.                     float dist = Vector3.Distance(pickup.transform.position, transform.position);
    19.                 }
    20.                 break;
    21.         }
    22.     }
    23.     void OnTriggerExit(Collider collision)
    24.     {
    25.         switch (collision.gameObject.tag)
    26.         {
    27.             case "Pickup":
    28.                 pickupsInRange.Remove(collision.gameObject);
    29.                 break;
    30.         }
    31.     }
     
  2. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    It sounds like what I'd do, except I don't see why you'd need to recalculate every frame. If it needs fast updating you'll probably still get good results updating every 0.1 seconds, so at 60 frames per second that would be 5/6 reduction in the number of Vector3.Distance calls. You can adjust the interval with play testing.

    Also, don't do the looping through the list in OnTriggerStay. You're looping through the entire list for each Pickup object in range. So 5 Pickup objects results in looping the list 5 times over, each frame. Do it in Update or a Coroutine IMO.
     
    Last edited: Apr 13, 2019
  3. the_terrible

    the_terrible

    Joined:
    Nov 4, 2015
    Posts:
    40
    Okay, I'll move it to update, but I'm not sure what I would do next. At that point I would just have assigned a variable with the distance to player for each object in range, although wouldn't the float "dist" just end up getting overwritten by the last object's distance?