Platform melompat masalah dengan tabrakan AABB

9

Lihat diagram pertama:

Ketika mesin fisika AABB saya menyelesaikan persimpangan, ia melakukannya dengan menemukan sumbu tempat penetrasi lebih kecil, lalu "mendorong keluar" entitas pada sumbu itu.

Mempertimbangkan contoh "melompat bergerak ke kiri":

  • Jika velocityX lebih besar dari velocityY, AABB mendorong entitas keluar pada sumbu Y, secara efektif menghentikan lompatan (hasil: pemain berhenti di udara).
  • Jika velocityX lebih kecil dari velocitY (tidak diperlihatkan dalam diagram), program berfungsi sebagaimana dimaksud, karena AABB mendorong entitas keluar pada sumbu X.

Bagaimana saya bisa menyelesaikan masalah ini?

Kode sumber:

public void Update()
{
    Position += Velocity;
    Velocity += World.Gravity;

    List<SSSPBody> toCheck = World.SpatialHash.GetNearbyItems(this);

    for (int i = 0; i < toCheck.Count; i++)
    {
        SSSPBody body = toCheck[i];
        body.Test.Color = Color.White;

        if (body != this && body.Static)
        {                   
            float left = (body.CornerMin.X - CornerMax.X);
            float right = (body.CornerMax.X - CornerMin.X);
            float top = (body.CornerMin.Y - CornerMax.Y);
            float bottom = (body.CornerMax.Y - CornerMin.Y);

            if (SSSPUtils.AABBIsOverlapping(this, body))
            {
                body.Test.Color = Color.Yellow;

                Vector2 overlapVector = SSSPUtils.AABBGetOverlapVector(left, right, top, bottom);

                Position += overlapVector;
            }

            if (SSSPUtils.AABBIsCollidingTop(this, body))
            {                      
                if ((Position.X >= body.CornerMin.X && Position.X <= body.CornerMax.X) &&
                    (Position.Y + Height/2f == body.Position.Y - body.Height/2f))
                {
                    body.Test.Color = Color.Red;
                    Velocity = new Vector2(Velocity.X, 0);

                }
            }
        }               
    }
}

public static bool AABBIsOverlapping(SSSPBody mBody1, SSSPBody mBody2)
{
    if(mBody1.CornerMax.X <= mBody2.CornerMin.X || mBody1.CornerMin.X >= mBody2.CornerMax.X)
        return false;
    if (mBody1.CornerMax.Y <= mBody2.CornerMin.Y || mBody1.CornerMin.Y >= mBody2.CornerMax.Y)
        return false;

    return true;
}
public static bool AABBIsColliding(SSSPBody mBody1, SSSPBody mBody2)
{
    if (mBody1.CornerMax.X < mBody2.CornerMin.X || mBody1.CornerMin.X > mBody2.CornerMax.X)
        return false;
    if (mBody1.CornerMax.Y < mBody2.CornerMin.Y || mBody1.CornerMin.Y > mBody2.CornerMax.Y)
        return false;

    return true;
}
public static bool AABBIsCollidingTop(SSSPBody mBody1, SSSPBody mBody2)
{
    if (mBody1.CornerMax.X < mBody2.CornerMin.X || mBody1.CornerMin.X > mBody2.CornerMax.X)
        return false;
    if (mBody1.CornerMax.Y < mBody2.CornerMin.Y || mBody1.CornerMin.Y > mBody2.CornerMax.Y)
        return false;

    if(mBody1.CornerMax.Y == mBody2.CornerMin.Y)
        return true;

    return false;
}
public static Vector2 AABBGetOverlapVector(float mLeft, float mRight, float mTop, float mBottom)
{
    Vector2 result = new Vector2(0, 0);

    if ((mLeft > 0 || mRight < 0) || (mTop > 0 || mBottom < 0))
        return result;

    if (Math.Abs(mLeft) < mRight)
        result.X = mLeft;
    else
        result.X = mRight;

    if (Math.Abs(mTop) < mBottom)
        result.Y = mTop;
    else
        result.Y = mBottom;

    if (Math.Abs(result.X) < Math.Abs(result.Y))
        result.Y = 0;
    else
        result.X = 0;

    return result;
}
Vittorio Romeo
sumber

Jawaban:

2

Saya hanya melihat kode saya belum mencoba membuktikan di mana itu salah.

Saya melihat kode dan 2 baris ini tampak aneh:

if ((Position.X >= body.CornerMin.X && Position.X <= body.CornerMax.X) &&
(Position.Y + Height/2f == body.Position.Y - body.Height/2f))

Anda memeriksa interval dan kemudian Anda memeriksa kesetaraan? Saya mungkin salah, (mungkin ada beberapa pembulatan terjadi) tetapi tampaknya itu dapat menyebabkan masalah.

pengguna712092
sumber
0

Sulit membaca kode orang lain, tetapi saya pikir ini adalah satu solusi yang mungkin (murni brainstormed), meskipun tentu saja saya tidak dapat mengujinya:

  1. Sebelum deteksi tabrakan terjadi, simpan kecepatan pemain ke beberapa variabel sementara.
  2. Setelah Anda melakukan respons tabrakan, periksa apakah posisi pemain X atau Y telah diperbaiki
  3. Jika posisi X telah diubah, setel ulang secara manual (sebagai semacam "setel ulang aman") kecepatan pemain Y ke yang ia miliki sebelum respons.

Ngomong-ngomong, apa yang terjadi dengan kode Anda saat ini ketika pemain Anda menyentuh atap sambil melompat?

TravisG
sumber
Mengubah kecepatan tidak akan menyelesaikan apa pun, karena kecepatan tidak terpengaruh oleh respons tabrakan. Responsnya hanya mengubah Posisi pemain, meninggalkan Velocity tidak berubah. Ketika pemain menabrak atap, ia mengapung sebentar lalu kembali turun. Ini dimaksudkan karena saya tidak mengatur Velocity ke 0 ketika menyentuh langit-langit.
Vittorio Romeo
Apa yang terjadi jika Anda menghapus kode yang menetapkan salah satu dari komponen vektor hasil menjadi nol dalam metode GetOverlapVector?
TravisG
Entitas akan terdorong keluar secara diagonal, kadang-kadang bahkan tidak berfungsi dengan benar, lain kali itu hanya terkunci seperti jika berada di grid.
Vittorio Romeo
Saya tidak bisa memahaminya sekarang. Cara entitas Anda didorong keluar harus bergantung pada jaraknya dari tubuh yang bertabrakan dengannya, tetapi algoritma Anda sudah melakukannya. Saya akan melihat lagi besok.
TravisG