Estoy tratando de crear un efecto similar al de Mario Galaxy o Geometry Wars 3 donde el jugador camina alrededor del "planeta", la gravedad parece ajustarse y no se caen del borde del objeto como lo harían si la gravedad fue arreglado en una sola dirección.
(fuente: gameskinny.com )
Logré implementar algo cercano a lo que estoy buscando usando un enfoque donde el objeto que debería tener la gravedad atrae otros cuerpos rígidos hacia él, pero al usar el motor de física incorporado para Unity, aplicando movimiento con AddForce y similares, Simplemente no pude hacer que el movimiento se sintiera bien. No pude lograr que el jugador se moviera lo suficientemente rápido sin que el jugador comenzara a volar fuera de la superficie del objeto y no pude encontrar un buen equilibrio de fuerza aplicada y gravedad para acomodar esto. Mi implementación actual es una adaptación de lo que se encontró aquí
Siento que la solución probablemente aún usaría física para hacer que el jugador se conecte a tierra sobre el objeto si salieran de la superficie, pero una vez que el jugador haya sido conectado a tierra, habría una manera de encajar al jugador en la superficie y apagar la física y controlar al jugador a través de otros medios, pero realmente no estoy seguro.
¿Qué tipo de enfoque debo tomar para encajar al jugador en la superficie de los objetos? Tenga en cuenta que la solución debería funcionar en el espacio 3D (a diferencia de 2D) y debería poder implementarse utilizando la versión gratuita de Unity.
Respuestas:
Logré lograr lo que necesitaba, principalmente con la ayuda de esta publicación blog para la pieza de la superficie del rompecabezas y se me ocurrieron mis propias ideas para el movimiento del jugador y la cámara.
Ajustar jugador a la superficie de un objeto
La configuración básica consiste en una esfera grande (el mundo) y una esfera más pequeña (el jugador), ambas con colisionadores de esferas unidas a ellas.
La mayor parte del trabajo realizado se realizó en los siguientes dos métodos:
los
Vector3 movementDirection
parámetro es tal como suena, la dirección en la que vamos a mover a nuestro jugador en este cuadro, y calcular ese vector, aunque terminó siendo relativamente simple en este ejemplo, fue un poco difícil de entender al principio. Más sobre eso más adelante, pero solo tenga en cuenta que es un vector normalizado en la dirección en que el jugador mueve este cuadro.Al pasar, lo primero que hacemos es verificar si un rayo, que se origina en la hipotética posición futura dirigida hacia el vector hacia abajo del jugador (-transform.up), llega al mundo usando WorldLayerMask, que es una propiedad pública de LayerMask del script. Si desea colisiones más complejas o varias capas, tendrá que construir su propia máscara de capa. Si la emisión de rayos impacta con éxito en algo, hitInfo se utiliza para recuperar el punto normal y el punto de golpe para calcular la nueva posición y rotación del jugador que debe estar justo en el objeto. La compensación de la posición del jugador puede ser necesaria según el tamaño y el origen del objeto del jugador en cuestión.
Finalmente, esto realmente solo se ha probado y probablemente solo funcione bien en objetos simples como esferas. Como sugiere la publicación del blog en la que basé mi solución, es probable que desee realizar múltiples transmisiones de rayos y promediarlas para su posición y rotación para obtener una transición mucho más agradable al moverse sobre terrenos más complejos. También puede haber otras trampas que no he pensado en este momento.
Cámara y movimiento
Una vez que el jugador se pegaba a la superficie del objeto, la siguiente tarea a abordar era el movimiento. Originalmente había comenzado con el movimiento relativo al jugador, pero comencé a encontrar problemas en los polos de la esfera donde las direcciones cambiaron repentinamente, lo que hizo que mi jugador cambiara rápidamente de dirección una y otra vez sin dejarme pasar nunca por los polos. Lo que terminé haciendo fue hacer que mis jugadores se movieran en relación con la cámara.
Lo que funcionó bien para mis necesidades fue tener una cámara que siguiera estrictamente al jugador basándose únicamente en la posición del jugador. Como resultado, a pesar de que la cámara estaba rotando técnicamente, presionar hacia arriba siempre movía al jugador hacia la parte superior de la pantalla, hacia abajo, hacia abajo, y así sucesivamente con la izquierda y la derecha.
Para hacer esto, se ejecutó lo siguiente en la cámara donde el objeto objetivo era el jugador:
Finalmente, para mover el reproductor, aprovechamos la transformación de la cámara principal para que con nuestros controles hacia arriba, hacia abajo, hacia abajo, etc. Y aquí es donde llamamos UpdatePlayerTransform, que hará que nuestra posición se ajuste al objeto del mundo.
Para implementar una cámara más interesante, pero los controles deben ser casi los mismos que los que tenemos aquí, puede implementar fácilmente una cámara que no esté renderizada o simplemente otro objeto ficticio para basar el movimiento y luego usar la cámara más interesante para representar lo que quieres que se vea el juego. Esto permitirá transiciones agradables de la cámara a medida que recorres objetos sin romper los controles.
fuente
Creo que esta idea funcionará:
Mantenga una copia del lado de la CPU de la malla del planeta. Tener vértices de malla también significa que tienes vectores normales para cada punto del planeta. Luego, desactive completamente la gravedad para todas las entidades, en lugar de aplicar una fuerza en la dirección exactamente opuesta de un vector normal.
Ahora, ¿en base a qué punto debe calcularse ese vector normal del planeta?
La respuesta más fácil (que estoy bastante seguro de que funcionará bien) es aproximarse de manera similar al método de Newton : cuando los objetos aparecen por primera vez, conoces todas sus posiciones iniciales en el planeta. Use esa posición inicial para determinar el
up
vector de cada objeto . Obviamente la gravedad estará en la dirección opuesta (haciadown
). En el siguiente cuadro, antes de aplicar la gravedad, proyecta un rayo desde la nueva posición del objeto hacia su viejodown
vector. Use la intersección de ese rayo con el planeta como la nueva referencia para determinar elup
vector. El raro caso de que el rayo no golpee nada significa que algo salió terriblemente mal y debe mover su objeto de nuevo a donde estaba en el cuadro anterior.También tenga en cuenta que al usar este método, cuanto más origen del jugador sea del planeta, peor será la aproximación. Por lo tanto, es mejor usar en algún lugar alrededor de los pies de cada jugador como su origen. Supongo, pero creo que usar los pies como origen también resultará en un manejo y navegación más fácil del jugador.
Una última nota: para obtener mejores resultados, incluso puede hacer lo siguiente: realizar un seguimiento del movimiento del jugador en cada cuadro (por ejemplo, usando
current_position - last_position
). Luego sujete esomovement_vector
para que su longitud hacia el objetoup
sea cero. Llamemos a este nuevo vectorreference_movement
. Mueva el anteriorreference_point
porreference_movement
y use este nuevo punto como origen de trazado de rayos. Después (y si) el rayo golpea el planeta, muévasereference_point
a ese punto de golpe. Finalmente, calcule el nuevoup
vector, a partir de este nuevoreference_point
.Algunos pseudocódigo para resumirlo:
fuente
Esta publicación podría ser útil. Su esencia es que no usas los controladores de personajes, sino que los tuyos con el motor de física. Luego, usa las normales detectadas debajo del jugador para orientarlas hacia la superficie de la malla.
Aquí hay una buena descripción de la técnica. Hay muchos más recursos con términos de búsqueda en la web como "unidad caminar en objetos 3d mario galaxy".
También hay un proyecto de demostración de unity 3.x que tenía un motor para caminar, con un soldado y un perro y en una de las escenas. Demostró caminar sobre objetos 3d al estilo Galaxy . Runevision lo llama sistema de locomoción.
fuente
Rotación
Verifique la respuesta a esta pregunta en answers.unity3d.com (en realidad la pregunté yo mismo). Citar:
Aquí está el código que me sugirió:
Llame a eso cada actualización, y debería hacerlo funcionar. (tenga en cuenta que el código está en UnityScript ).
El mismo código en C # :
Gravedad
Para la gravedad, puede usar mi "técnica de física de planetas", que describí en mi pregunta, pero no está realmente optimizada. Era solo algo que tenía en mente.
Le sugiero que cree su propio sistema para la gravedad.
Aquí hay un tutorial de Youtube por Sebastian Lague . Esa es una solución que funciona muy bien.
EDITAR: en la unidad, vaya a Edición > Configuración del proyecto > Física y establezca todos los valores de Gravedad en 0 (o elimine el Cuerpo rígido de todos los objetos), para evitar que la gravedad incorporada (que simplemente tira al jugador hacia abajo) entre en conflicto con La solución personalizada. (apágalo)
fuente