¿Cómo creo un objeto arrastrable que se engancha a obstáculos en el camino?

8

Traigo otra pregunta de arrastrar con el mouse (estoy usando Unity con C #), pero con un detalle particular menos común: la existencia de obstáculos en el medio del camino a través del cual ocurre el arrastre (espacio 3D, no 2D) .

Dejame explicar. Supongamos que tengo un plano sobre el cual quiero arrastrar un cubo llamado "obj". Eso es fácil. Aquí está mi implementación simple para eso:

void Update () {
  Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
  RaycastHit hit;
  if(Physics.Raycast(ray, out hit, 1000000))
  obj.transform.position = new Vector3(hit.point.x,0.25F,hit.point.z);
}

Funciona. Sin embargo, supongamos que también tengo algunos otros cubos sobre el avión, que son los obstáculos. Obviamente, cuando el jugador mueve "obj" sobre el avión, tal movimiento debe ser bloqueado por los obstáculos. Y luego, mientras choca con los obstáculos, "obj" solo debe moverse a los lados de ese obstáculo. Si se mueve el mouse y "obj" deja de chocar con obstáculos, el movimiento de arrastre libre se reanuda nuevamente.

Arrastrar un objeto hacia un obstáculo y detenerse en su borde, y luego reanudarlo cuando la resistencia lo supera.

Para dificultar el desafío, estoy tratando de lograrlo sin el uso de componentes RigidBody en los obstáculos (el objeto arrastrado puede tenerlo). ¿Alguna idea sobre cuál es la forma más eficiente de lograr eso? ¡Muchas gracias!

EDITAR: Los comentaristas me han llamado la atención sobre que debo mencionar que los objetos pueden rotar cuando se rompen.

EDITAR 2: Considerando la dificultad de la formulación original, cambié la pregunta permitiendo el uso de componentes Rigidbody en los objetos arrastrados. La solución simplemente no puede usar componentes de Rigidbody en los obstáculos.

Mand
fuente
¿Estás moviendo formas convexas arbitrarias, son siempre de cuatro lados? ¿Son siempre 2D?
Steven
¿Puedo saber la razón por la que no usarás Rigidbodies? Son la forma más fácil de hacer lo que quieres sin tener que volver a implementar el código ya disponible en Unity.
EvilTak
@EvilTak Prefiero aprender a lidiar con la geometría involucrada en la tarea y, por razones de rendimiento, no me gusta usar Rigidbodies a menos que sea realmente inevitable. En este caso particular, tendré muchos miles de objetos que se comportarán como obstáculos
MAn
Por cierto, ¡gracias a @Anko (o a quien lo hizo) por incluir esa imagen animada para ilustrar el problema! Todavía estaba pensando en la mejor manera de hacerlo.
2015
1
@ Steven y EvilTak: se puede permitir que el objeto gire, los obstáculos no. Las formas habituales de detectar colisiones parecen no ser suficientes: el objeto principal sigue entrando en los objetos.
2015

Respuestas:

2

Es difícil detectar la colisión sin ningún cuerpo rígido involucrado, pero dado que está usando cubos, puede usar Bounds . Intersects . En cada actualización, verifique si los límites del objeto arrastrado se cruzan con los límites de cualquier obstáculo. Si es así, entonces puedes probar esto:

  1. Desactive el Renderizador de malla para el objeto arrastrado para hacerlo invisible (pero continúe arrastrándolo).
  2. Deje caer un objeto de marcador de posición visible idéntico al arrastrado en la última posición antes de la intersección de límites (ahora parece que el objeto se detuvo, pero realmente todavía está arrastrando el original).
  3. En cada actualización, verifique si los límites del objeto que sigue arrastrando se cruzan con los límites de un obstáculo.
  4. Cuando los límites del objeto arrastrado ya no se cruzan con los de un obstáculo, elimine / desactive el objeto marcador de posición y vuelva a habilitar el Renderizador de malla para que el objeto arrastrado vuelva a ser visible.

Nunca dejas de arrastrar el bloque; simplemente le parece al usuario que el bloque ha dejado de arrastrarse mientras se cruza con un obstáculo.

Evan
fuente
Basado en comentarios anteriores y en su respuesta, edité la pregunta para que sea más fácil de lograr: ahora digamos que Rigidbody podría usarse para el objeto arrastrable o sus marcadores de posición. Rigidbody simplemente no podía usarse para los obstáculos.
2015
1

Sin haberlo hecho yo mismo, esto es lo que probaría:

  1. Decida qué tan alto debe ser un obstáculo en el avión para bloquear su objeto arrastrado (donde "alto" significa quitado a lo largo del eje apropiado; supongo que el que apunta hacia la cámara).
  2. En cada actualización, guarde la posición de su hit raycast.
  3. Cada actualización, antes de guardar la posición del golpe de emisión de rayos actual, verifique la posición del golpe de emisión de rayos actual con la posición del golpe de emisión de rayos anterior.
  4. Si la diferencia> = altura de bloqueo, detenga su objeto en movimiento en la posición anterior de impacto de rayos.

Me parece que si desea que su objeto se arrastre a lo largo de un plano inclinado de un obstáculo, simplemente debe hacer que su transformación continúe siguiendo la posición del último golpe de rayos.

Evan
fuente
Gracias por tu respuesta, @Evan. Sin embargo, esa solución no sería precisa. Supongamos que RayCast se dispararía desde el centro del cuadro delimitador del objeto arrastrable. ¿Qué pasa si el obstáculo en el camino bloquea solo una parte del objeto arrastrable que está a la izquierda o derecha del rayo? Incluso si aumentamos el número de rayos emitidos (lo que puede llegar a ser exponencialmente alto si el objeto arrastrable se puede arrastrar en direcciones de 360º en las dimensiones X, Z), dependiendo de cuán pequeño sea el obstáculo en relación con el objeto arrastrable, aún podría estar entre rayos emitidos - y por lo tanto no se detectaría
MA
Muy bien, creo que entiendo lo que quieres decir.
Evan