การตรวจจับการชนกันของกระเบื้องที่มีประสิทธิภาพสำหรับสี่เหลี่ยมจำนวนมากหรือไม่


9

ขณะนี้ฉันกำลังทำเกมตามแบบตัวเอง (คิดว่า Terraria แต่แปลกน้อยกว่านี้ (ฉันคิดว่านั่นเป็นคำหรือไม่ขออภัยถ้าไม่ใช่)

อย่างไรก็ตามตอนนี้ฉันมีระบบตรวจจับการชนกันของข้อมูลทำงานได้ดี มีบางสิ่งที่น่ายินดีเป็นอย่างยิ่งที่ได้เห็นผีสางไม่วิ่งผ่านบล็อก แต่แล้วฉันก็มีความคิดที่จะสร้างมาตรฐาน ความคิดที่ไม่ดี

1,000 สี่เหลี่ยมไม่มีปัญหา 10,000 สแควร์สำหรับ 3 ตัวอักษรเป็นความล่าช้า 100,000 squares (แผนที่ใหญ่มาก) สำหรับ 3 ตัวละครนั้นเล่นไม่ได้

ฉันมีปัญหาที่ฉันไม่ต้องการพิจารณาบล็อกที่อยู่ไกลจากผู้เล่นตัวละครไอเท็ม ฯลฯ แต่ฉันไม่ต้องการโหลดหน่วยความจำที่เหลืออยู่เหล่านั้นอย่างต่อเนื่อง

นี่คืออัลกอริทึมของฉันจนถึงตอนนี้อย่าลังเลที่จะวิจารณ์

foreach (Block in level)
{
    if (distance from block to player > a specified amount)
        ignore this block;
    else
    {
        get the intersection depth between the two bounding boxes
        if (depth of intersection != Zero-vector)
        {
            check y size vs x size
            resolve on smallest axis
        }
    }
}

ดังที่คุณจะทราบเมื่อขนาดของเลเวลใหญ่ขึ้นลำดับของอัลกอริทึมนี้จะเพิ่มขึ้นตามบล็อค N ฉันไม่ต้องการพิจารณาบล็อกที่ไม่ได้อยู่ใกล้กับผู้เล่น

ฉันคิดว่าอาจจะใช้ (0,0) ถึง (mapWidth, mapHeight) สองแถวของบล็อกแทนที่จะเป็นรายการคำนวณเขตอันตรายขึ้นอยู่กับตำแหน่งของบุคคลเช่นถ้าตำแหน่งผู้เล่นอยู่ที่ (10, 20) มันจะดูจาก (0, 10) ถึง (20, 30) หรืออื่น ๆ

ความคิดและการพิจารณาใด ๆ ที่ยอดเยี่ยมขอบคุณ


1
และยินดีต้อนรับสู่ stackexchange! :-) อย่าลืมอ่านคำถามที่พบบ่อยหากคุณไม่ทราบว่าระบบประกันคุณภาพและชื่อเสียงทั้งหมดทำงานอย่างไร
David Gouveia

แน่นอนว่าแผ่นเหล่านี้มีขนาดใหญ่กว่า 16 x 16 พิกเซลที่ 1920 ถึง 1080 ที่ 8,100 ไทล์ แน่นอนคุณรู้ว่าหน่วยงานที่เคลื่อนย้ายได้อยู่ที่ไหนและคุณสามารถตรวจสอบไทล์บนกริดที่อาจอยู่ในช่วง (ถ้ามี 160 * 160 และศูนย์กลางอยู่ในไทล์ (12,12) คุณจำเป็นต้องตรวจสอบระหว่างไทล์ (6) , 6) และ (18,18) รวมไพ่ที่เป็นไปได้ประมาณ 150 รายการ) กระเบื้องที่อยู่ภายใต้แรงโน้มถ่วงจะล้มลงเท่านั้นดังนั้นคุณต้องมองหากระเบื้องถัดไปที่อยู่ด้านล่าง
DampeS8N

คุณคิดว่า 16x16 นั้นเล็กเกินไปหรือไม่ ฉันคงไม่ยากที่จะเปลี่ยนขนาดของกระเบื้องเนื่องจากสิ่งใดก็ตามที่อ้างอิงถึงความกว้างของกระเบื้อง / ความสูงนั้นคงที่ สิ่งที่ฉันต้องทำก็คือขยายมันใน Paint.NET ซึ่งดีมากเพราะมันเพิ่มรายละเอียดมากขึ้น
Ross

คุณต้องการแบ่งปันรหัสการชนกันหรือไม่ : /
ashes999

คำตอบ:


7

ใช่คุณคิดอย่างถูกต้อง คุณควรใช้อาร์เรย์แบบเรียงต่อกันของแบบสองมิติตั้งแต่ที่ช่วยให้คุณสามารถจัดทำดัชนีกระเบื้องตามตำแหน่ง

Block[,] level = new Block[width, height];

และเนื่องจากผู้เล่นสามารถชนกับไพ่โดยรอบเท่านั้นจำนวนการตรวจสอบการชนที่คุณต้องทำมีน้อยมาก แน่นอนนี้ขึ้นอยู่กับขนาดของผู้เล่น ตัวอย่าง Platformerไม่ได้เช่นนี้

int leftTile = (int)Math.Floor((float)characterBounds.Left / tileWidth);
int rightTile = (int)Math.Ceiling(((float)characterBounds.Right / tileWidth)) - 1;
int topTile = (int)Math.Floor((float)characterBounds.Top / tileHeight);
int bottomTile = (int)Math.Ceiling(((float)characterBounds.Bottom / tileHeight)) - 1;

for (int y = topTile; y <= bottomTile; ++y)
{
    for (int x = leftTile; x <= rightTile; ++x)
    {
        // Handle collisions with the tile level[x,y] just like you were doing!
    }
}

ตรวจสอบตัวอย่างถ้าคุณยังคงมีปัญหาใด ๆ


นี่เป็นอัลกอริทึมเล็ก ๆ ที่ดีมากฉันไม่เคยได้ยินแม้แต่ตัวอย่าง Platformer (ฉันควรมี แต่ฉันอ้างว่าไม่รู้) ขอบคุณ!
Ross

@Ross จริงเหรอ? คุณจะประหลาดใจที่โซลูชันของคุณมีความคล้ายคลึงกับตัวอย่างอย่างไร :-) ลบส่วนของรายการทุกอย่างอื่นเหมือนกันมาก (กล่องตัดกัน, รับความลึกของจุดตัด, แก้ไขบนแกนที่เล็กที่สุด)
David Gouveia

1
โอ้มนุษย์ฉันแค่ดูมัน >. <หวังว่าฉันรู้เรื่องนี้เมื่อ 2 วันก่อน !! ฉันยังใหม่กับ XNA แต่ฉันได้แก้ไขด้วยกราฟิก 2D (แค่ OpenGL ไม่ใช่การเขียนโปรแกรมเกมมาก) ฉันเดาว่าฉันควรตรวจสอบแหล่งข้อมูลเพิ่มเติมก่อนที่จะเริ่มเขียนโปรแกรมก่อน
Ross

1

ฉันเดาคำตอบของฉันจะเป็นคำตอบของคุณ! ;-)

หากคุณมีตำแหน่งผู้เล่น (และขนาด) คุณสามารถคำนวณดัชนีของกระเบื้องรอบข้าง (ซึ่งเป็นเพียงรายละเอียดเดียวที่จะทำการตรวจสอบโดยละเอียด) วิธีนี้จะไม่เกี่ยวข้องกับแผนที่ของคุณใหญ่เพียงใดขึ้นอยู่กับขนาดที่แท้จริงของผู้เล่นของคุณซึ่งจะทำให้มีการตรวจสอบไทล์มากขึ้น

อาจตรวจสอบการสอนเกี่ยวกับการชนกันที่ riemers.net หากคุณยังไม่มี


ฉันได้ยินชื่อของ Riemer แล้ว แต่ไม่เคยได้ดูเลยขอบคุณ!
Ross

1

เมื่อต้องรับมือกับการชนจำนวนมากคุณมักต้องการนำโครงสร้างขั้นสูงมาใช้เช่น Quadtree หรือ Hashmap เพื่อตรวจสอบการชนเหล่านั้น

เนื่องจากกระเบื้องคงที่ฉันแนะนำให้ใช้Quadtree ต้นไม้รูปสี่เหลี่ยมประกอบด้วยสี่คน แต่ละรูปสี่เหลี่ยมประกอบด้วยสี่รูปสี่เหลี่ยมและรูปสี่เหลี่ยมแต่ละรูปนั้นเป็นรูปสี่สี่สี่ สิ่งนี้จะดำเนินต่อไปจนถึงขนาดที่ระบุซ้ำ แต่ละ Quad สามารถมีรายการของไพ่ที่อาศัยอยู่ในพื้นที่ของหน้าจอ ด้วยวิธีนี้เมื่อคุณตรวจสอบการชนคุณสามารถ

  1. จำกัด การตรวจสอบกับผู้ที่อยู่ในบริเวณใกล้เคียง
  2. จำกัด การตรวจสอบเฉพาะวัตถุที่กำลังเคลื่อนที่

ตอนนี้ถ้าคุณไม่อยากแม้แต่จะมองที่หน้าจอไทล์คุณก็สามารถทำสิ่งต่างๆได้เช่นกัน

public bool CheckCollision(myPosition) {
    if(quadNodes.Count > 0) {
        // This is not a leaf, keep checking
        foreach(Quad node in quadNodes) {
            if(node.Position is insideViewport && nearPlayer)
                // Continue recursion
            }
        }
    }
    else {
        // This is a leaf, do checks
        foreach(Tile tile in tileList) {
            if(collision)
                return true;
        }
        return false;
    }
}

อืมฉันเคยได้ยิน Octrees ในการตรวจจับการชนกันแบบ 3 มิติ แต่ไม่เคยเห็นโครงสร้างข้อมูลขั้นสูงที่ใช้สำหรับการตรวจจับการชนกันแบบ 2D ขอบคุณมาก!
Ross

1
เนื่องจากเกมของเขา (สมมติว่า Terraria) ประกอบด้วยกระเบื้องที่เว้นระยะเท่ากันการใช้กริดจะทำให้ทั้งง่ายขึ้นและเร็วขึ้นกว่าควอดทรี ควอดทรีทำงานได้ดีขึ้นสำหรับโลกที่ซับซ้อนมากขึ้นซึ่งกริดจะยากต่อการประกอบและทุกอย่างมีขนาดตามอำเภอใจ
David Gouveia

1
คุณพูดถูกถ้าเป็นเกมที่ใช้กริดล้วนๆแม้จะเป็นขนาดตัวละครก็ตาม ฉันรู้ว่าใน Terraria พวกเขายังมีสัตว์ประหลาดที่ไม่เหมาะกับรูปแบบกริด ฉันทำงานภายใต้สมมติฐานว่าโลกพื้นฐานทำจากกระเบื้อง แต่วัตถุอื่น ๆ จะแตกต่างกันและพวกเขาสามารถเก็บไว้ในโครงสร้างที่คล้ายกันเพื่อหลีกเลี่ยงการสร้างอีก ฉันคิดว่าพวกเขาสามารถใช้ตารางสำหรับกระเบื้องจากนั้นโครงสร้างที่แตกต่างกัน (หากจำเป็น) สำหรับวัตถุอื่น
Mike Cluck

1
นั่นคือสิ่งที่ฉันกำลังจะแนะนำ :) ควรใช้กริดเพื่อจัดการการชนกับภูมิประเทศในขณะที่ quadtree สามารถใช้เพื่อจัดการการชนกันของวัตถุ
David Gouveia

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