Microsoft XNA Platformer Örneği, Collsion Detection doğru bir şekilde uygulandı mı?


11

Microsoft tarafından sağlanan örnek, çarpışma algılamasında (görebildiğim kadarıyla) küçük bir hata olacak gibi görünüyor. Kullanıcı Geçilemeyen bir döşemeyle çarpıştığında, kesişimin derinliği hesaplanır. X ve Y derinlik değerlerinden daha küçük olanı, kullanıcının döşemeyle çarpışmayacak şekilde konumunu sabitlemek için kullanılır. Ancak kullanıcı çapraz olarak seyahat ediyorsa, bu, karakterin döşemeyle ilk çarpıştığı noktada kesin olarak sonuçlanmamasına neden olabilir mi?

Muhtemelen yanılıyorum ama tam da böyle görüyorum.

   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
Neden eksi 1, ppl? Soru benim için geçerli. Ancak kısa bir cevap: XNA ile gelen platform demosu zaten sadece bir örnek. Oyunlarınız için kesinlikle bir model olarak takip edilmemelidir. Size bir oyunun YAPILABİLECEĞİNİ göstermektir. Uygulama hiç de iyi değilse rahatsız etmemelisiniz.
Gustavo Maciel

Teşekkürler, sadece yaptıkları şeyin en iyi yol olduğunu ve bir şeyleri kaçırdığımı varsaydım. Benim için temizlediğin için teşekkürler.
PriestVallon

Yanıtlar:


12

Kesinlikle haklısın . XNA platformer örneğindeki çarpışma rutinleri ile ilgili sorunlardan payımı aldım. Ancak kodda örnekte belirtildiği gibi başlamayı başardım ve attığım her test senaryosunda tutarlı sonuçlar elde edene kadar biraz değiştirdim.

Özellikle, yaşadığım sorun, bir duvara çapraz olarak hareket ederek bir duvar boyunca kaymaya çalışırken oldu. Çünkü örnek yer değiştirme en küçük eksene bağlı olarak çözülmesine çarpışmaları için yapar varsayım, bu bir duvara iterek hareket etmeyi mümkün olmayan karakteri sonuçlandı bazı yöne. Örneğin, bir işaret kullanarak, tavana sarılırken ve soldan sağa doğru hareket etmeye çalışırken takılırım (özellikleri hatırlayamıyorum). İşaretin değiştirilmesi bu durumu çözecektir, ancak karşı senaryoda bir sorun ortaya çıkacaktır. Sonuç olarak, sağlanan uygulama ile her yönden ve her yönden doğru çalışmasını sağlayamadım sağlayamadım - her zaman en az bir vakada başarısız olur.

Yani yaptığım değişikliklerin özü, X ekseni üzerindeki hareketi Y eksenindeki hareketten bağımsız olarak iki ayrı adımda ele almaya başlamaktı. Bu cevapta daha önce yazdım, bu yüzden ayrıntılar için oraya gidin.

Ve doğru hatırlarsam, bunun gerçek nedeni şuydu:

resim açıklamasını buraya girin


1
David her zaman XNA'da pwn ediyor!
Gustavo Maciel

1
@ Gustavo-Gtoknu Hala sorunun çizimine ihtiyaç duyduğunu hissettim: P
David Gouveia

1
Sadece bu cevaba rastladım - harika iş! Teşekkürler David.
Austin Brunkhorst

1

Çarpışmalarınızı, ilgili her bir dikdörtgenin merkezine en yakından en uzağa doğru giderirseniz, "asılı" sorunu yaşamayacaksınız.

1) Tüm çarpışan dikdörtgenleri bulun

2) Birden fazla varsa (kullanım durumunuza bağlı olarak, bu sık veya seyrek olabilir), en yakını bulun.

3) Çarpışmaları teker teker çözün ve diğerlerinin hala geçerli çarpışma olup olmadığını kontrol edin

Kabul edilen cevapta çarpışma ve giriş mantığı çamurludur; başlığı, vb. belirlemek için kontrolleri vardır. Tarif edilen şekilde uygulanması, çarpışma mantığını gerektiğinde mesafe hesaplama pahasına giriş mantığından ayrı tutar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.