在光线投射 2D 处销毁对象会导致不相关的对象被销毁

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

在我的游戏中,用户可以通过单击鼠标生成 2 个预制件的实例化版本:瓷砖和球。球可以在方块上生成。

用户还可以删除已生成的对象。这是通过将以下代码放在更新方法的 if(Input.GetMouseButtonDown(0))) 块中实现的:

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);
    }
}

正在删除要删除的对象,但问题是其他不相关且距离较远的对象有时也会同时删除。例如,如果我生成 2 个正方形并在每个正方形上生成一个球,然后删除第一个球,当我删除第一个正方形时,第二个球也会同时删除。有时当一个对象被删除时,另一个对象同时被删除 "un-deleted"!

使用以下代码生成对象:

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

其中 TileOrBall 是正在生成的对象的 class,tileOrBall 是对来自此 class 的两个预制件之一的引用。

那么我处理对象生成或销毁的方法有问题吗?在尝试销毁这些对象的实例时,如何解决不同对象的同时删除(有时是复活)问题?

编辑:

正在将 link 添加到项目的 zip 文件中:

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

要重现该问题,请单击边栏中的方块和网格中任意位置的 "paint" 方块,然后单击边栏中的球并 "paint"被放置。最后,单击橡皮擦图标并通过单击开始删除对象。你会看到你没有点击的对象被删除了,你甚至可能会看到当你尝试删除对象时对象被复活了。

谢谢!

在项目中发现了一些问题。

1。当您执行 Destroy(unitAtMouse); 时,您并没有从光线投射中删除游戏对象。您 ONLY 删除附加到该 GameObject 的 Unit 脚本。

由于删除失败,您将在一处拥有多个 Square GameObjects。这使得以后更难删除,因为您必须多次单击删除,直到最后一个 Square GameObjects 被删除。

要解决此问题,请将 Destroy(unitAtMouse); 替换为 Destroy(unitAtMouse.gameObject);

2。最好将要实例化的 GameObject 设为 GameObject 而不是脚本。例如 public Unit selectedObject; 应该是 public GameObject selectedObject;

3。点击侧边栏中的方形或圆形时,将 eraserSelected 设置为 false。这解决了即使用户在 eraserSelected 模式下再次选择方块时,他们也可以删除甚至创建新方块的问题。如果单击侧边栏中的方形或圆形,您想禁用 eraserSelected。换句话说,如果 setSelectedObject 被调用。

4。擦除按钮也应该像其他按钮一样位于面板下方。否则,它会在某些屏幕分辨率下丢失。

5。固定枚举以使用实际枚举而不是 enum.string

6。修复了球不可见的问题,看起来像是被删除了。发生的事情是球被送到广场后面。通过将球 sortingOrder 设为 1 并将正方形 sortingOrder 设为 0.

来解决此问题

或者,根据@Programmer 的回复,您可以创建一个新脚本,比如 DeletableObject,暂时可以完全为空,并将其附加到球形和方形预制件以及您可能会在未来使用的任何预制件有。然后在上面建议的代码中,更改:

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

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

这样你就可以将脚本附加到你以后制作的任何预制件上,以便能够删除它们。

附带说明一下,如果您要添加/删除大量对象并且性能成为问题,请查看 Object Pooling。事实上,无论如何你都应该研究它,因为这是一个养成的好习惯。