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

问题描述 投票:0回答:1

刚刚开始使用 Unity,所以请耐心等待 :) 我们正在构建一款类似塞尔达 (Zelda) 的游戏 - 自上而下,没有物理/重力,地图上有瓦片地图。我们不想使用动态刚体,因为它背后的物理原理。

图块地图有“墙”,带有 CompositeCollider2D 和静态刚体,我们的玩家有 CircleCollider2D 和运动学刚体。玩家和墙壁都有零摩擦的物理材质。

运动刚体碰撞检测的最佳方法是什么?我们有几个概念,例如Physics2D.CircleCastAll,但最终我们的玩家卡在墙壁中或卡在角落(玩家应该在拐角处平滑移动)或卡在两个重叠的碰撞器中。

我们想出的最佳解决方案是这样的(玩家有时仍然会遇到碰撞器,但至少不会再被卡住)。

// 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)));
    }
}

播放器设置:

墙壁设置:

不知怎么的,还是感觉太复杂了。这是进行碰撞检测的最佳方法还是我们做得完全错误并且有更好/更简单的方法?请记住,我们希望能够以某种方式绕过直角,而不是被困在上面。并且有重叠的碰撞器或彼此相邻的碰撞器。

感谢您的宝贵时间!

unity-game-engine collision-detection game-physics game-development
1个回答
0
投票

如果我理解你想要正确做的事情,那么你就让这件事变得过于复杂了。如果场景中有两个带有碰撞器的对象,如果您让 Unity 为您进行移动,它们将不会“相互碰撞”。

我的意思是,您可以将 RigidBody2D 组件附加到您的播放器,并使用类似

Player.Transform.position = new Vector3(Player.Transform.position.x + 1, Player.Transform.position.y, Player.transform.position.z)
的东西在代码中引用它,而不是使用类似
myRigidBody = GetComponent<RigidBody2D>();
的东西来执行运动,然后在您的运动函数中,您只需使用一些东西像
myRigidBody.velocity = new Vector3(moveSpeed, myRigidBody.velocity.y, myRigidBody.velocity.z)
一样移动玩家。然后,只要玩家有碰撞器,您希望它不进入的对象也有碰撞器,并且所有碰撞器都没有勾选“isTrigger”,那么玩家就不会进入任何场景。

我确实注意到你的“像素校正”类型代码,虽然我自己从未使用过类似的东西,但我认为你可以在这些东西之上使用它,它会工作得很好。

© www.soinside.com 2019 - 2024. All rights reserved.