I want to make the object I have the following script on look at the second closest object with the tag “obstacle.”
I don’t get any error messages but my game Object isn’t moving to face the obstacle. I’ve been working on it since last night at around 2AM, and had to wait until this morning to post a help wanted post cuz it was so late
Anyway, the following is a modification of the second scripting API example for FindGameObjectsWithTag in the docs.
I’m a beginner coder, but I’d say you could be better of using some sort of comparison.
I’ve used it at some point, can’t remember exact details.
Collect all your objects with tag, then sort them by distance, do a search “unity sort gameobjects by distance” or such, or check out MSDN about IComparable.
also can you explain the use case a little, sorting can be pretty expensive thing to do especially if done in the update like you are. Depending on what you want their may be a more efficient way
I’d say find the objects, compare all the distances (which you perhaps store all their references and the matching distances) then find the closest, and then just find the second closest? I guess this may work, untested though:
GameObject[] gos;
float[] distances;
float closestDistance = 999, secondClosest = 999;
int closestIndex, secondIndex;
void Start()
{
gos = GameObject.FindGameObjectsWithTag("obstacle");
distances = new float[gos.Length]; // init the distances
}
void Update()
{
//findclosests();
for (int i = 0; i < gos.Length; i++)
{
distances[i] = FindDistance(gos[i], this.gameObject); // however you decide to get distance, origin is probably this gameobject?
if (distances[i] < closestDistance)
{
closestDistance = distances[i];
closestIndex = i; // remember which one in the array is closest
}
else if(distances[i] < secondClosest)
{
secondClosest = distances[i];
secondIndex = i;
}
}
// now you have all the distances, and can compare them to decide what to do next
Debug.Log("Closest: " + gos[closestIndex].name);
Debug.Log("Second Closest: " + gos[secondIndex].name);
}
float FindDistance(GameObject go, GameObject origin)
{
return Vector3.Distance(go.transform.position, origin.transform.position);
}
I’ve got an enemy AI character using a grapple hook in a city (both the player and the enemy use the grapple hooks with swords). All of the obstacles are buildings he uses the grapple hook on. there’s 71 buildings, so it really probably will slow down a lot. I’ve fiddled around with a few different scripts to get the job done separately until I find one that works well enough, but I think I can make it only sort when a new hook is being fired by calling the sorting method next to the calling of instantiating the grapple hook.
Is there a way to make it only grab the obstacles? I could use if (tag == “obstacle”) afterward but it would still grab the other enemies causing the game to slow down first, right?
You can make it only target certain layers, by passing in a LayerMask to it. After that just set what layers you want it to act on in the inspector, and also make sure you have your Obstacles on that layer.
IndexOutOfRangeException: Array index is out of range. D1grapplespawn.SpawnHook () (at Assets/Plugins/D1grapplespawn.cs:90) D1grapplespawn.Update () (at Assets/Plugins/D1grapplespawn.cs:49)
I need those lines because the whole reason i’m doing the sorting is to get the second closest object with that tag. How should I edit it to get the transform of the second closest gos?
well the error means that gos does not have a index of 1, maybe you should make sure your layer is set correctly. Also do your obstacles have colliders on them?
all of the buildings are under the layer “obstacle” which is layer number 14. In the Sort method, in the layermask part of the overlapspehere, doesn’t that mean I should put 14? if so, I’m not sure what’s wrong.
also, if I leave out the layermask section completely it still gives the same error.
the obstacles do have box colliders on them. Box colliders which aren’t IsTriggered.
well you are returning the OverlapSphere to “ya” but are sorting on “gos” so that is a place to start.
Also you created a public layermask you might as well pass that into the OverlapSphere in place of the 14 you placed their. This will allow you to set what layers the OverlapSphere will use in the unity inspector.
don’t use 14 as a layer number. Actually call it through the LayerMask.GetMask(). I’m guessing Obstacles is the 14th layer. LayerMask is actually a bitmask so Obstacle is actually the 14th bit, NOT 14. but 8192, (2^13 remember its zero-based).
with a value of 14 you’re actually masking to the bitmask of 1110, or layers 2,3,and 4.
this is also why you can’t have more than 32 layers… for performance and sanity reasons
if i put that, then I get this error before I start the game. Assets/Plugins/D1grapplespawn.cs(96,9): error CS0029: Cannot implicitly convert type UnityEngine.Collider' to UnityEngine.GameObject’
and now there’s a red line indicating the code is wrong inside VisualStudio on the same part as before.
than make sure the obsticals have colliders on them, and that you set the mask on this script in the inspector to the correct layer. Also 20000 might be overkill for the radius on this since that is a pretty large distance.