ตัวอย่าง Microsoft XNA Platformer การตรวจจับ Collsion มีการใช้งานอย่างถูกต้องหรือไม่


11

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

ฉันอาจผิด แต่นั่นเป็นเพียงวิธีที่ฉันเห็น

   private void HandleCollisions()
        {
            // Get the player's bounding rectangle and find neighboring tiles.
            Rectangle bounds = BoundingRectangle;
            int leftTile = (int)Math.Floor((float)bounds.Left / Tile.Width);
            int rightTile = (int)Math.Ceiling(((float)bounds.Right / Tile.Width)) - 1;
            int topTile = (int)Math.Floor((float)bounds.Top / Tile.Height);
            int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom / Tile.Height)) - 1;

            // Reset flag to search for ground collision.
            isOnGround = false;

            // For each potentially colliding tile,
            for (int y = topTile; y <= bottomTile; ++y)
            {
                for (int x = leftTile; x <= rightTile; ++x)
                {
                    // If this tile is collidable,
                    TileCollision collision = Level.GetCollision(x, y);
                    if (collision != TileCollision.Passable)
                    {
                        // Determine collision depth (with direction) and magnitude.
                        Rectangle tileBounds = Level.GetBounds(x, y);
                        Vector2 depth = RectangleExtensions.GetIntersectionDepth(bounds, tileBounds);
                        if (depth != Vector2.Zero)
                        {
                            float absDepthX = Math.Abs(depth.X);
                            float absDepthY = Math.Abs(depth.Y);

                            // Resolve the collision along the shallow axis.
                            if (absDepthY < absDepthX || collision == TileCollision.Platform)
                            {
                                // If we crossed the top of a tile, we are on the ground.
                                if (previousBottom <= tileBounds.Top)
                                    isOnGround = true;

                                // Ignore platforms, unless we are on the ground.
                                if (collision == TileCollision.Impassable || IsOnGround)
                                {
                                    // Resolve the collision along the Y axis.
                                    Position = new Vector2(Position.X, Position.Y + depth.Y);

                                    // Perform further collisions with the new bounds.
                                    bounds = BoundingRectangle;
                                }
                            }
                            else if (collision == TileCollision.Impassable) // Ignore platforms.
                            {
                                // Resolve the collision along the X axis.
                                Position = new Vector2(Position.X + depth.X, Position.Y);

                                // Perform further collisions with the new bounds.
                                bounds = BoundingRectangle;
                            }
                        }
                    }
                }
            }

            // Save the new bounds bottom.
            previousBottom = bounds.Bottom;
        }

3
ทำไมต้องลบ 1, ppl คำถามนี้ใช้ได้สำหรับฉัน แต่นี่เป็นคำตอบสั้น ๆ : ตัวอย่าง platformer ที่มาพร้อมกับ XNA เป็นเพียงตัวอย่างเท่านั้น เพื่อไม่ให้เป็นแบบอย่างสำหรับเกมของคุณอย่างเคร่งครัด มันคือการแสดงให้คุณเห็นว่าเกมสามารถทำได้ คุณไม่ควรกังวลหากการนำไปใช้นั้นไม่ได้ดีที่สุดเลย
Gustavo Maciel

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

คำตอบ:


12

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

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

ดังนั้นแกนกลางของการเปลี่ยนแปลงที่ฉันทำคือเริ่มที่จะจัดการกับการเคลื่อนไหวบนแกน X อย่างอิสระจากการเคลื่อนที่บนแกน Y ในสองขั้นตอนแยกกัน ฉันเคยเขียนเกี่ยวกับมันมาก่อนในคำตอบนี้มุ่งหน้าไปที่รายละเอียด

และถ้าฉันจำได้อย่างถูกต้องเหตุผลที่แท้จริงของมันคืออะไรแบบนี้:

ป้อนคำอธิบายรูปภาพที่นี่


1
เดวิดมักจะพูดคุยกับ XNA อยู่เสมอ!
Gustavo Maciel

1
@ Gustavo-Gtoknu ฉันรู้สึกว่ามันยังคงต้องการภาพวาดของปัญหา: P
David Gouveia

1
เพิ่งเจอคำตอบนี้ - เยี่ยมมาก! ขอบคุณเดวิด
Austin Brunkhorst

1

เมื่อคุณมีการชนหลายครั้งหากคุณแก้ไขการชนจากที่ใกล้เคียงที่สุดให้ไกลที่สุดจากกึ่งกลางของแต่ละสี่เหลี่ยมที่เกี่ยวข้องคุณจะไม่พบปัญหา "การแขวน"

1) ค้นหาสี่เหลี่ยมที่ชนกันทั้งหมด

2) หากมีมากกว่าหนึ่ง (ขึ้นอยู่กับการใช้งานของคุณกรณีนี้อาจเป็นบ่อยครั้งหรือไม่บ่อยนัก) ให้ค้นหาที่ใกล้เคียงที่สุด

3) แก้ไขการชนกันทีละครั้งและตรวจสอบว่าการชนอื่น ๆ ยังคงมีการชนกันที่ถูกต้องหรือไม่

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

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