【问题标题】:Detect collision/colliding only once只检测一次碰撞/碰撞
【发布时间】:2016-12-23 13:21:55
【问题描述】:

我有一个对象向另一个对象移动并与它发生物理碰撞,我希望该碰撞/碰撞事件只发生一次。我尝试使用bool,但它没有按预期工作。看来我做错了什么。

bool doDamage = true;
void OnCollisionEnter2D(Collision2D other)
{
    if (other.gameObject.tag == "Target" && doDamage)
    {
        doDamage = false;
        // damage code
    }
}

void OnCollisionExit2D(Collision2D other)
{
    if (other.gameObject.tag == "Target")
    {
        doDamage = true;
    }
}

编辑:

我希望“损坏代码”只运行一次,即使 2 个对象仍处于接触状态。此脚本仅分配给 1 个对象,而不是两者。

【问题讨论】:

  • 你的意思是整个碰撞应该只发生一次,第二次这个对象应该表现得像没有碰撞器或者你只是想控制损坏?
  • 我希望整个碰撞只发生一次。
  • 为你的游戏对象准备不同的层。在物理设置中,取消选中这两层的层碰撞矩阵。为两个对象设置相同的图层,并在碰撞后更改其中一个对象的图层。他们不会再碰撞了。您也可以在碰撞后将其中一个碰撞器更改为触发器。
  • 在我的脑海中,我确实认为 OnCollisionEnter2D 只会被调用一次,除非你稍后再次发生碰撞?

标签: c# unity3d collision-detection


【解决方案1】:

我不知道解释为什么您的代码不起作用的最简单方法,但我会尝试。

你有两个游戏对象:

  1. GameObject A 带有 doDamage 变量。

  2. GameObject B 带有doDamage 变量。

GameObject AGameObject B 碰撞时:

AGameObject A 上调用了OnCollisionEnter2D 函数。 if(other.gameObject.tag == "Target" && doDamage) 执行是因为 doDamage 为真。

BGameObject A 中的doDamage 变量随后被设置为false

这不会影响 GameObject B 中的 doDamage 变量。

然后

CGameObject B 上调用了OnCollisionEnter2D 函数。 if(other.gameObject.tag == "Target" && doDamage) 执行是因为 doDamage 为真。

DGameObject B 中的doDamage 变量随后被设置为false

您的两个损坏代码都会运行,因为 doDamage 在每个 OnCollisionEnter2D 调用中始终为真。您当前所做的只是影响每个 individual 脚本中的 doDamage 变量。

你目前在做什么

local/this脚本中的doDamage设置为false,同时检查是否设置了local/this doDamage

你需要做什么

other 脚本中的 doDamage 设置为 false,但阅读 local/this doDamage 以检查它是否已设置。

它应该是这样的:

public class DamageStatus : MonoBehaviour
{
    bool detectedBefore = false;

    void OnCollisionEnter2D(Collision2D other)
    {
        if (other.gameObject.CompareTag("Target"))
        {
            //Exit if we have already done some damage
            if (detectedBefore)
            {
                return;
            }

            //Set the other detectedBefore variable to true
            DamageStatus dmStat = other.gameObject.GetComponent<DamageStatus>();
            if (dmStat)
            {
                dmStat.detectedBefore = true;
            }

            // Put damage/or code to run once below

        }
    }

    void OnCollisionExit2D(Collision2D other)
    {
        if (other.gameObject.tag == "Target")
        {
            //Reset on exit?
            detectedBefore = false;
        }
    }
}

【讨论】:

  • 很抱歉我之前没有指出这一点,但这个脚本只分配给 1 个游戏对象,而不是两者。
  • 那检测一次是什么意思?
  • 当第一个物体撞击第二个物体时,碰撞保持活跃,第一个物体继续造成伤害。我希望碰撞事件中的损坏代码只运行一次。
【解决方案2】:

如果你想运行一次sn-p代码,直接在你想触发你的代码的回调事件中运行代码。

void OnCollisionEnter2D(Collision2D other)
{
    DoSomeDamageTo(other.gameObject);
}

这应该只在碰撞时触发一次。

如果您希望这种情况只发生一次(例如,如果持有脚本的物体再次撞击某物),您需要一个标志来说明损坏已经造成:

bool hasHitSomething = false;
void OnCollisionEnter2D(Collision2D other)
{
    if (!hasHitSomething)
    {
        DoSomeDamageTo(other.gameObject);
        hasHitSomething = true;
    }
}

我怀疑鉴于您共享的代码,这些对象在引擎中多次碰撞(如果它们是实体且受物理控制的,则很有可能),导致OnCollisionEnter 被多次调用。 OnCollisionEnter should only be called once per collision. 如果您观察到它被多次调用,那么您实际上是在观察多次碰撞,或者您发现了一个不起眼的 Unity 错误。前者的可能性更大,更多

【讨论】:

  • 你的代码的第一部分和我正在做的没有什么不同。
猜你喜欢
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-05
  • 2019-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多