【问题标题】:Prevent Collision Forces in Unity Physics in Collision Callback在碰撞回调中防止 Unity Physics 中的碰撞力
【发布时间】:2016-05-02 20:52:28
【问题描述】:

如何防止碰撞在 Unity 中施加力?我正在使用 2D 物理,并希望将箭头插入板条箱。我可以在碰撞回调中轻松移除刚体和碰撞器,但似乎仍然对箭头施加了一帧碰撞力,导致位置和旋转发生轻微跳跃。碰撞回调中刚体上的 isKinematic 设置似乎也不会阻止施加这一帧的力。

我希望告诉 Unity 不要为碰撞应用物理。

在箭的整个生命周期中使用运动学不是一种选择,因为箭需要真实地飞行,直到它击中某物。

这是处理碰撞的 crate 对象的代码:

protected virtual void HandleCollision(ArrowScript arrow, Collision2D coll)
{
    StickArrow(arrow, coll);

    if (DestroyAfterSeconds >= 0.0f)
    {
        Destroy(arrow.gameObject, DestroyAfterSeconds);
    }
}

private void OnCollisionEnter2D(Collision2D coll)
{
    ArrowScript script = coll.gameObject.GetComponent<ArrowScript>();
    if (script != null)
    {
        HandleCollision(script, coll);
    }
}

private bool StickArrow(ArrowScript arrow, Collision2D coll)
{
    Vector2 surfaceNormal = coll.contacts[0].normal;
    float surfaceAngle = Mathf.Atan2(surfaceNormal.y, surfaceNormal.x);
    float arrowAngle = Mathf.PI + (arrow.transform.eulerAngles.z * Mathf.Deg2Rad);
    float angleDifference = Mathf.Abs(BowAndArrowUtilities.DifferenceBetweenAngles(surfaceAngle, arrowAngle));
    float penetration = arrow.PercentPenetration * PenetrationPercentageModifier * (1.0f - angleDifference);
    if (penetration <= MinimumPenetrationPercentage)
    {
        arrow.PercentPenetration = 0.0f;
        return false;
    }

    // Make the arrow a child of the thing it's stuck to
    arrow.transform.parent = transform;
    arrow.gameObject.transform.Translate(new Vector3(-penetration * arrow.Length, 0.0f, 0.0f));

    SpriteRenderer thisSpriteRenderer = GetComponent<SpriteRenderer>();
    if (thisSpriteRenderer != null)
    {
        arrow.GetComponent<SpriteRenderer>().sortingLayerID = thisSpriteRenderer.sortingLayerID;
        arrow.GetComponent<SpriteRenderer>().sortingOrder = Mathf.Max(0, thisSpriteRenderer.sortingOrder - 1);
    }

    BowAndArrowUtilities.PlayRandomSound(arrow.CollisionAudioClips, penetration * 5.0f);

    // destroy physics objects from the arrow (rigid bodies, colliders, etc.). This unfortunately doesn't prevent this frame from apply force (rotation, position) to the arrow.
    arrow.DestroyPhysicsObjects();

    return true;
}

Unity 版本是 5.3.4。

【问题讨论】:

  • 你试过检查使用运动学吗?我可能会离开,但我认为这可能会完成你正在寻找的东西。看这里:docs.unity3d.com/Manual/class-Rigidbody.html
  • 设置运动学可以防止箭头在空中飞行,所以它不是一个选项。碰撞后在脚本中设置 isKinemtic 对跳跃性没有影响。
  • 在对象之间没有实际物理交互的情况下发生碰撞的简单解决方法是从对象中移除任何碰撞器但保留其刚体。设置它的速度或AddForce() 以使对象移动。然后,在每次物理计算中使用其先前的位置,执行从那里到对象当前位置的光线投射。如果有撞击,来自光线投射的RaycastHit 应该使脸部正常,然后您可以在碰撞处理中使用它。 (如果您需要将此示例写入代码,请告诉我。)
  • 一个想法。如您所知,在游戏中无处不在,您(令人惊讶的是“消费者”)实际上在不同时间将整个预制件换成不同的预制件(例如,去玩布娃娃,上车 - 无论如何)。关于您描述的情况,在某些情况下,我们会在联系时这样做。只是要记住一个想法。
  • @JoeBlow 这是一个很好的解决方案。你应该回答这个

标签: unity3d physics


【解决方案1】:

我最终把箭头变成了扳机。在 OnTriggerEnter2D 内部,然后我在箭头指向的方向上执行一个圆形投射,其宽度为箭头精灵的宽度。触发器不受 Unity 物理计算的影响。

private void OnTriggerEnter2D(Collider2D coll)
{
    ArrowScript script = coll.gameObject.GetComponent<ArrowScript>();
    if (script != null)
    {
        Vector2 dir = -script.ArrowHead.transform.right;

        // ray cast with the arrow size y value (thickness of arrow)
        RaycastHit2D[] hits = Physics2D.CircleCastAll(script.ArrowHead.transform.position, script.Size.y, dir);
        foreach (RaycastHit2D hit in hits)
        {
            // collider2d is a member variable assigned in Start that is the Collider2D for this object
            if (hit.collider == collider2d)
            {
                HandleCollision(script, hit.normal);
                break;
            }
        }
    }
}

【讨论】:

  • 这正是我要告诉你的,但你及时发现了 ;) 你应该避免调用 GetComponent,尝试使用标签或其他东西进行识别,然后当你识别出你的碰撞时,然后你尝试获取组件。始终牢记性能。
【解决方案2】:

您的问题是 OnCollisionEnter 和 OnTriggerEnter 在所有冲突都解决后被调用。

在不影响任何东西的情况下解决此问题的最简单方法是更改​​框、箭头或两者的重量。

将箱子的重量设置为高值,将箭头的重量设置为低值。

另一种方法是使用触发对撞机,就像您所做的那样。然而,触发对撞机有问题的副作用。例如,它不会在 crate 上调用 OnCollisionEnter 或 OnTriggerEnter。您必须在箭头脚本中执行所有逻辑,这不是什么大问题。

然而,还有很多其他丑陋的 hack。您可以在撞击后将箱子的速度设置为 0,但如果您在箱子移动时撞到箱子,它会冻结箱子。您可以使用碰撞信息来取消施加到板条箱的力以解决碰撞。您可以在每帧保存 crate 的最后一个速度,并在 OnCollision 调用期间将其重新应用到刚体。

我不会建议任何这些,但它们是可能的。

【讨论】:

    猜你喜欢
    • 2015-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多