【问题标题】:Destroying object at raycast 2D causes unrelated object to be destroyed在 raycast 2D 中销毁对象会导致不相关的对象被销毁
【发布时间】:2017-05-23 06:49:21
【问题描述】:

在我的游戏中,用户可以通过鼠标点击生成 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 个方格和每个方格上的一个球,然后删除第一个球,当我去删除第一个方格时,同时删除第二个球。有时当一个对象被删除时,另一个对象同时被“取消删除”!

使用以下代码生成对象:

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

其中TileOrBall 是正在生成的对象的类,tileOrBall 是对该类的两个预制件之一的引用。

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

编辑:

添加项目 zip 文件的链接:

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

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

谢谢!

【问题讨论】:

    标签: c# unity3d mouseover instantiation destroy


    【解决方案1】:

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

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

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

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

    2。最好将您要实例化的游戏对象作为游戏对象而不是脚本。例如public Unit selectedObject; 应该是public GameObject selectedObject;

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

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

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

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

    【讨论】:

      【解决方案2】:

      或者,基于@Programmer 的响应,您可以创建一个新脚本,例如DeletableObject,该脚本暂时可以完全为空,并将其附加到球和方形预制件以及您可能拥有的任何未来预制件上。然后在上面建议的代码中,更改:

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

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

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

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

      【讨论】:

      • 感谢您提供指向对象池的链接@Just Another Commenter,我将其添加到我的学习列表中。我有一种感觉,以我现在的方式创建和删除对象效率低下,并且必须有更好的方法,但我也有一种感觉,我读到的很少,对象池可能不是正确的方法。你看,球在这里只是一个代理,它们最终会变成一个集合,这些东西可能太不同而无法汇集。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-13
      • 2017-01-11
      • 2013-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多