Actualmente, tengo un juego de plataformas con mosaicos para terreno (gráficos tomados de Cave Story). El juego está escrito desde cero usando XNA, así que no estoy usando un motor existente o un motor de física.
Las colisiones de mosaicos se describen exactamente como se describe en esta respuesta (con SAT simple para rectángulos y círculos), y todo funciona bien.
Excepto cuando el jugador se encuentra con una pared mientras cae / salta. En ese caso, se agarrarán de un azulejo y comenzarán a pensar que han golpeado un piso o techo que en realidad no está allí.
En esta captura de pantalla, el jugador se mueve hacia la derecha y cae hacia abajo. Entonces, después del movimiento, se comprueban las colisiones, y primero, resulta que el personaje del jugador colisiona con la ficha 3 del piso y se empuja hacia arriba. En segundo lugar, se encuentra colisionando con el mosaico a su lado y empujado hacia un lado: el resultado final es que el personaje del jugador piensa que está en el suelo y no se cae, y se 'atrapa' en el mosaico mientras se encuentre con él. .
Podría resolver esto definiendo las fichas de arriba a abajo, lo que lo hace caer suavemente, pero luego ocurre el caso inverso y golpeará un techo que no está allí cuando salta hacia arriba contra la pared.
¿Cómo debería abordar la resolución de esto, para que el personaje del jugador pueda caer a lo largo de la pared como debería?
fuente
Respuestas:
El enfoque más simple y a prueba de fallas es simplemente no verificar colisiones en bordes ocultos. Si tiene dos fichas de pared, una directamente encima de la otra, entonces el borde inferior de la ficha superior y el borde superior de la ficha inferior no deben verificarse por colisión contra el jugador.
Puede determinar qué bordes son válidos durante una pasada simple sobre el mapa de mosaicos, almacenando los bordes externos como banderas en cada ubicación de mosaico. También puede hacer esto en tiempo de ejecución comprobando los mosaicos adyacentes durante la detección de colisión.
Hay versiones más avanzadas de esta misma técnica que también hacen que sea más fácil y rápido admitir mosaicos no cuadrados.
Te recomiendo que leas los artículos a continuación. Son introducciones simples y decentes para hacer física básica y detección de colisiones en plataformas modernas (como Cave Story). Si buscas una sensación de Mario de la vieja escuela, hay algunos trucos más de los que preocuparte, pero la mayoría de ellos involucran manejar saltos y animaciones en lugar de una colisión.
http://www.metanetsoftware.com/technique/tutorialA.html http://www.metanetsoftware.com/technique/tutorialB.html
fuente
Aquí el orden que haría las cosas ...
1) Guardar X, Y actual del personaje
2) Mueve la dirección X
3) Verifique todos los rincones del carácter obteniendo los datos del mosaico y verifique si es sólido haciendo lo siguiente: (X e Y es la posición del carácter)
... para obtener datos de mosaico correctos de los datos del mapa
4) Si alguna de las fichas es sólida, entonces debes forzar a X a la mejor posición posible restaurando la X guardada y ...
5) Repita 2-4 usando Y
Si tu personaje es más alto que un mosaico, debes verificar más mosaicos. Para hacer esto, debe realizar un bucle y agregar tileHeight a la posición del carácterY para obtener el mosaico
Si el carácter es más ancho que 1 bloque, haga lo mismo pero reemplace characterY, characterHeight, tileHeight, etc. con characterX, characterWidth, etc.
fuente
¿Qué sucede si se verifica la posibilidad de una colisión como parte del método de movimiento del jugador y se rechaza el movimiento que hizo que el jugador se deslizara hacia otro objeto? Esto evitaría que el jugador ingrese "dentro" de un bloque y, por lo tanto, no podría estar "encima" del bloque debajo de él.
fuente
Me encontré con casi el mismo problema en un juego en el que estoy trabajando actualmente. La forma en que lo resolví fue almacenar el área de la parte superpuesta cuando se realizaban pruebas de colisiones, y luego manejar esas colisiones en función de su prioridad (primero el área más grande), luego verificar dos veces cada colisión para ver si ya había sido resuelta por una anterior. manejo.
En su ejemplo, el área de colisión del eje x sería mayor que el eje y, por lo que se manejaría primero. Luego, antes de intentar manejar la colisión del eje y, verificaría y vería que ya no está colisionando después de moverse sobre el eje x. :)
fuente
Una solución simple, pero no perfecta, es cambiar la forma del cuadro de colisión del jugador para que no sea un cuadrado. Corta las esquinas para hacerlo octágono o algo similar. De esta manera, cuando choca con un azulejo como los que están en la pared, se deslizará y no quedará atrapado. Esto no es perfecto porque todavía puedes notar que se queda un poco atrapado en las esquinas, pero no se atasca y es muy fácil de implementar.
fuente
En este tutorial se cubrió un problema muy similar: Introducción al desarrollo de juegos . La parte relevante del video es a las 1:44 , explicando con diagramas y fragmentos de código.
El aviso 14-tilemap.py muestra el problema de recorte, pero se soluciona en 15-blocker-sides.py
No puedo explicar exactamente por qué el último ejemplo de tutorial no se recorta mientras que su código sí, pero creo que tiene algo que ver con:
self.resting
miembro en el código solo se usa para verificar si el jugador puede saltar. A pesar de esto, no puedo hacer que el jugador haga un 'doble' salto desde una pared. En teoría, podría ser posible)fuente
Otro método (al que respondí la pregunta que Byte56 enlazó) sería verificar si la resolución de colisión coloca al personaje en un lugar vacío o no. Entonces, en su problema, obtiene una colisión desde el techo del rectángulo interior para moverlo hacia arriba, lo que sería ilegal (ya que todavía está en colisión con otra baldosa). En cambio, solo lo mueve si se mueve a un espacio libre (como la forma en que la colisión desde el mosaico superior lo movería hacia la izquierda), y una vez que encuentre esa colisión, habrá terminado.
La respuesta que di tenía código, pero se volvió demasiado complicada. Llevaría un registro de todas las colisiones dentro de ese plazo y solo tomaría la que conduzca a un espacio libre. Sin embargo, si no hubiera ninguno, creo que recurrí a restablecer la posición del personaje a su última posición, sin embargo, eso es realmente feo y tal vez prefieras intentar implementar algo como el Mario original donde simplemente se mueve en una dirección o algo cuando no hay resolución de espacio libre es posible. También puede ordenar esa lista de resoluciones de colisión y solo moverse al espacio libre con la distancia más corta (creo que esa solución sería la más preferible, aunque no codifiqué para eso).
fuente
Solo he hecho 3 SAT en 3D, así que tal vez no estoy haciendo esto bien. Si entiendo su problema, podría deberse a tener contactos con un eje de contacto que no debería ser posible, lo que da como resultado que el jugador actúe como si hubiera un piso. Una solución alternativa podría ser usar una forma circular para su caracter, entonces solo obtendrá ejes de contacto en la dirección del eje x cuando golpee una pared.
fuente