Dado que esto se basa en su otra pregunta, daré una solución para cuando el rectángulo esté alineado con el eje.
Primero, construye el rectángulo de su objeto actual con los siguientes valores:
int boxLeft = box.X;
int boxRight = boxLeft + box.Width;
int boxTop = box.Y;
int boxBottom = boxTop + box.Height;
A continuación, debe tener la posición del objeto antiguo (que puede almacenar en cada objeto o simplemente pasar a una función) para crear el rectángulo del objeto antiguo (cuando no estaba colisionando):
int oldBoxLeft = box.OldX;
int oldBoxRight = oldBoxLeft + box.Width;
int oldBoxTop = box.OldY;
int oldBoxBottom = oldBoxTop + box.Height;
Ahora, para saber de dónde fue la colisión, debe encontrar el lado donde la posición anterior no estaba en el área de colisión y dónde está su nueva posición. Porque, cuando lo piensas, esto es lo que sucede cuando chocas: un lado que no colisionó entra en otro rectángulo.
Así es como podría hacerlo (estas funciones suponen que hay una colisión. No deberían llamarse si no hay colisión):
bool collidedFromLeft(Object otherObj)
{
return oldBoxRight < otherObj.Left && // was not colliding
boxRight >= otherObj.Left;
}
Enjuague y repita.
bool collidedFromRight(Object otherObj)
{
return oldBoxLeft >= otherObj.Right && // was not colliding
boxLeft < otherObj.Right;
}
bool collidedFromTop(Object otherObj)
{
return oldBoxBottom < otherObj.Top && // was not colliding
boxBottom >= otherObj.Top;
}
bool collidedFromBottom(Object otherObj)
{
return oldBoxTop >= otherObj.Bottom && // was not colliding
boxTop < otherObj.Bottom;
}
Ahora, para el uso real con la respuesta de colisión de la otra pregunta:
if (collidedFromTop(otherObj) || collidedFromBottom(otherObj))
obj.Velocity.Y = -obj.Velocity.Y;
if (collidedFromLeft(otherObj) || collidedFromRight(otherObj))
obj.Velocity.X = -obj.Velocity.X;
Una vez más, esta puede no ser la mejor solución, pero esa es la forma en que generalmente utilizo la detección de colisiones.
Como la pregunta es parcialmente idéntica a esta pregunta , reutilizaré algunas partes de mi respuesta para intentar responderla.
Vamos a definir un contexto y algunas variables para que la siguiente explicación sea más comprensible. La forma de representación que usaremos aquí probablemente no se ajuste a la forma de sus propios datos, pero debería ser más simple de entender de esta manera (de hecho, puede usar los siguientes métodos usando otros tipos de representaciones una vez que comprenda el principio)
Por lo tanto, consideraremos un cuadro delimitador alineado del eje (o un cuadro delimitado orientado ) y una entidad en movimiento .
El cuadro delimitador se compone de 4 lados, y definiremos cada uno como:
Lado1 = [x1, y1, x2, y2] (dos puntos [x1, y1] y [x2, y2])
La entidad en movimiento se define como un vector de velocidad (posición + velocidad):
una posición [posX, posY] y una velocidad [speedX, speedY] .
Puede determinar qué lado de un AABB / OBB es golpeado por un vector utilizando el siguiente método:
1 / Encuentre los puntos de intersección entre las líneas infinitas que pasan por los cuatro lados de la AABB y la línea infinita que pasa a través de la posición de la entidad (pre-colisión) que usa el vector de velocidad de la entidad como pendiente. (Puede encontrar un punto de colisión o un número indefinido, que corresponde a paralelos o líneas superpuestas)
2 / Una vez que conozca los puntos de intersección (si existen) puede buscar aquellos que están dentro de los límites del segmento.
3 / Finalmente, si todavía hay varios puntos en la lista (el vector de velocidad puede pasar a través de múltiples lados), puede buscar el punto más cercano desde el origen de la entidad utilizando las magnitudes del vector desde la intersección hasta el origen de la entidad.
Luego puede determinar el ángulo de colisión utilizando un simple producto de puntos.
----------
Más detalles:
1 / Buscar intersecciones
a / Determine las líneas infinitas (Ax + Bx = D) usando sus formas paramétricas (P (t) = Po + tD).
Utilicé los valores de puntos de entidad para ilustrar el método, pero este es exactamente el mismo método para determinar las líneas infinitas de 4 lados del cuadro delimitador (Use Po = [x1, y1] y D = [x2-x1; y2-y1] en lugar).
b / A continuación, para encontrar la intersección de dos líneas infinitas podemos resolver el siguiente sistema:
que produce las siguientes coordenadas para la intercepción:
Si el denominador ((A1 * B2) - (A2 * B1)) es igual a cero, entonces ambas líneas son paralelas o superpuestas, de lo contrario, debe encontrar una intersección.
2 / Prueba de los límites del segmento. Como esto es fácil de verificar, no hay necesidad de más detalles.
3 / Buscar el punto más cercano. Si todavía hay varios puntos en la lista, podemos encontrar qué lado es el más cercano al punto de origen de la entidad.
a / Determine el vector que va del punto de intersección al punto de origen de la entidad
b / Calcular la magnitud del vector
4 / Ahora que sabe qué lado será golpeado, puede determinar el ángulo con un producto de puntos.
a / Sea S = [x2-x1; y2-y1] será el vector lateral que será golpeado y E = [speedX; speedY] sea el vector de velocidad de la entidad.
Usando la regla del producto de puntos vectoriales, sabemos que
Entonces podemos determinar θ manipulando un poco esta ecuación ...
con
Nota: Como dije en el otro hilo de preguntas, probablemente esta no sea la forma más eficiente ni la más simple de hacerlo, esto es lo que viene a la mente, y alguna parte de las matemáticas podría ayudar.
No verifiqué con un ejemplo OBB concreto (lo hice con un AABB) pero también debería funcionar.
fuente
Una manera simple es resolver la colisión, luego traducir el cuadro de colisión del objeto en movimiento por un píxel en cada dirección y ver cuáles resultan en colisión.
Si desea hacerlo "correctamente" y con formas de colisión rotadas o polígonos arbitrarios, le sugiero que lea el Teorema del eje de separación. El software Metanet (la gente que creó el juego N), por ejemplo, tiene un increíble artículo de desarrollo sobre SAT . También discuten la física involucrada.
fuente
Una forma sería rotar el mundo alrededor de su rectángulo. "El mundo" en este caso son solo los objetos que te interesan: el rectángulo y la pelota. Gira el rectángulo alrededor de su centro hasta que sus límites estén alineados con los ejes x / / y, luego gira la bola en la misma cantidad.
El punto importante aquí es que giras la bola alrededor del centro del rectángulo, no la suya.
Luego, puede probar fácilmente la colisión como lo haría con cualquier otro rectángulo no girado.
Otra opción es tratar el rectángulo como cuatro segmentos de línea distintos y probar la colisión con cada uno de ellos por separado. Esto le permite probar la colisión y descubrir qué lado colisionó al mismo tiempo.
fuente
Utilicé ángulos fijos en mis cálculos, pero esto debería ayudarte
fuente