Detecting Enemy Distance via List
I have been attempting to create a system that detects all enemies inside a sphere collider and calculates their distance. So far, I have this which grabs all the objects and puts them in to a list, this works good.
private void OnTriggerEnter(Collider other)
{
if (HitBoxAI.isENEMY) {
if (other.tag == "Friendly")
{
if (!targets.Contains(other.gameObject))
{
targets.Add(other.gameObject);
}
}
if (other.tag == "Player")
{
if (!targets.Contains(other.gameObject))
{
targets.Add(other.gameObject);
}
}
}
if (HitBoxAI.isALLY)
{
if (other.tag == "Enemy")
{
if (!targets.Contains(other.gameObject))
{
targets.Add(other.gameObject);
}
}
}
Now, that all works and successfully adds the gameobjects into the list.
What do I want?
I want to make it so that I can run a function that will look through the list and determine the closest game object in the list to the current transform.gameObject and then to assign the AI's target to that.
So, as for pseudocode, I am trying to achieve something like;
ai.target = targets.closestInList
I can imagine another way would be using the List.Sort method and then just making the target the first in the index such as [0]. My experience with lists unfortunatetly is not very good, I hope someone can give a helping hand.
Many thanks.
Answer by SilverSho0t · Aug 22, 2017 at 05:35 PM
I do this a lot for my game, i'm happy to share it to you if it can help you ;) It's pretty simple.
float distance = 0;
GameObject closestTarget;
for (int i = 0; i < targets.Length; i++)
{
float targetDistance = Vector3.Distance (transform.position, targets [i].transform.position);
if (targetDistance < distance || i == 0)
{
closestTarget = targets [i];
distance = targetDistance;
}
}
ai.target = closestTarget;
I hope it help, Sean.
Hey Sean!
Thanks for sharing that, I finally found a solution, however, yours is also correct so I'll mark you as correct! :)
For any others who come across this thread;
Create a Script called GameObjectUtils and insert this code inside;
using UnityEngine; using System.Linq; using System.Collections; using System.Collections.Generic;
public static class GameObjectUtils { public static List<GameObject> SortByDistance(this List<GameObject> objects, Vector3 mesureFrom) { return objects.OrderBy(x => Vector3.Distance(x.transform.position, mesureFrom)).ToList(); } }
Create a function for your script with the list and run the function whenever you want it to sort them in to distance and then you could simply set your target to targets[0].gameObject.
public void ByDistance() { targets = targets.SortByDistance(transform.position); }
Answer by Malace · Aug 22, 2017 at 06:12 PM
You will have to loop through your list. Keeping track of which object has the lowest distance from the target object.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Example : MonoBehaviour {
public List<GameObject> targets;//This is your list fill it with the objects you want to test.
public GameObject NearestEnemyObject;// This will hold our result of our closest target at the end
public GameObject ObjectToCompareTo;// This you will need to have declared as your object you want to be your center point.
public float closestTarget;// used to detect the first run of our foreach loop below.
// Use this for initialization
void Start () {
closestTarget = 0.0f;//Set to 0 so we can force the first run of the loop to catch our distance values.
///Assuming your list is already populated in this script before this point....
foreach (GameObject TargetObjectToTestDistance in targets)
{
if (closestTarget == 0.0f)//Only happens on first run as we are about to set below. We need to have at least one distance calculation before we can compare that vs the other objects in list.
{
closestTarget = Vector3.Distance(TargetObjectToTestDistance.transform.position, ObjectToCompareTo.transform.position);//Since we are in our fist run store the distance of the first object of our list
NearestEnemyObject = TargetObjectToTestDistance;//Go ahead and set our NearestEnemy variable incase the first object is the closes out of all.
}
else//this will trigger every run after the first since distance should never return 0.0f unless you test 2 objects in the same x,y,z location.
{
if (Vector3.Distance(TargetObjectToTestDistance.transform.position, ObjectToCompareTo.transform.position) < closestTarget)//test to see if each following object's distance is lower than our current lowest distance result
{
closestTarget = Vector3.Distance(TargetObjectToTestDistance.transform.position, ObjectToCompareTo.transform.position);//if the object was closer update our closest distance float so our next loop run will test vs this.
NearestEnemyObject = TargetObjectToTestDistance;//Since we are closer than any object before go ahead and store the gameobject for later use.
}
}
}
//Now that our loop has finished iterating through all our list objects we should have overwritten NearestEnemyObject with the closet target enemy of all from our list
Debug.Log("Closest object is. " + NearestEnemyObject.name.toString());
}
}
This is just a rough example. But if you populate the list with some objects. Then set your object to test against through inspector you should end up with the name of the closest object in debug.
Your answer
Follow this Question
Related Questions
How to search a LIST(not an array) for game objects with a specific tag? 1 Answer
Animations not playing correctly for FPS enemy AI 0 Answers
Animations not playing correctly for FPS enemy AI 0 Answers
Most efficient way to store information in an inspector dropdown menu? 0 Answers
Why does my enemy teleport to my player? 2 Answers