Tengo un sistema de agua basado en una cuadrícula 2D en mi juego XNA, tenemos un método que utiliza autómatas celulares para simular la caída y propagación del agua.
Ejemplo de agua que fluye por una pendiente:
Cada mosaico puede contener una masa de 0 a 255 valores de líquido, almacenados en un byte. No uso floats
el antiguo sistema de agua que tenía, sin embargo, agregó complicaciones y tuvo un impacto en el rendimiento.
Cada baldosa de agua se actualiza con un conjunto simple de reglas:
- Si el mosaico de abajo tiene espacio, muévase tanto como sea posible del mosaico actual al inferior (Flujo hacia abajo)
- Si los 2 lados no son iguales y no son cero y ambos son transitables, obtenemos la suma de las 3 fichas (izquierda + actual + derecha) y la dividimos entre 3 dejando el resto en la casilla central (actual)
- Si la regla anterior dio un número de 2 como suma, deberíamos dividir las fichas en los dos lados (1, 0, 1)
- Si la regla 2 dio 1 como la suma, elija un lado aleatorio para fluir
- Si la regla 2 falla, debemos verificar si un lado es aceptable y el otro no. Si eso es cierto, dividimos el mosaico actual por la mitad para los 2 mosaicos.
¿Cómo puedo ampliar esta lógica para incluir la presión? La presión hará que los líquidos suban sobre las "curvas en U" y llene las bolsas de aire.
Ejemplo sobre cómo esto falla actualmente:
El agua debe fluir y ecualizarse a cada lado de la curva en U. Además, he creado métodos para averiguar qué tan lejos está un bloque de agua y, por lo tanto, cuánta presión está experimentando. Ahora necesito poder tomar estos números y aplicarlos a las otras áreas para igualar la presión.
Respuestas:
Tenga en cuenta que nunca he hecho esto; Estas son solo ideas que pueden ayudar. O podría ser totalmente falso. Desde que Terraria he querido abordar este problema, pero actualmente no estoy trabajando en ese juego.
Una forma en la que he considerado intentar es darle a cada bloque de agua superficial (cualquier bloque con agua y sin un bloque de agua encima) un valor de presión inicial igual (o una función de) su altura desde el fondo del mundo. El valor de presión implícito de cualquier ficha infranqueable es
MAX_PRESSURE
(digamos 255), y para una ficha al aire libre esMIN_PRESSURE
(0).Luego, la presión se extiende hacia arriba / abajo / lateralmente desde cualquier mosaico con una presión más alta a mosaicos con una presión más baja durante cada tic, estilo de autómata celular. Tendría que obtener una simulación real para averiguar exactamente a qué ecualizar. La presión de un bloque debe ser igual a su presión implícita más la presión "excesiva" de alrededor de la ecualización (por lo que solo necesitaría almacenar este exceso de presión, no la presión implícita).
Si una loseta de superficie tiene una presión mayor que su presión implícita basada en la altura y si la loseta de arriba tiene espacio libre para el agua, una pequeña porción de agua se mueve hacia arriba. El agua solo fluye hacia abajo si la loseta tiene espacio, ya que tiene una presión más baja de lo esperado.
Esto simula más o menos la idea de que cuanto más profundo es el "punto" del agua, más presión tiene, aunque los valores de presión representan más la altura que la presión real (ya que se espera que las baldosas más altas tengan una "presión" más alta). Esto hace que la presión sea algo así como el
h
término en la ecuación (pero no realmente):El resultado es que si la presión del agua es más alta de lo que debería ser por su profundidad, será empujada hacia arriba. Debería significar que los niveles de agua en sistemas cerrados igualarán la presión en todos los niveles de altura con el tiempo.
No estoy seguro de cómo lidiar o si uno incluso necesita lidiar con las "burbujas de aire" que se crearían (donde una baldosa no superficial tendrá cantidades de agua no llenas cuando el agua se empuja hacia arriba). Tampoco estoy seguro de cómo evitaría que las presiones de agua de los bucles sean desiguales en un lado y luego, después de marcar, en el otro lado, de un lado a otro.
fuente
Creé un sistema similar al que buscas en 3D. Tengo un video corto que demuestra la mecánica simple de esto aquí y una publicación de blog aquí .
Aquí hay un pequeño gif que hice de la mecánica de presión detrás de un muro invisible (jugado a alta velocidad):
Permítanme explicar los datos involucrados, para dar una idea de algunas de las características del sistema. En el sistema actual, cada bloque de agua contiene lo siguiente en 2 bytes:
Height
es la cantidad de agua en el cubo, similar a su presión, pero mi sistema solo tiene 8 niveles.Direction
es la dirección en la que va el flujo. Al decidir dónde fluirá el agua a continuación, es más probable que continúe en su dirección actual. Esto también se utiliza para rastrear rápidamente un flujo hasta su cubo de origen cuando sea necesario.IsSource
indica si este cubo es un cubo fuente, lo que significa que nunca se queda sin agua. Usado para la fuente de ríos, manantiales, etc. El cubo a la izquierda en el gif de arriba es un cubo fuente, por ejemplo.HasSource
indica si este cubo está conectado a un cubo fuente. Cuando se conecta a una fuente, los cubos intentarán aprovechar la fuente para obtener más agua antes de buscar otros cubos sin fuente "más completos".Largest
le dice a este cubo cuál es el flujo más grande entre él y su cubo fuente. Esto significa que si el agua fluye a través de un espacio estrecho, limita el flujo a este cubo.Active
Es un mostrador. Cuando este cubo tiene un flujo activo que lo atraviesa, hacia él o desde él, el activo se incrementa. De lo contrario, el activo se disminuye aleatoriamente. Una vez que el activo llegue a cero (lo que significa que no está activo), la cantidad de agua comenzará a reducirse en este cubo. Este tipo de actos como evaporación o remojo en el suelo. ( Si tienes flujo, ¡deberías tener reflujo! )FlowOut
indica si este cubo está conectado a un cubo que está en el borde del mundo. Una vez que se hace un camino hacia el borde del mundo, el agua tiende a elegir ese camino sobre cualquier otro.Extra
es un bit extra para uso futuro.Ahora que conocemos los datos, veamos una descripción general de alto nivel del algoritmo. La idea básica del sistema es priorizar el flujo hacia abajo y hacia afuera. Como explico en el video, trabajo de abajo hacia arriba. Cada capa de agua se procesa un nivel a la vez en el eje y. Los cubos para cada nivel se procesan al azar, cada cubo intentará extraer agua de su fuente en cada iteración.
Los cubos de flujo extraen agua de su fuente siguiendo su dirección de flujo hacia arriba hasta que alcanzan un cubo fuente o un cubo de flujo sin padre. Almacenar la dirección del flujo en cada cubo hace que seguir la ruta a la fuente sea tan fácil como atravesar una lista vinculada.
El pseudocódigo para el algoritmo es el siguiente:
Las reglas básicas para expandir un flujo donde (ordenado por prioridad):
Lo sé, eso es bastante alto nivel. Pero es difícil entrar en más detalle sin conseguir manera en detalles.
Este sistema funciona bastante bien. Puedo llenar fácilmente pozos de agua, que se desbordan para continuar hacia afuera. Puedo llenar túneles en forma de U como ves en el gif de arriba. Sin embargo, como dije, el sistema está incompleto y aún no he resuelto todo. No he trabajado en el sistema de flujo en mucho tiempo (decidí que no era necesario para alfa y lo puse en espera). Sin embargo, los problemas con los que estaba lidiando cuando lo puse en espera fueron:
Piscinas . Al obtener un gran charco de agua, los punteros de niño a padre son como un desorden loco de cualquier cubo aleatorio seleccionado para fluir en cualquier dirección. Como llenar una bañera con una cuerda tonta. Cuando desee drenar la bañera, ¿debe seguir el camino de la cuerda tonta de regreso a su fuente? ¿O deberías tomar lo que sea más cercano? Entonces, en situaciones en las que los cubos están en un gran grupo, es probable que simplemente ignoren sus flujos primarios y tomen todo lo que esté por encima de ellos. Se me ocurrió un código de trabajo básico para esto, pero nunca tuve una solución elegante con la que pudiera estar feliz.
Múltiples padres . Una secuencia secundaria podría ser alimentada fácilmente por más de una secuencia principal. Pero el niño que tiene un puntero a un padre soltero no lo permitiría. Esto se puede solucionar mediante el uso de suficientes bits para permitir un bit para cada posible dirección principal. Y es probable que cambie el algoritmo para seleccionar aleatoriamente una ruta en el caso de varios padres. Pero, nunca pude probarlo y ver qué otros problemas podrían exponer.
fuente
Estoy de acuerdo con Sean, pero lo haría un poco diferente:
Un bloque genera una presión igual a su propio peso (la cantidad de agua que contiene) y lo aplica a los bloques debajo y al lado. No veo ninguna razón por la cual su posición en el mundo sea relevante.
En cada marca mueva el agua de alta a baja presión, pero mueva solo una fracción del agua necesaria para igualar. El agua también puede ser empujada hacia arriba si la presión en el bloque es demasiado grande para la presión que se aplica sobre el cuadrado.
Obtendrá bucles donde la presión del agua fluye demasiado en un sentido y luego tiene que corregir, pero como no mueve toda la cantidad de agua por tic, estos se amortiguarán. Creo que en realidad es algo bueno, ya que obtendrás efectos de sobretensión a medida que el agua se inunda en un área como lo harías en realidad.
fuente
Puede agregar una regla que intente ir hacia la izquierda o hacia la derecha (a través de las paredes) con los mosaicos hasta que encuentre un lugar libre, comenzando con las capas en la parte inferior. Si no puede encontrar, el mosaico permanece en la posición actual. Si lo encuentra, las otras reglas garantizarán el reemplazo de la ficha movida (si es necesario).
fuente
¿por qué no puedes definir otro tipo de bloque que actúe como una cantidad inamovible de presión? Por lo tanto, cuando usa su forma de mover normalmente los bloques de agua y verificar si puede moverse hacia arriba, no puede.
Aún mejor sería agregar otra definición a esos bloques que permita al usuario ingresar la cantidad de presión por bloque, aumentando la presión de acuerdo con la cantidad de bloques de agua que se le agreguen.
fuente