- Home /
Destroyed gameobject found with FindObjectsOfType<>?
I'm making a simple level editor for a 2D platformer. When I delete (Destroy()) a tile in the level editor, then try to recalculate the textures for my tile stitching, the remaining tiles behave as if the destroyed tile were still in the scene.
//Delete the (topmost) object at the mouse position
void DeleteObject() {
Collider2D hit = Physics2D.OverlapCircle(Camera.main.ScreenToWorldPoint(Input.mousePosition), 0.0001f, menuMask);
if (hit != null) {
if (hit.gameObject.GetComponent<Tile>() != null) {
Destroy(hit.gameObject);
Recalculate();
}
}
}
void Recalculate() {
Tile[] tiles = FindObjectsOfType<Tile>();
foreach (Tile t in tiles) {
t.RecalculateTexture();
}
}
In the above code, "hit.gameObject" is included in the array "tiles" after being destroyed, and the other tiles in "tiles" don't re-stitch themselves properly as a result. What do I need to do differently to destroy the hit tile completely before Recalculate() is called?
Answer by ninja_gear · May 28, 2016 at 05:23 AM
When you call Destroy a GameObject, Unity will wait until the end of the frame (or cycle I can't remember which but lets say frame to be safe) before it removes that object from the scene and releases its memory. If you ask Unity for a component from that GameObject before the end of the frame that you called Destroy on it, Unity will save that component and not release its memory while at the same time destroying all other parts of said GameObject. If you want to Recalculate() right after the destroy use a Coroutine to break the two commands apart by a frame:
//Delete the (topmost) object at the mouse position
void DeleteObject()
{
Collider2D hit = Physics2D.OverlapCircle(Camera.main.ScreenToWorldPoint(Input.mousePosition), 0.0001f, menuMask);
if (hit != null && hit.gameObject.GetComponent<Tile>() != null)
{
StartCoroutine(destroyThenRecalculate(hit.gameObject));
}
}
void Recalculate()
{
Tile[] tiles = FindObjectsOfType<Tile>();
foreach (Tile t in tiles)
{
t.RecalculateTexture();
}
}
IEnumerator destroyThenRecalculate(GameObject hitObj)
{
Destroy(hitObj);
yield return null;
Recalculate();
}
This actually doesn't work for me, I have no idea why not though. I do know for a fact that my "RecalculateTexture" method works perfectly because the tiles stitch properly when instantiating, just not when destroying.
The pictures below illustrate the problem: as I draw the tiles onto the grid, they stitch together dynamically. When I delete the rightmost one (second picture), the second-to-rightmost tile still thinks that the deleted tile is there. This is with your code enabled.
http://i.imgur.com/e26WAXm.png http://i.imgur.com/AU$$anonymous$$Y1eY.png
I've also tried to just enabled=false the box collider on deleted tiles (not destroying them) to see whether the other tiles still calculate their neighbors the same way, and they do (still no proper stitching), even though the collider is successfully disabled from what I can tell.
Well, to me it sounds like Tile.RecalculateTexture() might be the issue but we can zero in harder on the problem. What does this Debug.Log tell you:
void Recalculate()
{
Tile[] tiles = FindObjectsOfType<Tile>();
Debug.Log(tiles.Length);
foreach (Tile t in tiles)
{
t.RecalculateTexture();
}
}
That logs the correct amount of tiles. Which makes me think it's probably Tile.RecalculateTexture() that's acting up after all. But that's strange in itself, because it stitches them dynamically when the user paints the tiles onto the grid, just not when they erase them. I assumed the logic for recalculation would be the same, but I suppose I'll take another look (thanks for the help, by the way :D).