Obtenga detalles de colisión de Rectangle.Intersects ()

9

Tengo un juego Breakout en el que, en algún momento, detecto la colisión entre la pelota y la pala con algo como esto:

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

¿Hay alguna manera de obtener las coordenadas exactas de la colisión, o algún detalle al respecto, con la corriente XNA API?

Pensé en hacer algunos cálculos básicos, como comparar las coordenadas exactas de cada objeto en el momento de la colisión. Se vería algo así:

// 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

Pero no estoy seguro de que esta sea la forma correcta de hacerlo.

¿Ustedes tienen algún consejo sobre tal vez un motor que podría tener que usar para lograr eso? ¿O incluso buenas prácticas de codificación con este método?

Daniel Ribeiro
fuente

Respuestas:

8

Los rectángulos de XNA son bastante limitados. El Rectangle.Intersects()método solo devuelve un resultado booleano, por lo que deberá realizar más pruebas usted mismo si desea detalles. Sin embargo, puede utilizar el Rectangle.Intersect(Rectangle, Rectangle)método para obtener el rectángulo donde se superponen los dos. Eso le dará alguna información sobre profundidad y ubicación, al menos.

ssb
fuente
¿Esta get the rectangle where the two overlapfuncionalidad está disponible en el XNA APIo tengo que descargar algunas cosas adicionales, como el Platformer Starter Kit?
Daniel Ribeiro
1
¿Qué método es este? No recuerdo que XNA 4.0 sea compatible Rectangle Rectangle.Intersects(...).
cenizas999
Alguien me dio el derecho en stackoverflow: msdn.microsoft.com/en-us/library/…
Daniel Ribeiro
Ok, con el Rectángulo devuelto, ¿cómo puedo verificar la posición de la pala que colisionó con la pelota?
Daniel Ribeiro
Si sabe que la paleta con pelota se intersectan a continuación, utiliza la información de ubicación del rectángulo de paletas que marcó en el primer lugar, es decir, rectangle.Xo rectangle.Yo lo que desea acceder.
ssb
4

Actualización: si está utilizando MonoGame, a partir de 3.0 beta, Rectangle Rectangle.Intersect(rectangle, rectangle)no existe. En su lugar, puede usar el siguiente código del kit XNA Platformer.


Puede descargar XNA Platformer Starter Kit ( portado a Windows 7 ). Se envía con un método de extensión auxiliar que devuelve un rectángulo que describe la intersección de dos rectángulos:

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);
        }
}
cenizas999
fuente
Muchas gracias por este enlace. ¿Puedo preguntarle por qué necesitaba usar una versión modificada? ¿Es ese puerto oficial?
Daniel Ribeiro
@DanielRibeiro Revisé mi historial y aparentemente no lo modifiqué después de todo. El puerto no es oficial; Simplemente no pude encontrar el original. Funciona con MonoGame / C #, que fue lo suficientemente bueno para mí.
cenizas999
Pero hay un puerto original, ¿verdad? ¿No se supone que esto es una característica tan simple? De todos modos, no estoy usando MonoGame, solo XNA. ¿Todavía me recomendarías usar este puerto?
Daniel Ribeiro
Tuve que establecer la respuesta correcta ssb, pero muchas gracias por esto. ¡Seguro que entraré en este puerto! ¡Muchas gracias!
Daniel Ribeiro
1
@DanielRibeiro ah, ya veo. Creo que ese método no existe en MonoGame, por eso terminé usando este enfoque. Saludos sin embargo.
cenizas999