Unity 2D обнаружение столкновений с кинематическим жестким телом - PullRequest
0 голосов
/ 23 мая 2019

Просто начните с 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)));
    }
}

Настройка игрока:

enter image description here

Настройка стен:

enter image description here

Почему-то это все еще кажется слишком сложным.Это лучший подход для обнаружения столкновений, или мы делаем это совершенно неправильно, и есть лучшие / более простые способы?Имейте в виду, что мы хотим как-то ходить по прямым углам и не застрять на них.И рядом друг с другом есть перекрывающиеся коллайдеры или коллайдеры.

Спасибо за ваше время!

1 Ответ

0 голосов
/ 23 мая 2019

Если я понимаю, что вы пытаетесь сделать правильно, то вы чрезмерно усложняете это. Если у вас есть два объекта в вашей сцене с коллайдерами, они не будут «переходить друг в друга», если вы позволите 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», тогда игрок не пойдет ни в какой пейзаж.

Я заметил ваш код типа «коррекция пикселей», и хотя сам никогда не использовал ничего подобного, я предполагаю, что вы можете просто использовать его поверх всего этого, и он будет работать нормально.

...