- Home /
Getting Collider2D.bounds.extents to update immediately (2D)
for a while now I have been trying to solve a problem with newly instantiated 2D game objects spawning in each other. these objects can have any scale, any position, and any rotation.
my original solution was to spawn one, set rotation, position, and scale, and use something like Collider2D.OverlapCollider to find colliders inside of it, but the problem with this is I am spawning all these objects in a single frame, so the rot, pos, and scale don't update in time for this method to work / other colliders aren't placed in the world in time (idk I didn't do more testing, it just showed up as 0 colliders, or 1 if it was over a pre-existing game object like the player)
after trying some other solutions I landed on one that would work: using Physics2D.OverlapAreaAll to find all colliders in an area. to get this area I need the min and max bounds of the collider (collider2D.bounds.min, collider2D.bounds.max).
the value for these is always pos +/- extents - but here's the problem: if you spawn the game object, change pos, rot and scale the bounds.extents don't update till the next frame, therefore the area Physics2D.OverlapAreaAll checks in is always the size of the prefab scale and in the prefab rotation.
I tried to calculate the new extents myself, which would be great if it worked as I don't need to spawn a bunch more objects to check if a place is clear.
I started simple and kept adding more but I'm not a maths genius so I can't figure out the exact maths I need to get it right 100% of the time. the following is what I am up to:
Vector3 position = new Vector3(UnityEngine.Random.Range(minX, maxX), UnityEngine.Random.Range(minY, maxY), 0);
Vector3 localScale = new Vector3(UnityEngine.Random.Range(-obj.Value, obj.Value), UnityEngine.Random.Range(-obj.Value, obj.Value), 0);
Quaternion rotation = Quaternion.Euler(0, 0, UnityEngine.Random.Range(0.0f, 360.0f));
double extentX = (localScale.x / 2) + (Math.Pow(Math.Sin(((localScale.x + localScale.y) / Math.Sqrt(Math.Pow(localScale.x, 2) + Math.Pow(localScale.y, 2))) * ((Math.PI / 180) * rotation.eulerAngles.z)), 2) * (Math.Sqrt(2 * Math.Pow((localScale.x / 2), 2)) - (localScale.x / 2)));
double extentY = (localScale.y / 2) + (Math.Pow(Math.Sin(((localScale.x + localScale.y) / Math.Sqrt(Math.Pow(localScale.x, 2) + Math.Pow(localScale.y, 2))) * ((Math.PI / 180) * rotation.eulerAngles.z)), 2) * (Math.Sqrt(2 * Math.Pow((localScale.y / 2), 2)) - (localScale.y / 2)));
Vector3 extents = new Vector3((float)extentX, (float)extentY, 0);
Vector3 max = position + extents;
Vector3 min = position - extents;
//Debug.Log(max);
//Debug.Log(min);
Collider2D[] colliders = Physics2D.OverlapAreaAll(max, min);
the big problem with this is it only finds the extent up to the first maxima (when extent x/y is the greatest), I amended this to work for the first maxima and the next 180 degrees away (the image attached shows examples of graphs for this, as each one finds 2 maxima and there are 4, there are two graphs) but doing this made the extent never reach its minimas (when extent x/y is the lowest), and as such, I kept with the implementation above.
I tried to look for a method that would update the extents right then and there but I couldn't find anything. I even went looking in unity source code to find the formula they use to calculate bounds.extents but couldn't find anything relevant.
It is necessary that all the game object spawning is done in a single frame, so coroutines wouldn't work for me.
If anyone has the formula unity uses for extents, or a way to check overlapping colliders that would work for me, I'm all ears :)