Destroying object at raycast 2D causes unrelated object to be destroyed

273 Views Asked by At

In my game the user can spawn instantiated versions of 2 prefabs with mouse clicks: tiles and balls. The balls can be spawned over the tiles.

The user can also erase objects which have been spawned. This is achieved by placing the following code in a if(Input.GetMouseButtonDown(0))) block of the update method:

if (Input.GetMouseButtonDown(0))
{
    Vector3 mousePos = Input.mousePosition;
    mousePos.z = canvas.transform.position.z;
    Vector3 mousePosTrans = Camera.main.ScreenToWorldPoint(mousePos);
    RaycastHit2D rayHit = Physics2D.Raycast(mousePosTrans, Vector2.zero);
    if (eraserSelected)
    {
        Destroy(rayHit.collider.gameObject);
    }
}

The objects intended for deletion are being deleted, but the problem is that other unrelated and distant objects are sometimes also simultaneously deleted. For example, if I spawn 2 squares and a ball on each square, then delete the first ball, when I go to delete the first square the second ball is simultaneously deleted. Sometimes when an object is deleted another object is simultaneously "un-deleted"!

Objects are spawned with the following code:

TileOrBall obj = (TileOrBall) Instantiate(tileOrBall, pos, Quaternion.identity);
obj.transform.SetParent(canvas.transform);

where TileOrBall is the class of the objects being spawned and tileOrBall is a reference to one of the two prefabs from this class.

So is there something wrong with the approach I'm taking to object spawning or destruction? How can I solve the simultaneous deletion (and sometimes resurrection) of distinct objects when trying to destroy an instance of these objects?

EDIT:

Adding link to zip file of project:

https://drive.google.com/open?id=0B28_MgFRWv97OWxfNE96LXcxZHc

To replicate the issue, click on the square in the side bar and "paint" squares in the grid wherever, then click on the ball in the side bar and "paint" over the squares that have been placed. Finally, click on the eraser icon and start deleting objects by clicking on them. You will see that objects you did not click on are deleted, and you may even see that objects are resurrected when you try deleting objects.

Thanks!

2

There are 2 best solutions below

0
On BEST ANSWER

Found few problems in the Project.

1.When you do Destroy(unitAtMouse);, you are not deleting the GameObject from the raycast. You are ONLY deleting the Unit script that is attached to that GameObject.

Because this deletion failed, you will have multiple multiple Square GameObjects in one spot. That makes it harder to delete later on since you have to click delete multiple times until the last Square GameObjects is deleted.

To fix this, replace Destroy(unitAtMouse); with Destroy(unitAtMouse.gameObject);.

2.It is good to have the GameObject you are instantiating to be GameObject instead of script. For example public Unit selectedObject; should be public GameObject selectedObject;

3.Set eraserSelected to false when the square or circle in the side bar is clicked. This fixes problems that even user selects the square while again while in eraserSelected mode, they can delete or even create new square. You want to disable eraserSelected if square or circle in the side bar is clicked. In another word, if setSelectedObject is called.

4.The Erase Button should be under the panel like the other buttons too. Otherwise, it will go missing under some screen resolution.

5.Fixed enum to use the actual enum instead of enum.string.

6.Fix a problem that made the ball invisible which makes it look like it was deleted. What happens is that the ball is sent behind the square. Fixed this by making the ball sortingOrder to the 1 and the square sortingOrder to be 0.

1
On

Alternatively, building on @Programmer's response you could create a new script, say DeletableObject, that can be completely empty for the time being and attach this to the ball and square prefabs and any future prefabs you may have. Then in the suggested code above, change:

if (rayHit.collider.CompareTag("ball"))

to

if(rayHit.collider.GetComponent<DeletableObject>())

That way you can attach the script to any future prefabs you make to be able to delete them.

On a side note, if you're adding / deleting lots of objects and performance becomes an issue, look into Object Pooling. In fact, you should look into it anyway as it's a good habit to get into.