ปัญหาการข้ามแพลตฟอร์มด้วยการชน AABB


9

ดูแผนภาพแรก:

เมื่อเอนจิน AABB ฟิสิกส์ของฉันแก้ไขการตัดกันมันจะทำเช่นนั้นโดยการค้นหาแกนที่การแทรกซึมมีขนาดเล็กลงจากนั้น "ผลัก" เอนทิตีบนแกนนั้น

พิจารณาตัวอย่าง "การย้ายที่กำลังกระโดดซ้าย"

  • ถ้า velocityX ใหญ่กว่า velocityY AABB จะผลักเอนทิตีออกไปบนแกน Y แล้วหยุดการกระโดดได้อย่างมีประสิทธิภาพ (ผลลัพธ์: ผู้เล่นหยุดกลางอากาศ)
  • ถ้า velocityX มีขนาดเล็กกว่า velocitY (ไม่แสดงในแผนภาพ) โปรแกรมทำงานตามที่ตั้งใจไว้เพราะ AABB ผลักเอนทิตีออกไปบนแกน X

ฉันจะแก้ปัญหานี้ได้อย่างไร

รหัสแหล่งที่มา:

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

คำตอบ:


2
  • ทดสอบฟังก์ชั่นการสนับสนุนทั้งหมดของคุณ (ในรายการรหัสที่สอง) หากคุณยังไม่ได้ดำเนินการ
  • เห็นภาพหรือพิมพ์ไปยังเอาต์พุตมาตรฐานสิ่งที่วัตถุเหล่านี้ทำ ตรวจสอบให้แน่ใจว่าคุณรู้ว่าแต่ละรหัสทำอะไรและทำอย่างสมบูรณ์
  • มีข้อมูลเชิงลึกเกี่ยวกับการชนมากมายที่http://www.flipcode.com/archives/Theory_Practice-Issue_01_Collision_Detection.shtml

ฉันเพิ่งดูรหัสฉันไม่ได้พยายามพิสูจน์ว่ามันผิดตรงไหน

ฉันดูโค้ดแล้ว 2 บรรทัดนี้ดูแปลก ๆ :

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

คุณตรวจสอบช่วงเวลาและจากนั้นคุณตรวจสอบ euquality? ฉันอาจจะผิด (อาจมีการปัดเศษโสมเกิดขึ้น) แต่ดูเหมือนว่ามันอาจทำให้เกิดปัญหา


0

เป็นการยากที่จะอ่านรหัสของคนอื่น แต่ฉันคิดว่านี่เป็นวิธีหนึ่งที่เป็นไปได้ (การระดมสมองล้วนๆ) แต่ก็แน่นอนว่าฉันไม่สามารถทดสอบได้:

  1. ก่อนการตรวจจับการชนเกิดขึ้นให้บันทึกความเร็วของผู้เล่นในตัวแปรชั่วคราวบางอย่าง
  2. หลังจากเสร็จสิ้นการตอบสนองการชนให้ตรวจสอบว่าตำแหน่งผู้เล่น X หรือ Y ได้รับการแก้ไขหรือไม่
  3. หากตำแหน่ง X ถูกเปลี่ยนให้รีเซ็ตด้วยตนเอง (เป็น "การรีเซ็ตความปลอดภัย" ด้วยตนเอง) ผู้เล่นความเร็ว Y เป็นความเร็วที่เขามีก่อนการตอบสนอง

โดยวิธีการที่เกิดขึ้นกับรหัสปัจจุบันของคุณเมื่อผู้เล่นของคุณถึงหลังคาขณะกระโดด?


การเปลี่ยนความเร็วจะไม่แก้ปัญหาอะไรเลยเพราะความเร็วนั้นไม่ได้รับผลกระทบจากการตอบสนองการชน การตอบสนองเพียงแค่เปลี่ยนตำแหน่งของผู้เล่นโดยไม่เปลี่ยนแปลง Velocity เมื่อผู้เล่นชนกับหลังคามันลอยไปครู่หนึ่งจากนั้นกลับลงมา มันตั้งใจเพราะฉันไม่ได้ตั้งค่าความเร็วเป็น 0 เมื่อมันกระทบเพดาน
Vittorio Romeo

จะเกิดอะไรขึ้นถ้าคุณลบรหัสที่ตั้งค่าหนึ่งในผลลัพธ์เวกเตอร์ขององค์ประกอบเป็นศูนย์ในวิธี GetOverlapVector
TravisG

เอนทิตีถูกผลักออกแนวทแยงมุมบางครั้งก็ไม่สามารถทำงานได้อย่างถูกต้องอีกครั้งบางครั้งมันก็ยึดมันเหมือนว่ามันอยู่ในตาราง
Vittorio Romeo

ฉันไม่สามารถเข้าใจได้ในตอนนี้ วิธีที่เอนทิตีของคุณถูกผลักควรขึ้นอยู่กับระยะทางจากร่างกายที่มันชนกัน แต่อัลกอริทึมของคุณทำสิ่งนั้นแล้ว พรุ่งนี้ฉันจะพิจารณาอีกครั้ง
TravisG
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.