- Home /
Destroy a gameobject referenced in list and remove that element
Hi guys, In order to pick up an item (one among multiple ones) on the floor, I dynamically create a list of item in player range (i get a reference to each item).
I'd like to be able to destroy the closest (in terms of distance from player). How would you do that ? And if I get the right item wouldn't it be tricky to just destroy the object without removing it from list ?
thanks !!
Answer by HenryStrattonFW · Feb 19, 2017 at 02:26 PM
Scribbled this up in note pad, so not checked the syntax but it should be correct. Assuming your list of a MonoBehaviour type (in this example a fictional class called "Item") then you can do this.
public void DestroyNearest(List<Item> items)
{
// Find nearest item.
Item nearest = null;
float distance = 0;
for(int i=0;i<items.Count;i++)
{
float tempDistance = Vector3.Distance(transform.position, items[i].position);
if(nearest == null || tempDistance < distance)
{
nearest = items[i];
distance = tempDistance;
}
}
// Remove from list.
items.Remove(nearest);
// Destroy object.
Destroy(nearest.gameObject);
}
The basic premise is iterate all the items to locate the nearest one, storing a reference to it, then remove the reference from the list, and finally use the stored reference to then destroy the item. You can of course comment out/remove the line that removes the item from the list, but be warned that assuming the list of items are references to game objects then you will end up with a "null" item inside that list, which you would need to account for in any code (like this one) that iterates over the collection.
Answer by IgorAherne · Feb 19, 2017 at 02:33 PM
If you invoke GameObject.Destroy(myItems[myIndex])
the spot in the list will be occupied, but there "cell" will still contain null
. You will then have to remove this empty entry by calling myItems.RemoveAt(myIndex)
Also, if I am not wrong, unity has an issue where even if you call Destroy, the garbage collector won't free the memory. For that to happen, after Destroy(), you have to manually assign null
to the variable which used to point to the destroyed gameObject.
Also, you might want to sort the list every few frames, by distance to player. You should do this when you have spare FPS. That way you don't have to do distance comparison for every element in the list, if you need to do this many times during the frame. You just sort once, and then remove 1st element.
Use QuickSort if the list is almost sorted, Merge sort if it's badly sorted
It is actually where I was going with my question : you cannot destroy the object as HenryStratton suggests because it would create a missing component in the list.
To get the index so we can remove the slot from the list seems like a cool solution, I'll give it a try and accept your answer :)
Apologies, accidentally deleted the reply when trying to edit it.
If you look at my answer again, you will see that I point out at the end, that destroying the object alone will leave a null in your list. However the example code provided calls "Remove" on the list, providing the desired item as a parameter, this will remove the item from the list, meaning no "null" item will be left in its place, This is how Remove works, it does not null the item, it removes the item and its slot from the list, as if it was never there.
But do you still have the reference to "nearest" once you removed it from the list ?