运动刚体的Unity 2D碰撞检测

时间:2019-05-22 21:24:45

标签: unity3d collision-detection game-physics game-development

只是从Unity开始,所以请耐心等待:)我们正在构建类似Zelda的游戏-自上而下,没有物理/引力,地图的图块。由于它背后的所有物理原理,我们不想使用动态刚体。

图块贴图具有“ Walls”,CompositeCollider2D和静态刚体,我们的播放器具有CircleCollider2D和运动刚体。播放器和墙壁都具有零摩擦的物理材料。

使用运动刚体进行碰撞检测的最佳方法是什么?我们有几个类似Physics2D.CircleCast的概念,但是最终我们的玩家被卡在墙壁上或被卡在角落(玩家应在角落处平稳移动)或被两个重叠的对撞机卡住。

我们想出的最好的解决方案是(玩家有时仍会碰到对撞机,但至少不再卡住了。)

// MoveDirection is the movement input
movement = MoveDirection * Speed * Time.deltaTime;

List<RaycastHit2D> results = new List<RaycastHit2D>();
List<RaycastHit2D> resultsX = new List<RaycastHit2D>();
List<RaycastHit2D> resultsY = new List<RaycastHit2D>();

if (movement.x != 0)
{
    actorCollider.Cast(new Vector2(movement.x, 0), filter, resultsX, movement.magnitude);
    results.AddRange(resultsX);
}

if (movement.y != 0)
{
    actorCollider.Cast(new Vector2(0, movement.y), filter, resultsY, movement.magnitude);
    results.AddRange(resultsY);
}

foreach (RaycastHit2D hit in results)
{
    Vector2 normal = hit.normal;

    float projection = Vector2.Dot(movement, normal);

    if (projection < 0)
    {
        if (hit.distance > 0)
        {
            projection += Mathf.Max(hit.distance - 0.01f, 0);
        }

        movement -= projection * normal;
    }
}

// move player
newPosition = body.position + movement;

// make sure the player is positioned at pixel perfect positions
newPosition.x = (Mathf.Round(newPosition.x * 16) / 16);
newPosition.y = (Mathf.Round(newPosition.y * 16) / 16);
body.MovePosition(newPosition);

// this part moves the player back in case it is in a collider.
List<Collider2D> colliderList = new List<Collider2D>();
if (actorCollider.OverlapCollider(filter, colliderList) > 0)
{
    foreach (Collider2D hit in colliderList)
    {
        var distance = hit.Distance(actorCollider);
        body.MovePosition(body.position + (distance.normal * Mathf.Abs(distance.distance)));
    }
}

玩家设置:

enter image description here

墙设置:

enter image description here

以某种方式仍然感觉太复杂了。这是进行碰撞检测的最佳方法,还是我们做错了,并且有更好/更容易的方法?请记住,我们希望能够以某种方式绕直角走而不被卡住。而且有相互重叠的对撞机。

谢谢您的时间!

1 个答案:

答案 0 :(得分:0)

如果我了解您要正确执行的操作,那么您将使其复杂化。如果您的场景中有两个带碰撞器的对象,并且让Unity为您移动,它们将不会“进入彼此”。

我的意思是,与其使用Player.Transform.position = new Vector3(Player.Transform.position.x + 1, Player.Transform.position.y, Player.transform.position.z)之类的动作来执行运动,不如将RigidBody2D组件附加到您的播放器并使用myRigidBody = GetComponent<RigidBody2D>();之类的代码来引用它,然后在您的运动中您只需使用myRigidBody.velocity = new Vector3(moveSpeed, myRigidBody.velocity.y, myRigidBody.velocity.z)之类的功能来移动播放器。然后,只要玩家有一个对撞机,您不想让它进入的对象就会有一个对撞机,并且没有对撞机打上“ isTrigger”,那么玩家就不会进入任何风景。

我确实注意到了您的“像素校正”类型代码,尽管我自己从未使用过类似的代码,但我认为您可以在此工具之上使用它,并且可以正常工作。