2011-09-09 7 views
8

En la unidad, tengo una raqueta que se supone golpea una pelota, y la raqueta es controlada directamente por el mouse, es decir, el mouse que usa los ejes del mouse y la función transform.translate() para mover la raqueta.Problema con la detección de colisión de una bola que se mueve rápidamente con una raqueta controlada por mouse

Esperaba que la física de Unity3d no tradujera correctamente el movimiento de la raqueta directamente con el mouse e impactara la pelota en consecuencia, y tendría que escribir algo personalizado, y resultó ser cierto.

Pero la colisión de la bola no se detecta correctamente cuando la raqueta se está moviendo. Cuando está quieto, todo está bien, y la pelota se comporta como me gusta.

Ahora llegué a escribir una secuencia de comandos de física personalizada (uso C# para secuencias de comandos) en la que adjunté 4 rayos de longitud 0.6F a la bola, y después de hacer algunos cálculos complejos, calcular la velocidad de la bola después de golpear la raqueta, y aplicarla directamente a la velocidad de la pelota usando rigidbody.velocity = calculateVelocity(). Ahora vuelve a funcionar bien cuando la raqueta no se mueve, pero no cuando muevo la raqueta. El problema exacto (síntomas de) es:

Uso de Física integrada y detección de colisión: cuando la raqueta se mueve, la pelota a veces pasa directamente a través de la raqueta y, a veces, se ralentiza (a niveles increíbles).

Usando mi secuencia de comandos para calcular la velocidad: El problema es el mismo, pero me permite identificar qué está mal cuando imprimo la normalidad del colisionador (la raqueta). A veces da la normalidad correcta, y en algún momento da el negativo del vector normal, lo que significa que va directamente a través de la superficie superior y detecta el golpe con el lado inferior del colisionador (raqueta).

Las cosas que he intentado:

  1. El aumento del tamaño del colisionador (funciona con la mayor colisionador de cuadro en la raqueta, pero entonces, evidentemente, la bola se mueve desde una distancia bastante lejos de la raqueta, y mi propio script funciona aquí, la física predeterminada da resultados extraños cuando se mueve la raqueta), en resumen, no obtengo la realidad que quiero.

  2. Disminuyendo la marca de tiempo fija a 0.001, lo que mejoró significativamente las cosas, pero aún muy lejos del resultado que deseo, y la pelota de nuevo escoge el lado equivocado de la pelota.

  3. Cambiando la detección de colisión a dinámica continua. Lo cual tampoco mejoró las cosas.

Y además del lado equivocado elegidos al choque, otro problema que he observado es que después de rebotar en la raqueta, la pelota está movimientos, pero la raqueta se mueve más rápido, en lugar de moverse en un arco completo o línea, de alguna manera aparece en frente de la pelota, lo que resulta en dos golpes. Es una conjetura basada en lo que es visible.

También está claro que el aspecto de "movimiento" de la raqueta no está siendo leído por la física incorporada de Unity3d, lo que resulta en un comportamiento extraño cuando la raqueta se mueve con el mouse golpea la pelota.

Estoy atascado, no tengo ni idea de dónde moverse desde aquí. Por favor, dime qué es lo que estoy haciendo mal.

Respuesta

8

Como han señalado otros, el problema es que la pelota pasa de estar en un lado del pad en un cuadro a estar del otro lado en el siguiente. Los objetos de movimiento rápido tienden a hacer eso si las barreras son demasiado escasas.

Hay tres soluciones muy sencillas para este problema:

  • aumentar el tamaño de la almohadilla o la pelota, que es lo que sucedió cuando se cambió el tamaño colisionador.
  • Establezca una velocidad máxima para la pelota, para que nunca se mueva lo suficientemente rápido como para pasar por las almohadillas.
  • Aumenta la frecuencia con la que Unity realiza sus cálculos de física. Se puede cambiar en Time Manager, reduciendo el valor de Fixed Timestep. Tenga cuidado con reducir esto demasiado, o el motor de física no podrá finalizar una llamada antes de que comience la próxima ronda y nunca podrá ponerse al día con el juego.

Establecer una velocidad máxima para mover objetos es algo que siempre se debe hacer. No puede arriesgarse a que un objeto importante se dispare durante el juego y deje todo en un estado incontrolado.

+0

He intentado establecer la velocidad máxima tanto para la raqueta como para la pelota, puedo quizás aumentar el tamaño de todo el entorno, quizás esto podría brindar una mejor oportunidad de detectar el lado derecho del colisionador. Implementaré tanto la solución dada por Justin808 como el tamaño de todo. – SpeedBirdNine

+0

Esto funcionó tan brillantemente, dupliqué el tamaño de todo, y ahora no falta una colisión. Todavía tengo el otro problema del que Justin808 habló, que la raqueta en un momento está en frente de la pelota y el siguiente cuadro está detrás de la pelota, pero al menos veo dos colisiones distintas, ¡que pueden manejarse con código! ¡Muchas gracias! Me tomó solo 2 minutos para hacer. Ahora voy a implementar la solución de Justin para resolver dos colisiones. En este momento, si alguien tiene otra explicación, ¡por favor, compartala también! – SpeedBirdNine

+0

Ok problema resuelto, no tuve que colocar un raycast entre la posición anterior y siguiente de la pelota ya que ahora el colisionador de la raqueta no le falta la pelota. Otra cosa es que el movimiento de la raqueta a través del mouse no se traduce en una fuerza adicional aplicada a la pelota. Tuve que escribir esta parte yo mismo, y establecer istrigger como verdadero para el colisionador de raquetas para que la física original no interfiera. Pero ahora había un problema de golpear varias veces, lo resolví usando una bandera, que se vuelve falsa cuando se golpea la primera vez, y es verdadera otra vez después de 1 segundo, o cuando la pelota golpea a otro objeto. ¡Esto funciona! – SpeedBirdNine

3

Esta no es una respuesta completa, pero recuerdo haber tenido que hacer frente a un problema como este hace muchos años en máquinas más lentas.

El problema consistía en utilizar la detección de colisiones basada en sprites; confiando en los píxeles para el sprite y el obstáculo que se renderizan en las mismas coordenadas. Si la velocidad de cuadro es tan baja que el sprite se mueve más que el tamaño del obstáculo en un cuadro, te meterás en situaciones en las que está (por ejemplo) a la izquierda del obstáculo en un cuadro ya la derecha del obstáculo en el siguiente cuadro sin ocupando los mismos pixeles

En este caso, las colisiones basadas en sprites no funcionan, tiene que basar las colisiones en los vectores. En lugar de verificar cada píxel de sprite en busca de colisiones, registre la posición y el casco convexo del sprite. Después de cada cuadro, calcule un vector desde la posición anterior a la nueva posición y cúbralo con el casco convexo de cada obstáculo.

Existen varios accesos directos que puede realizar, como comparar solo cuadros delimitadores al principio y calcular el casco solo si el vector se cruza con un cuadro delimitador, pero esta es la idea básica. Buena suerte.

+1

La idea parece ser un buen punto de partida, pero hay alguna idea de cómo implementarla en Unity3d usando la mayor cantidad posible de elementos incorporados (en la medida en que está optimizado). Y sobre máquinas lentas, lo probé en una máquina Core i7 con 6 GB de RAM DDR3 y 1 GB de tarjeta gráfica ATi Radeon HD5890, y el FPS nunca cae por debajo de 70. Y explique qué es la detección de colisiones basada en sprites y esto es lo que usa Unity3d ? Como estoy usando Unity3d, no creo que pueda controlar los detalles del mecanismo de detección de colisiones en este sentido – SpeedBirdNine

+1

Lo siento, no he usado Unity. Los gráficos basados ​​en Sprite usan el buffer de cuadro real para los cálculos; si está utilizando OpenGL o ActiveX, probablemente no esté usando sprites. Sin embargo, la noción de verificar vectores contra cascos convexos para colisiones es aplicable a gráficos de modos retenidos. Imagino que la Unidad tiene una forma de ver si un vector cruza un casco. –

+0

¿Alguna más respuesta a alguien? – SpeedBirdNine

5

Lo que creo que está sucediendo es que cada intervalo que pasa la pelota/raqueta se mueve y luego se comprueba si hay una colisión. El problema es que la pelota/raqueta se mueve muy lejos en un solo intervalo y se pierde la colisión.

1) Ball before racquet 
2) Ball after racquet 

not 

1) Ball before racquet 
2) Ball touching racquet 

Así que lo que tiene que hacer es en su método de su GameObject bola FixedUpdate() se echa un rayo desde la ubicación actual pelota a la ubicación bola anterior. Si hay algo entre esos dos puntos que debería haber sido golpeado (es decir, la raqueta) mueva la pelota de vuelta al punto de golpe reportado en el rayo. Esto disparará su detección de colisión existente.

El motivo por el que aumenta el tamaño del colisionador también funciona porque la pelota no se salta el colisionador de cerveza dorada. Esto tiene los inconvenientes que mencionaste en tu pregunta. La proyección de rayos evita este problema y permite que la pelota/raqueta se mueva tan rápido o lento como lo necesiten.

0

He estado trabajando en un juego de pong 3d también, y me he encontrado con los mismos problemas. Voy a intentar agrandar todo lo que ustedes chicos hicieron. En cuanto a la paleta que agrega velocidad y giro a la pelota, me quedé desconcertado hasta que me di cuenta de que cambiar la posición de la paleta no cambia su velocidad. Si la paleta estaba en velocidad cero antes de que se moviera, estará en cero cuando el motor de física lo vea en el siguiente cuadro.La falta de comprobación es kenimatic y el control de la paleta directamente a través de la propiedad de velocidad solucionó el problema. Hizo que la paleta temblara al golpear las paredes, pero lo solucioné al quitar las paredes de la capa de paletas y manejar los límites manualmente en LateUpdate. Además, cuando actualice la velocidad, primero almacene la nueva velocidad deseada en Update para que los controles funcionen sin problemas y luego confirme los cambios en FixedUpdate.

Cuestiones relacionadas