2009-02-21 126 views
58

He jugado con eso por un tiempo, pero simplemente no puedo entenderlo.¿Cómo calcular el ángulo de rebote?

Hice un tanque que dispara misiles, y cuando los misiles golpean las paredes, quiero que reboten, pero quiero que reboten en el ángulo correcto.

En este momento no tengo ningún obstáculo, los misiles simplemente rebotan cuando salen del viewportRectangle que hice.

¿La solución que estoy buscando es bastante avanzada?

¿Hay una forma relativamente simple de hacerlo?

+2

Este es un problema por el que la solución probablemente se vuelva inmediatamente obvia si vas a jugar un juego de billar. – smartcaveman

Respuesta

61

Creo que una manera más fácil de hacer esto es utilizar la velocidad del misil en lugar de calcular anglos. Supongamos que tiene un misil que tiene xVelocity y yVelocity para representar su movimiento horizontal y verticalmente. Esas velocidades pueden ser positivas o negativas para representar izquierda, derecha, arriba o abajo.

  • Si un misil golpea un borde superior o inferior, invierta el signo del yVelocity.
  • Si un misil golpea un borde izquierdo o derecho, invierta el signo del xVelocity.

Esto mantendrá igual el movimiento en el eje opuesto.

El préstamo de la imagen desde ChrisF's answer, digamos que el misil comienza en la posición I.

Angle of Reflection

Con la xVelocity y yVelocity tanto ser positivo (en gráficos 2D derecha y hacia abajo son típicamente positivo) el misil viajará en la dirección indicada. Vamos a asignar valores de

xVelocity = 3 
yVelocity = 4 

Cuando el misil golpea la pared en la posición C , su xVelocity no debe cambiar, pero su yVelocity debe ser revertido a -4 manera que viaja en la dirección hacia arriba, pero sigue yendo hacia la derecha.

La ventaja de este método es que sólo es necesario hacer un seguimiento de un misil de xPosition, yPosition, xVelocity y yVelocity. Usando solo estos cuatro componentes y la velocidad de actualización de tu juego, el misil siempre se volverá a dibujar en la posición correcta. Una vez que te metes en obstáculos más complicados que no están en ángulo recto o se están moviendo, será mucho más fácil trabajar con velocidades X e Y que con ángulos.

+2

Esa es una forma notablemente elegante de manejar este problema. – acrosman

+0

Uso el ángulo del misil para hacer que avance. usando Math.Sin y Math.Cos. Tuve problemas para entender de otra manera, usando la velocidad, como en el ejemplo de XNA con las canonballs. Así que todo lo que tengo que cambiar es el ángulo del misil, luego avanzará solo. – Moulde

+0

Simplemente buena física. UNA MUY bonita ilustración. +1 solo por eso, ya que una imagen vale 10K palabras. Estoy repartiendo micro puntos, por lo que es 0.001 por palabra guardada. 8) – duffymo

3

no es complicado en absoluto - pseudo-código:

angleObjectHitWall = a; 
bounceAngle = 180-a; 

Por supuesto, esto es un cálculo muy simple, y es totalmente irrelevante una vez que empiece a tener en cuenta factores tales como material, la gravedad, paredes que aren 't recto, etc ...

+3

err no. esto solo funcionaría en el caso en que el ángulo de incidencia y el reflejo sean los mismos. – bergin

9

Para partículas perfectas (& light) el ángulo de reflexión es igual al ángulo de incidencia, como se ilustra en este diagrama (de commons.wikimedia.org).

Angle of Reflection

hacer una búsqueda de "ángulo de reflexión" (sin las comillas) en Google.

Es un poco más complicado si se toma en cuenta la elasticidad y materiales del objeto y los obstáculos;)

2

180-a no funcionará en todos los casos, a menos que solo esté trabajando un rebote en una superficie superior cuando X está aumentando.

Una dirección a la cabeza son los foros XNA o recoger el código de muestra XNA. Es C# y es para construir juegos. No estoy diciendo que quieras construir tus juegos en XNA, pero es una gran herramienta, y es gratis.

+0

Está utilizando XNA im. Y sí, hay un problema .. Al disparar misiles en el borde izquierdo y derecho de la ventana, los misiles se reflejan correctamente, pero cuando se dispara en el borde inferior o superior de la ventana, puedo ver el reflejo, simplemente no el ángulo correcto – Moulde

0

Esto es realmente una cuestión de física, así que si no eres físico (y ya que estás haciendo esta pregunta, voy a entender que no) se requerirá mucha lectura e intercambio de ideas para obtener bien.

Sugiero leer this entrada en la wikipedia para obtener la idea básica sobre la profundidad de su pregunta.

Si sólo desea que sea "mirar plausible", entonces no me preocupe demasiado y utilizar Bill respuesta del lagarto, sin embargo si quieres que sea justo que tendrá toda una aventura. ¡No dejes que esto te asuste! ¡Buena suerte!

174

Puede pensar que debido a que sus paredes están alineadas con los ejes de coordenadas, tiene sentido escribir un código de mayúsculas especial (para una pared vertical, anule la coordenada x de la velocidad; para una pared horizontal, niegue la y- coordenada de la velocidad). Sin embargo, una vez que hayas logrado que el juego funcione bien con las paredes verticales y horizontales, probablemente lo siguiente que pienses es: "¿qué hay de las paredes en ángulos arbitrarios?" Entonces, vale la pena pensar en el caso general desde el principio.

En el caso general, supongamos que el misil tiene velocidad v y golpea una pared con superficie normal n.

Missile with vector v about to obliquely hit a wall with surface normal n.

de Split v en componentes u perpendicular a la pared y w paralela a ella.

Right-angled triangle with hypotenuse for v, short side u parallel to wall and long side w parallel to wall.

Donde:

u = (v · n/n · n) n
w = v-u

Aquí, v · n es el dot product de los vectores v y n. Vea el enlace para una explicación de cómo calcularlo. El producto de puntos n · n evalúa el cuadrado de la longitud del vector normal; si siempre conserva sus normales en el formato unit vectors, entonces n · n = 1 y puede omitir la división.

Después de rebotar, el componente de movimiento paralelo a la pared se ve afectado por la fricción f, y el componente perpendicular a la pared se ve afectada por la elasticidad, que se puede dar en forma de un rcoefficient of restitution.

Así que la velocidad después de la colisión es v ' = fw-ru. En coluna colisión perfectamente elástica y sin fricción, v ' = w - u; es decir, el movimiento se refleja sobre lo normal en el punto de colisión, como en el diagrama dado en la respuesta de Bill.

Este enfoque funciona igual en tres dimensiones también.

(Obviamente, esto es una noción muy simplificada de rebote, sino que no tiene en cuenta el momento angular o deformación Pero para muchos tipos de juegos de video este tipo de simplificación es perfectamente adecuado..)

+1

Estoy de acuerdo en que comenzar con la codificación de casos especiales para paredes verticales y horizontales es el camino equivocado. No es un trampolín para la ruta correcta, sino que es un camino sin salida. –

+0

Hola chicos, esta es una explicación increíble, pero creo que tiene un error. ¿No debería ser u = -n (v.n/n.n)? Después de todo, estás en la dirección inversa de n. – nullspace

+1

¿Soy el único confundido con el uso de v.n, en lugar de usar v · n? Cuando leo n.n, mi cerebro acaba de explotar; pensando que un normal tiene un elemento llamado normal. (¿estoy acostumbrado a C++ demasiado?). – Rookie

4

Como acotación al margen de la pregunta física específica que está preguntando, recomendaría el libro "Principio de Matemáticas y Física para Programadores de Juegos" por Wendy Stahler. Lo encontré bastante útil para mis proyectos de programación de juegos/física.

El código que acompaña al libro es C++, pero si conoce C#, sería muy fácil realizar la conversión.

¡Que tenga una buena!

5

Tuve este problema, la única forma que encontré fue separando los ejes de colisión.

Práctica:

x += velocity * Math.cos(angle * Math.PI /180); 
y += velocity * Math.sin(angle * Math.PI /180); 

if (x < 0 || x > canvas.width) { 
    angle = 180 - angle; 
} 
else if (y < 0 ||y > canvas.height) { 
    angle = 360 - angle; 
} 

Espero que esto te ayude!

+0

No era la solución ideal para casos generales, sin embargo, era precisamente lo que necesitaba en este momento (reflejándose en los bordes del lienzo). Por alguna razón, no pude hacer que mi cerebro llegara a esta solución por sí mismo. – Draco18s

-3
if(!Collide(Missle, Mainchar)){ 
(Velocity.x)*-1; 
(Velocity.y)*-1; 
} 

Funciona y es simple, buena suerte.

+1

Sí no. Esto hace que el objeto regrese a lo largo de su vector original en reversa. Eso no es un reflejo de espejo. – Draco18s

Cuestiones relacionadas