unity3d 用相同的脚本碰撞两个相同的游戏对象,OnCollisionEnter()执行两次(每个脚本一次)

utugiqy6  于 2023-02-16  发布在  其他
关注(0)|答案(2)|浏览(153)

我有两个完全相同的游戏对象碰撞。
两者都附加了脚本,其中我有OnCollisionEnter()
背景:两支舰队(* 单个游戏对象,脚本:ShipBehaviour *)是战斗和一个有更多的船里面生活,另一个是破坏;
问题是**OnCollisionEnter()*被调用两次(每个游戏对象一次),
因此,
最终计算数量 *(ShipsInside)是其应达到的两倍。

    • OnCollisionEnter(碰撞碰撞)**方法:
if(collision.gameObject.tag == "Ship")
        {
            var shipBehaviour = collision.gameObject.GetComponent<ShipBehaviour>();
            if ( shipBehaviour != null )
            {
                
                    if(shipBehaviour.ShipsInside > ShipsInside)
                    {
                        shipBehaviour.ShipsInside -= ShipsInside;
                        Destroy(gameObject);
                    }
                    else if(shipBehaviour.ShipsInside < ShipsInside)
                    {
                        ShipsInside -= shipBehaviour.ShipsInside;
                        Destroy(shipBehaviour.gameObject);
                    }
                    else if (shipBehaviour.ShipsInside == ShipsInside)
                    {
                        Destroy(gameObject);
                        Destroy(shipBehaviour.gameObject);
                    }
                
            }
            return;
        }

所以我想在一个游戏对象中执行**OnCollisionEnter()**逻辑,并在其他游戏对象中忽略它。
我有个解决办法:简单地加上除以2的计算,那么最后的数字会是准确的。但显然这不是一个正确的方法去做。
有没有更有效的方法来这样做?

46qrfjad

46qrfjad1#

其实你不需要一面旗子。
你的战斗结果是完全对称的,这意味着任何一方是赢家。
因此,在我看来,最简单的解决办法是只让获胜(或交替失败)的一方处理战斗的结果,并做例如。

// Note that your tag check is actually redundant
// this would already be enough and you don't need to remember assigning tags
if(collision.gameObject.TryGetComponent<ShipBehaviour>(out var shipBehaviour))
{             
    if(shipBehaviour.ShipsInside < ShipsInside)
    {
        ShipsInside -= shipBehaviour.ShipsInside;
        Destroy(shipBehaviour.gameObject);
    }
    else if (shipBehaviour.ShipsInside == ShipsInside)
    {
        Destroy(shipBehaviour.gameObject);
    }
}

这应该足够了,因为另一个冲突方已经处理了他们这边的其他情况。
当然,你也可以反过来处理你自己的失败案例。同样的,你可能更喜欢在==案例中只毁灭自己。
如果你不关心这个多余的减法(因为物体无论如何都会被破坏),你甚至可以把它缩短为

if(collision.gameObject.TryGetComponent<ShipBehaviour>(out var shipBehaviour))
{             
    if(shipBehaviour.ShipsInside <= ShipsInside)
    {
        ShipsInside -= shipBehaviour.ShipsInside;
        Destroy(shipBehaviour.gameObject);
    }
}
ktca8awb

ktca8awb2#

您只需添加一个标志即可解决此问题。

private bool _collisionHandled = false;

private void OnCollisionEnter(Collision collision)
{
    if (_collisionHandled || collision.gameObject.tag != "Ship")
    {
        return;
    }

    var shipBehaviour = collision.gameObject.GetComponent<ShipBehaviour>();
    if (shipBehaviour != null)
    {
        if (shipBehaviour.ShipsInside > ShipsInside)
        {
            shipBehaviour._collisionHandled = true;
            shipBehaviour.ShipsInside -= ShipsInside;
            Destroy(gameObject);
        }
        else if (shipBehaviour.ShipsInside < ShipsInside)
        {
            _collisionHandled = true;
            ShipsInside -= shipBehaviour.ShipsInside;
            Destroy(shipBehaviour.gameObject);
        }
        else if (shipBehaviour.ShipsInside == ShipsInside)
        {
            _collisionHandled = true;
            shipBehaviour._collisionHandled = true;
            Destroy(gameObject);
            Destroy(shipBehaviour.gameObject);
        }
    }
}

相关问题