- Home /
Finding the closest gameobjects in a radius
Collider[] balloons = Physics.OverlapSphere(transform.position, range);
foreach (Collider c in balloons)
{
if (c.gameObject.tag == "B" && !taggedB.Contains(c.gameObject))
{
taggedB.Add(c.gameObject);
}
}
for (int i = 0; i < taggedB.Count - 1; i++)
{
float dist1 = Vector2.Distance(taggedB[i].transform.position, transform.position);
float dist2 = Vector2.Distance(taggedB[i + 1].transform.position, transform.position);
if (dist1 < dist2)
{
transform.LookAt(taggedB[i].transform.position);
}
else
{
transform.LookAt(taggedB[i + 1].transform.position);
}
if (dist1 >= range)
{
taggedB.RemoveAt(i);
}
I'm trying to search for the closest gameobject with tag "B" within a given radius, and compare it to the rest within the radius, then rotate towards the closest as a sorting function of a "tower" in a tower defense game.
What I currently have has incorrect logic. It looks at the object that entered the radius most recently I think, not to sure whats going on.
Any better ideas are appreciated.
Answer by GrayLightGames · Nov 02, 2019 at 02:05 PM
Hi @gurekam150, from your code snippet, it would look at the most recently added if the distances were all equal. Are you sure this loop is executing without error though? You may want to double check your console... with your RemoveAt statement you are modifying a collection that you are looping on, which usually throws an exception in C#. So maybe you're seeing unexpected result because the code has bombed out? You may also check if localPosition is the thing to use instead of position... do the balloons and this object have the same parent?
Is there anything below the snippet or just end brackets?
If you haven't already done so, Debug.Log can help you investigate what is going on... if you look at the values being compared, it will probably show you why it's picking the balloon it is.
Here's a quick code example of how Debug.Log will become your new best friend... I just rebuilt taggedB every time so you don't need to worry about removing objects and hitting that kind of exception, as well as a currentClosest set of variables to make your for loop a little easier... hope that helps!
//Empty the list
List<GameObject> taggedB = new List<GameObject>();
Collider[] balloons = Physics.OverlapSphere(transform.position, range);
foreach (Collider c in balloons)
{
Debug.Log("Checking GO " + c.gameObject.name + " for B tag.");
if (c.gameObject.tag == "B")
{
taggedB.Add(c.gameObject);
}
}
//Need to check count to ensure it doesn't exception if empty
if (taggedB.Count > 0)
{
//Initially defaulting the closest to the first element
GameObject closestGO = taggedB[0];
float closestDistance = Vector2.Distance(taggedB[0].transform.position, transform.position);
//Notice the loop starts at second element, and only if it exists
for (int i = 1; i < taggedB.Count; i++)
{
float dist1 = Vector2.Distance(taggedB[i].transform.position, transform.position);
Debug.Log("Closest GO is " + closestGO.gameObject.name + " Closest Dist is " + closestDistance + " comparing to " + taggedB[i].gameObject.name + " with distance " + dist1);
if (dist1 < closestDistance)
{
closestGO = taggedB[i];
closestDistance = dist1;
}
}
transform.LookAt(closestGO.transform.position;
}
So this does target the nearest object, but it doesn't check if theres a closer target after it locks on. Basically it sees an object enter it's radius, then ignores others if they get closer. Also it doesn't stop locking on after it exits the radius. That's what the if (dist1 >= range) { taggedB.RemoveAt(i); }
dealio was. Very lastly, it doesn't check if the object has already been added to the list, it just re-adds the same object over and over.
Sorry, bug in my code... I checked dist1 twice with opposite conditions! Let me update, not sure how that extra if condition snuck in there.
If you rebuild the list every time, you don't need to remove objects that have exited the range. It will call the overlap function and any that are out of range will not be added to the list.
The first line in my code resets taggedB to a new List, so without that, it will infinitely add as you describe.
Do you use the taggedB list for anything other than this?
In my original code I had a check in place for weather or not said object was in the list, so we have that base covered. I just need to verify if that object is still in the radius, if not remove, and compare distances between objects.
Well this is my snippet of targeting logic. It's 3d but i think it's not that problematic to convert. Note that "found thingies" is a Physics.OverlapSphere array result. it also checks angle and raycasts to know if it can "see" the target(if it's not behind a wall or something). Also worth mentioning that Vector3.Distance does square root operation which is from what i gather relatively cpu intensive so just use sqr$$anonymous$$agnitude and square the distance i look for. if you need more info ,ask.
oh and i don't say it's perfect i debugged it many times already so you might find an issue. The "Base" variable is turret Base mesh that has rotating barrel as a child. Forward axis of that base is needed is for angle measure.
Sorry for the bad formatting i don't know why it does that....?
void UpdateTarget()
{
//
float ShortDistance = $$anonymous$$athf.Infinity;
GameObject NearestEnemy = null;
switch (TargetWeight) {
case TurretTargetWeight.Closest:
foreach (Collider enemy in foundThingies) {
if (Physics.Raycast (ShootPoint.position, (ShootPoint.position - enemy.gameObject.transform.position) * -1, out hit, ShootRange))
{
if (hit.collider.tag == "Enemy") {
float dist = (Base.position - enemy.transform.position).sqr$$anonymous$$agnitude;
if (dist < ShortDistance && dist >= $$anonymous$$inimumRange * $$anonymous$$inimumRange )
{
ShortDistance = dist;
NearestEnemy = enemy.gameObject;
}
if (NearestEnemy != null && ShortDistance <= ShootRange * ShootRange) { // check if anyone is near to shot at if we are too close with lock-on
Vector3 direction = Base.transform.position - NearestEnemy.transform.position;
Angle = Vector3.Angle (direction, Base.transform.forward);
if (Angle < $$anonymous$$axAngle) {
Target = NearestEnemy.transform;
Enemy = Target.gameObject.GetComponent<Enemy> ();
}
} else {
Enemy = null;
Target = null;
}
}
}
}
break;
}
}
Your answer
Follow this Question
Related Questions
A node in a childnode? 1 Answer
Re-target new Enemy 1 Answer
"look at target" problem 1 Answer
lookAt on Y axis only 1 Answer