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?

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.


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);
        }
}

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.