Cómo implementar áreas de bordes suaves con partículas

13

Mi juego se creó con Phaser, pero la pregunta en sí es independiente del motor.

En mi juego tengo varios entornos, esencialmente áreas poligonales en las que los personajes jugadores pueden moverse y verse afectados. Por ejemplo, hielo, fuego, veneno, etc. El elemento gráfico de estas áreas es el área del polígono lleno de color y partículas del tipo adecuado (en este ejemplo fragmentos de hielo). Así es como lo estoy implementando actualmente: con una máscara de polígono que cubre un mosaico con el patrón de partículas:

ingrese la descripción de la imagen aquí

El borde duro se ve mal. Me gustaría mejorar haciendo dos cosas: 1. Hacer que el área de relleno del polígono tenga un borde suave y se mezcle con el fondo. 2. Haga que algunos fragmentos salgan del área del polígono, para que no se corten en el medio y el área no tenga una línea recta

por ejemplo (maqueta):

ingrese la descripción de la imagen aquí

Creo que se puede lograr 1 difuminando el polígono, pero no estoy seguro de cómo hacerlo con 2.

¿Cómo harías para implementar esto?

OpherV
fuente
2
Eso se ve increible. ¿Puedo tener un enlace a tu juego por favor? :)
cenizas999
@GameAlchemist Aquí está la imagen de mosaico i.imgur.com/y54CeQ9.png
OpherV
@ ashes999 Sigue siendo un trabajo en progreso. Definitivamente publicaré un enlace aquí una vez que lo tenga :)
OpherV
Observe que es un PNG transparente con objetos blancos. Si lo ve sobre un fondo blanco (como suele suceder al abrir una imagen en un navegador), no verá nada
OpherV
@OpherV eso sería genial. Simplemente edite su pregunta y publique un enlace; esa es probablemente la forma más temática de comercializarla en este sitio :)
ashes999

Respuestas:

2

1.Si quieres algo que esté cerca de tu maqueta, usaría partículas (no tiene que ser un sistema de partículas completamente desarrollado).

Renderice sus partículas en forma de polígono en una RenderTexture. Asegúrese de utilizar mezclas de aditivos en las partículas. Las partículas en el interior del polígono se mezclarán suavemente entre sí, mientras que las partículas en el exterior le darán el borde suave que desea. (Se puede ver un ejemplo del efecto en este video de youtube: Video de partículas aditivas Ahora renderice la RenderTexture en su pantalla principal y listo. La RenderTexture es necesaria para que las partículas no se mezclen con su fondo.

Puedes intentar colocar los triángulos directamente sobre la textura de la partícula y ver cómo funciona. De lo contrario, colóquelos encima de su "sopa de partículas" como una capa separada.

Creó una maqueta rápida en un jsfiddle actualizado que se ve así Manifestación Puede encontrar la demostración actualizada aquí

2. Cada partícula tiene una velocidad y un origen. Cuando tu jugador toca el polígono, cambias la velocidad de cada partícula proporcionalmente a la velocidad del jugador. Cuanto más lejos esté una partícula de tu jugador, menos se verá afectada por la velocidad del jugador.

La fórmula para calcular la velocidad de una partícula sería algo como esto:

//player.velocity and particle.velocity are vectors 
//k is a factor to enhance or weaken the influence of players velocity
var distanceToPlayer = (player.position - particle.position).length();
particle.velocity = particle.velocity + ((k * player.velocity) + particle.velocity) * (1/distanceToPlayer);

Para calcular la posición de la partícula, coloque esto en su método de actualización:

var speedY = -(springConstant * (particle.position.y - particle.origin.y)) - (dampingFactor * particle.velocity.y);
var speedX = -(springConstant * (particle.position.x - particle.origin.x)) - (dampingFactor * particle.velocity.x);

particle.position.y = particle.position.y + speedY;
particle.position.x = particle.position.x + speedX;

particle.velocity.x = particle.velocity.x + speedX;
particle.velocity.y = particle.velocity.y + speedY;

Esto debería darte un "fluido" donde cada partícula gira alrededor de su origen cuando el jugador agita el fluido. El springConstant cambia cuánto se aleja una partícula de su origen y el factor de amortiguación la rapidez con que la partícula se detiene. Es posible que tengas que modificar el código ya que es la versión modificada de una simulación 1d que uso en mi juego.

Ahora con una demostración: Demo Simplemente modifique las 3 constantes en la parte superior hasta que el fluido se comporte como lo desea.

zilluss
fuente
¡Esa es una idea realmente interesante para resolver # 1! Me gusta. ¿Cómo sugeriría implementar el movimiento del triángulo \ espaciado?
OpherV
1
Edité la publicación original para responder la pregunta # 2.
zilluss
Se agregó una pequeña demostración del efecto de partículas. Creo que podrías obtener el efecto deseado con un pequeño ajuste.
zilluss
Terminé usando su solución, es lo más parecido al efecto que estaba buscando lograr. ¡Gracias! Sin embargo, una pregunta: ¿cómo podría sujetar la elasticidad en sus ejemplos, de modo que movimientos realmente leves no causen que las partículas salten distancias tan grandes?
OpherV
Puedes jugar con dampingFactor y springConstant. Una amortiguación alta hará que las partículas descansen más rápido. Una constante de resorte más baja reduce la velocidad de las partículas. Desafortunadamente, ambos valores permiten que la sopa de partículas se sienta más viscosa. Entonces, en cambio, cuando tu jugador toca la partícula, puedes sujetar la velocidad máxima que el jugador agrega a la partícula, de esta manera: partícula.velocidad.x = clamp (maxVelocity, -maxVelocity, particle.velocity.x + ((playerInfluenceFactor * deltaVelocityX ) + particle.velocity.x) * (1 / distanceToPlayer)); para ver la abrazadera, consulte: stackoverflow.com/a/11409944
zilluss
4

Mis pensamientos sobre estos dos puntos:

  1. Puede usar el desenfoque del sombreador, pero será muy costoso. En cambio, dibujaría un borde extra de triángulos que se desvanecen de translúcido en el centro a transparente en los bordes, para simular el "desenfoque". Lo hice en un juego mío y funciona bastante bien. Aquí hay dos capturas de pantalla de un refuerzo de arco iris en mi juego.

    ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

    El borde exterior tiene un gradiente. En mi situación, el borde no comienza con la misma opacidad que la parte interna, pero si establece esas opacidades iguales, tendrá un agradable desvanecimiento.

  2. Programaría un sistema de partículas y haría que las partículas siguieran el polígono. Al hacerlo, no tiene que preocuparse por lo que sucederá en los bordes. La dinámica de su sistema de partículas se asegurará de que las partículas estén dentro del polígono y estén distribuidas uniformemente. Podrías tratar de hacer que las partículas más cercanas se alejen entre sí, pero hazlo con mucha "masa" para que tengas inercia y se vea suave. Para hacer esto más rápido, hay algunas posibilidades, pero el gran problema será la complejidad del tiempo de presionarse mutuamente. Si hace que cada partícula empuje a todas las demás, tendrá O (n ^ 2), lo que no es bueno, si tiene, por ejemplo, 100 partículas en su sistema. Una buena lectura sobre cómo puede optimizar esto es esta presentación de PixelJunk:http://fumufumu.q-games.com/gdc2010/shooterGDC.pdf

    Un enfoque más simple sería conectar cada partícula a otras tres o cuatro partículas al construir el sistema de partículas. Ahora cada partícula solo tendrá que empujar las otras cuatro partículas a las que está conectada. Sin embargo, este enfoque hace que las turbulencias en su sistema de partículas sean imposibles. Pero esto no parece ser un problema, ya que su situación actual utiliza una textura estática. Este enfoque será O (n), lo cual es genial.

Martijn Courteaux
fuente
¡Gracias! 1. Me está costando mucho visualizar esto. ¿Puedes publicar una maqueta de cómo se ve \ funciona en tu juego? 2. Interesante! leerá sobre eso
OpherV
Gracias por las imagenes. Puedo ver cómo funcionaría eso en una forma de tubo o línea, pero ¿cómo funcionará eso con un polígono? ¿Los gradientes de los triángulos proyectados desde cada lado no se alinearán bien ...?
OpherV
Haz que encajen bien. Esa es la idea. Esto implica algunos puntos de intersección matemáticos y computacionales, etc. También podría subdividir el borde y suavizarlo. Toneladas de posibilidades.
Martijn Courteaux
3

La idea que tuve al leer su publicación fue esta:
• construir un conjunto de mosaicos que usará para sus áreas.
• renderice el polígono de área en un pequeño lienzo temporal con la resolución del mosaico (por ejemplo: si los mosaicos son 16X16, renderice con una resolución (16X, 16X) menor).
• use ese lienzo temporal para decidir si desea renderizar mosaicos o no en el lienzo principal:
si se establece un punto en el lienzo de baja resolución, dibuje un mosaico 'aleatorio' en el lienzo principal. Si un punto es solo un vecino de un punto establecido, dibuje un mosaico 'aleatorio' con una opacidad menor (para hacer la transición) en el lienzo principal.

Temía que reducir la resolución creara un efecto de bloque, pero incluso con mosaicos de 20X20, se ve bastante bien:

ingrese la descripción de la imagen aquí

Los pasos para esto son: tome su polígono:
ingrese la descripción de la imagen aquí

Dibuje el polígono a la resolución de su mosaico: ingrese la descripción de la imagen aquí(¡sí, es la cosa roja del centro comercial).

Luego use imageData del lienzo de baja resolución para decidir si dibujar un mosaico o una nota.
Si se establece un píxel en el lienzo de baja resolución, significa que debemos dibujar el mosaico: seleccione un índice de mosaico 'aleatorio' para elegir qué mosaico dibujar. Ese índice aleatorio siempre debe ser el mismo para un área / mosaico dado.
Si un punto está vacío pero junto a un punto relleno, también dibuje un mosaico, pero con la mitad de la opacidad.

ingrese la descripción de la imagen aquí

Así que dibujemos las fichas:

ingrese la descripción de la imagen aquí

Para el polígono, solo dibujo varias veces el polígono, reduciéndolo y aumentando la opacidad en cada dibujo (también se puede usar el 'encendedor' globalCompositeOperation).

ingrese la descripción de la imagen aquí

Una vez que sumas todo, da:

ingrese la descripción de la imagen aquí

el violín está aquí:

http://jsfiddle.net/gamealchemist/T7b4Y/

Déjeme saber si esto ayuda.

GameAlchemist
fuente
¡Gracias por elaborar su solución y proporcionar el código! ¿Qué quiere decir con "Entonces use los datos de imagen del lienzo de baja resolución para decidir si dibujar un mosaico o una nota". ¿Cómo utiliza los datos de la imagen pequeña para decidir dónde \ cómo dibujar en la imagen grande? Y usando este método, ¿cómo puedo evitar la superposición de los triángulos para lograr un espacio similar al de mi maqueta?
OpherV
Quiero decir que es una prueba booleana completa: ¿necesito llenar este mosaico? , verdadero o falso, viene dado por la prueba de baja resolución en imageData [(x + y * width) * 4]! = 0, es decir == 'dibujé algo en el lienzo de baja resolución en ese lugar de baldosas? Entonces, en caso afirmativo, uso alguna fórmula elaborada llena de números primos (getRandomNumber) para pasar de (x, y) a un índice de mosaico 'aleatorio' que siempre proporcionará el mismo número para un área determinada + (x, y). No veo cómo las cosas podrían superponerse si define correctamente su polígono, así que no recibo su segunda pregunta.
GameAlchemist
1

Solo una idea:

En su mosaico, las "piezas" tienen aproximadamente 80px de ancho como máximo. Sugeriría, haciendo 2 áreas. Dibujas tu polígono original y haces una maqueta de él a unos 80 píxeles de cada borde. Luego dibujas tus fichas en el polígono más grande.

Luego, todas las "piezas" que tienen un píxel fuera del polígono interno, y sin intersección con el polígono interno que puede inundar, las llenan con transparencia.

Este es un nivel muy alto, pero pensé que lo compartiría contigo. Hay muchos detalles por determinar aquí.

Una imagen cruda para demostrar:

ingrese la descripción de la imagen aquí

Si el polígono negro interno fuera el original, borraría todos los polígonos con un punto rojo.

usuario46560
fuente
Sin embargo, ¿cómo comprobaría la intersección de las piezas incrustadas en la imagen de mosaico con el polígono interno?
OpherV
@OpherV Uhmm, ¿Puedes determinar si el punto X está en un polígono, verdad? Puede recorrer todos los píxeles en el polígono externo, y para cada píxel blanco, compruebe todos los píxeles, y vea si hay alguno en el interior / exterior. Sin embargo, esto no parece particularmente eficiente, pero una vez que tienes algo, ¿puedes pensar en formas de optimizar?
user46560
Ese es el procesamiento posterior realizado en la CPU. Difícilmente optimizable en sí mismo. Su idea podría funcionar bien si el polígono interno y el externo se conectan mediante una tira triangular. El OP podría agregar información de atributo de vértice y etiquetar cada vértice como dentro o fuera. Luego, en el sombreador de vértices, la opacidad / alfa se puede interpolar linealmente de un valor menos transparente a uno opaco completo.
Teodron
@teodron Este es el punto que intenté hacer en la respuesta. Es una idea de alto nivel, y no soy realmente un desarrollador de juegos. Acabo de tener una idea.
user46560
@ user46560 sí, pero de esta manera no tienes que calcular qué píxeles hay en esa banda entre polígonos ... ni en la GPU ni en la CPU. Como no estás acostumbrado a las formas de desarrollo del juego como dices, mereces un +1 por tu idea :).
Teodron