Uzyskaj szczegóły kolizji z Rectangle.Intersects ()

9

Mam grę Breakout, w której w pewnym momencie wykrywam kolizję między piłką a wiosłem za pomocą czegoś takiego:

// Ball class
rectangle.Intersects(paddle.Rectangle);

Czy jest jakiś sposób na uzyskanie dokładnych współrzędnych kolizji lub jakichkolwiek szczegółów na jej temat z prądem XNA API?

Myślałem o przeprowadzeniu podstawowych obliczeń, takich jak porównanie dokładnych współrzędnych każdego obiektu w chwili zderzenia. Wyglądałoby to tak:

// Ball class
if((rectangle.X - paddle.Rectangle.X) < (paddle.Rectangle.Width / 2))
    // Collision happened on the left side
else
    // Collision happened on the right side

Ale nie jestem pewien, czy jest to właściwy sposób na zrobienie tego.

Czy macie jakieś wskazówki na temat silnika, którego mógłbym użyć, aby to osiągnąć? A może nawet dobre praktyki kodowania przy użyciu tej metody?

Daniel Ribeiro
źródło

Odpowiedzi:

8

Prostokąty XNA są dość ograniczone. Rectangle.Intersects()Metoda zwraca tylko logiczną wynik, więc trzeba zrobić więcej badań, czy chcesz szczegóły. Możesz jednak użyć tej Rectangle.Intersect(Rectangle, Rectangle)metody, aby uzyskać prostokąt, w którym oba zachodzą na siebie. To da ci trochę informacji o głębokości i lokalizacji.

ssb
źródło
Czy ta get the rectangle where the two overlapfunkcjonalność jest dostępna na XNA APIlub muszę pobrać dodatkowe rzeczy, takie jak Platformer Starter Kit?
Daniel Ribeiro,
1
Która to metoda? Nie pamiętam, że XNA 4.0 obsługuje Rectangle Rectangle.Intersects(...).
ashes999
Ktoś dał mi prawo w stackoverflow: msdn.microsoft.com/en-us/library/…
Daniel Ribeiro
Ok, ze zwróconym prostokątem, jak mogę sprawdzić pozycję wiosła, które uderzyło w piłkę?
Daniel Ribeiro,
Jeśli wiesz, że łopatka i piłka są przecinające się następnie użyć informacji o lokalizacji prostokąta łopatkowe, które sprawdzane w pierwszej kolejności, to znaczy rectangle.Xalbo rectangle.Yczy cokolwiek chcesz uzyskać dostęp.
ssb,
4

Aktualizacja: Jeśli używasz MonoGame, to od wersji beta 3.0 Rectangle Rectangle.Intersect(rectangle, rectangle)nie istnieje. Zamiast tego możesz użyć poniższego kodu z zestawu XNA Platformer.


Możesz pobrać XNA Platformer Starter Kit ( przeniesiony do systemu Windows 7 ). Jest dostarczany z metodą rozszerzenia pomocnika, która zwraca prostokąt opisujący przecięcie dwóch prostokątów:

static class RectangleExtensions
    {
        /// <summary>
        /// Calculates the signed depth of intersection between two rectangles.
        /// </summary>
        /// <returns>
        /// The amount of overlap between two intersecting rectangles. These
        /// depth values can be negative depending on which wides the rectangles
        /// intersect. This allows callers to determine the correct direction
        /// to push objects in order to resolve collisions.
        /// If the rectangles are not intersecting, Vector2.Zero is returned.
        /// </returns>
        public static Vector2 GetIntersectionDepth(this Rectangle rectA, Rectangle rectB)
        {
            // Calculate half sizes.
            float halfWidthA = rectA.Width / 2.0f;
            float halfHeightA = rectA.Height / 2.0f;
            float halfWidthB = rectB.Width / 2.0f;
            float halfHeightB = rectB.Height / 2.0f;

            // Calculate centers.
            Vector2 centerA = new Vector2(rectA.Left + halfWidthA, rectA.Top + halfHeightA);
            Vector2 centerB = new Vector2(rectB.Left + halfWidthB, rectB.Top + halfHeightB);

            // Calculate current and minimum-non-intersecting distances between centers.
            float distanceX = centerA.X - centerB.X;
            float distanceY = centerA.Y - centerB.Y;
            float minDistanceX = halfWidthA + halfWidthB;
            float minDistanceY = halfHeightA + halfHeightB;

            // If we are not intersecting at all, return (0, 0).
            if (Math.Abs(distanceX) >= minDistanceX || Math.Abs(distanceY) >= minDistanceY)
                return Vector2.Zero;

            // Calculate and return intersection depths.
            float depthX = distanceX > 0 ? minDistanceX - distanceX : -minDistanceX - distanceX;
            float depthY = distanceY > 0 ? minDistanceY - distanceY : -minDistanceY - distanceY;
            return new Vector2(depthX, depthY);
        }

        /// <summary>
        /// Gets the position of the center of the bottom edge of the rectangle.
        /// </summary>
        public static Vector2 GetBottomCenter(this Rectangle rect)
        {
            return new Vector2(rect.X + rect.Width / 2.0f, rect.Bottom);
        }
}
ashes999
źródło
Dziękuję bardzo za ten link. Czy mogę zapytać, dlaczego potrzebowałeś zmodyfikowanej wersji? Czy ten port jest oficjalny?
Daniel Ribeiro,
@DanielRibeiro Sprawdziłem swoją historię i najwyraźniej wcale jej nie modyfikowałem. Port jest nieoficjalny; Po prostu nie mogłem znaleźć oryginału. Działa z MonoGame / C #, co było dla mnie wystarczająco dobre.
ashes999
Ale jest oryginalny port, prawda? Czy to nie jest taka prosta funkcja? W każdym razie nie używam MonoGame, tylko XNA. Czy nadal poleciłbyś mi użycie tego portu?
Daniel Ribeiro,
Musiałem udzielić poprawnej odpowiedzi ssb, ale bardzo za to dziękuję. Na pewno dostanę się do tego portu! Wielkie dzięki!
Daniel Ribeiro,
1
@DanielRibeiro ah, rozumiem. Myślę, że ta metoda nie istnieje w MonoGame, dlatego skończyłem z takim podejściem. Na zdrowie.
ashes999