在碰撞回调中防止团结物理中的碰撞力

时间:2016-05-02 20:52:28

标签: unity3d physics

如何防止碰撞在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。

2 个答案:

答案 0 :(得分:0)

我最终让箭头成为触发器。在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;
            }
        }
    }
}

答案 1 :(得分:0)

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

解决此问题而不影响任何内容的最简单方法是更改​​框,箭头或两者的重量。

将包装箱的重量设置为较高的值,将箭头的重量设置为较低的值。

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

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

我不会提出任何建议,但有可能。