提问人:Nyein Chan 提问时间:5/30/2023 最后编辑:derHugoNyein Chan 更新时间:6/2/2023 访问量:171
即使在调用 Destroy() 之后,该脚本仍在执行
The script is still being executed even after Destroy() was called
问:
在下面的代码中,当玩家生命值达到 0 时,将使用 Destroy() 方法销毁游戏对象。但是在玩游戏时,print() 语句有时会产生 -1。我测试了几次,但它从未显示 -2。这意味着即使在调用 Destroy() 方法后,脚本仍在执行 1 次。我还通过设置 false 来测试启用标志,结果相同。销毁游戏对象或禁用/启用脚本不会立即生效?
private void CheckDamageCollision(Collision2D other)
{
if (!other.gameObject.CompareTag(Constants.TAG_ENEMY) && !other.gameObject.CompareTag(Constants.TAG_OBSTACLE) && !other.gameObject.CompareTag(Constants.TAG_ENEMY_WEAPON)) return;
if (justDamage) return;
--health;
PlayerDamage?.Invoke(health);
if (health < 1)
{
print("Health : " + health);
PlayerDead?.Invoke();
IgnoreLayerMatrix(false);
Destroy(gameObject);
return;
}
StartCoroutine(WaitNextDamageCollide());
}
上面的代码仅在 CollisionEnter 回调中使用。
private void OnCollisionEnter2D(Collision2D other)
{
CheckDamageCollision(other);
}
答:
您提供的代码似乎没问题。但是,很难确定,因为我看不到功能内部的内容,例如PlayerDamage?.Invoke(health);
如果这种情况只是偶尔发生,可能是因为每个帧发生不止一次,并且仅在停用阶段的该帧结束后调用:OnCollisionEnter2D
Destroy()
“如果固定时间步长小于实际帧更新时间,则物理循环可能每帧发生不止一次” - https://docs.unity3d.com/Manual/ExecutionOrder.html
为了避免这种情况,您可以引入一个标志并检查玩家是否没有受到伤害,然后调用所有伤害的东西,并设置为 .将标志设置回帧末尾,此时所有物理更新都已完成。isDamagedThisFrame
isDamagedThisFrame
true
false
private bool isDamagedThisFrame = false;
private void CheckDamageCollision(Collision2D other)
{
if (!other.gameObject.CompareTag(Constants.TAG_ENEMY) && !other.gameObject.CompareTag(Constants.TAG_OBSTACLE) && !other.gameObject.CompareTag(Constants.TAG_ENEMY_WEAPON)) return;
if (justDamage) return;
if (isDamagedThisFrame) return;
isDamagedThisFrame = true;
--health;
PlayerDamage?.Invoke(health);
if (health < 1)
{
print("Health : " + health);
PlayerDead?.Invoke();
IgnoreLayerMatrix(false);
Destroy(gameObject);
return;
}
StartCoroutine(WaitNextDamageCollide());
}
在你的你可以WaitNextDamageCollide()
yield WaitForEndOfFrame
IEnumerator WaitNextDamageCollide() {
// ... your code
yield return new WaitForEndOfFrame();
isDamagedThisFrame = false;
}
评论
Destroy 在帧的末尾调用。您可以使用立即销毁功能,但它有一些性能开销。如果这是一个小游戏,那么请继续使用它。否则,可以将碰撞器设置为“碰撞时禁用”,这样就不会调用下一个 OnCollisionEnter2D,并且脚本将在帧结束时销毁。
评论
DestroyImmediate
Object.Destroy
评论