Obtenha detalhes da colisão em Rectangle.Intersects ()

9

Eu tenho um jogo Breakout no qual, em algum momento, eu detecto a colisão entre a bola e a raquete com algo assim:

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

Existe alguma maneira de obter as coordenadas exatas da colisão, ou quaisquer detalhes sobre ela, com a corrente XNA API?

Pensei em fazer alguns cálculos básicos, como comparar as coordenadas exatas de cada objeto no momento da colisão. Seria algo como isto:

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

Mas não tenho certeza se essa é a maneira correta de fazer isso.

Vocês têm alguma dica sobre um mecanismo que talvez eu precise usar para conseguir isso? Ou mesmo boas práticas de codificação usando esse método?

Daniel Ribeiro
fonte

Respostas:

8

Os retângulos do XNA são bastante limitados. O Rectangle.Intersects()método retorna apenas um resultado booleano; portanto, você precisará fazer mais testes se quiser detalhes. No entanto, você pode usar o Rectangle.Intersect(Rectangle, Rectangle)método para obter o retângulo onde os dois se sobrepõem. Isso lhe dará algumas informações sobre profundidade e localização, pelo menos.

ssb
fonte
Essa get the rectangle where the two overlapfuncionalidade está disponível XNA APIou eu tenho que baixar algumas coisas extras, como a Platformer Starter Kit?
Daniel Ribeiro
11
Que método é esse? Não me lembro que o XNA 4.0 suporta Rectangle Rectangle.Intersects(...).
ashes999
Alguém me deu o direito no stackoverflow: msdn.microsoft.com/en-us/library/…
Daniel Ribeiro
Ok, com o retângulo retornado, como posso verificar a posição da raquete que foi colidida pela bola?
Daniel Ribeiro
Se você sabe que a raquete e a bola estão se cruzando, use as informações de localização do retângulo da raquete que você verificou em primeiro lugar, rectangle.Xou seja, rectangle.You o que você deseja acessar.
ssb
4

Atualização: se você estiver usando o MonoGame, a partir da versão 3.0 beta,Rectangle Rectangle.Intersect(rectangle, rectangle) não existe. Você pode usar o código abaixo do kit XNA Platformer.


Você pode fazer o download do XNA Platformer Starter Kit ( portado para Windows 7 ). É fornecido com um método de extensão auxiliar que retorna um retângulo que descreve a interseção de dois retâ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);
        }
}
ashes999
fonte
Muito obrigado por este link. Posso perguntar por que você precisou usar uma versão modificada? Esse porto é oficial?
Daniel Ribeiro
@DanielRibeiro Verifiquei meu histórico e, aparentemente, não o modifiquei. O porto não é oficial; Eu simplesmente não consegui encontrar o original. Funciona com MonoGame / C #, o que foi bom o suficiente para mim.
ashes999
Mas existe uma porta original, certo? Isso não deveria ser um recurso tão simples? De qualquer forma, não estou usando o MonoGame, apenas o XNA. Você ainda recomendaria que eu usasse essa porta?
Daniel Ribeiro
Eu tive que definir a resposta correta ssb, mas muito obrigado por isso. Com certeza vou entrar neste porto! Muito Obrigado!
Daniel Ribeiro
11
@DanielRibeiro ah, entendo. Eu acho que esse método não existe no MonoGame, e é por isso que acabei usando essa abordagem. Cheers embora.
ashes999