Game Development Asked by Thrindil on November 2, 2021
I’m writing a script which instantiates buildings in a scene, but in such a way that 2 buildings don’t overlap with each other. Every building consists of approx. 10 parts, of which each has a box collider.
The way I do this is by first instantiating the first building and adding it to a list. In this example I instantiate 2 buildings.
By the way, this doesn’t need to run in real-time, my intention for this is to press a button in the editor and have a lot of buildings instantiated at once.
for (int j = 0; j < 2; j++)
{
if(j == 0)
{
_buildingList.Add(GameObject.Instantiate(GetBuilding(Vector3.zero), _parent));
}
Now in this same for loop, I instantiate the next building, add it to the list and check if it collides with the previous building in the list, like so:
else
{
_buildingList.Add(GameObject.Instantiate(GetBuilding(Vector3.zero), _parent));
if (_buildingList.Count > 1)
{
int amountOfRepositioningAttempts
while (AreObjectsIntersecting(_buildingList[_buildingList.Count - 1], _buildingList[_buildingList.Count - 2]) && amountOfRepositioningAttempts < 10000)
{
amountOfRepositioningAttempts++;
GameObject buildingToMove = _buildingList[_buildingList.Count - 1];
buildingToMove.transform.Translate(Vector3.right);
}
}
}
}
As you can see I have a few helper methods, which look like this
public GameObject GetBuilding(Vector3 position)
{
GameObject buildingToInstantiate = _buildingPrefabContainer.GetRandomBuilding();
Vector3 lookDirection = Vector3.zero - position;
Quaternion lookRotation = Quaternion.LookRotation(lookDirection);
buildingToInstantiate.transform.position = position;
return buildingToInstantiate;
}
And the method from which I get unexpected results:
public bool AreObjectsIntersecting(GameObject object1, GameObject object2)
{
BoxCollider[] _collidersObject1 = object1.GetComponentsInChildren<BoxCollider>();
BoxCollider[] _collidersObject2 = object2.GetComponentsInChildren<BoxCollider>();
for (int i = 0; i < _collidersObject1.Length; i++)
{
for (int j = 0; j < _collidersObject2.Length; j++)
{
if (_collidersObject1[i].bounds.Intersects(_collidersObject2[j].bounds))
{
return true;
}
}
}
return false;
}
The intention here is that I go over each buildings collider, and if one of those colliders overlaps with one of the colliders of another building, then the building gets repositioned, and the check happens again.
But the method AreObjectsIntersecting() seems to always return true, and I don’t see why.
I know this because
int amountOfRepositioningAttempts
Always ends up being 10000, while the 2 objects should have stopped intersecting with each other after only a few iterations of moving them.
Can anyone help me out here?
Thanks in advance!
Remember that colliders and collision/overlap checks are part of the physics engine, while transforms are part of the game engine. These are two separate systems with their own data, and synchronizing that data has a non-zero cost.
By default, Unity will synchronize the physics data to align with changes to the transforms before each physics step, and synchronize physics movement back to the transforms at the end of the physics step / in time for collision handling callbacks.
But here, there's no physics step happening inside your while
loop between you repositioning the building and checking its overlaps, so you're still checking overlaps with stale, out-of-sate physics info.
To fix this, you can call Physics.SyncTransforms to force any updated transform data to be passed over to the physics engine, so you can do overlap testing with the latest transform positions.
Answered by DMGregory on November 2, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP