Come implementare aree con bordi morbidi con particelle


13

Il mio gioco è stato creato usando Phaser, ma la domanda in sé è indipendente dal motore.

Nel mio gioco ho diversi ambienti, essenzialmente aree poligonali in cui i personaggi del giocatore possono spostarsi ed essere interessati. Ad esempio ghiaccio, fuoco, veleno ecc. 'L'elemento grafico di queste aree è l'area poligonale piena di colore stesso e particelle del tipo adatto (in questo esempio frammenti di ghiaccio). Ecco come lo sto attualmente implementando - con una maschera poligonale che copre un tileprite con il motivo a particelle:

inserisci qui la descrizione dell'immagine

Il bordo duro sembra cattivo. Vorrei migliorare facendo due cose: 1. Rendere l'area di riempimento del poligono per avere un bordo morbido e fondersi con lo sfondo. 2. Fai in modo che alcuni frammenti escano dall'area del poligono, in modo che non vengano tagliati nel mezzo e l'area non abbia una linea retta

ad esempio (mockup):

inserisci qui la descrizione dell'immagine

Penso che 1 possa essere ottenuto sfocando il poligono, ma non sono sicuro di come procedere con 2.

Come faresti per implementarlo?


2
Sembra fantastico. Posso avere un link al tuo gioco per favore? :)
ashes999,

@GameAlchemist Ecco l'immagine della piastrella i.imgur.com/y54CeQ9.png
OpherV

@ ashes999 È ancora in fase di elaborazione.
Pubblicherò

Si noti che è un PNG trasparente con oggetti bianchi. Se lo visualizzi su uno sfondo bianco (come spesso accade quando apri un'immagine in un browser) non vedrai nulla
OpherV,

@OpherV sarebbe fantastico. Per favore, modifica la tua domanda e pubblica un link - questo è probabilmente il modo più
tematico

Risposte:


2

1.Se vuoi qualcosa che è vicino al tuo modello, userei le particelle (non deve essere un sistema di particelle completamente bruciato).

Rendi le tue particelle sotto forma di poligono su una RenderTexture. Assicurati di usare la miscelazione additiva sulle particelle. Le particelle all'interno del poligono si fonderanno uniformemente l'una con l'altra mentre le particelle all'esterno daranno il bordo morbido che desideri. (Un esempio dell'effetto può essere visto in questo video di YouTube: Video sulle particelle additive additive Ora esegui il rendering del RenderTexture sulla schermata principale e il gioco è fatto. Il RenderTexture è necessario in modo che le particelle non si fondano con lo sfondo.

Puoi provare a mettere i triangoli direttamente sulla trama delle particelle e vedere come funziona. Altrimenti renderli sopra la tua "zuppa di particelle" come uno strato separato.

Creato un mockup rapido in un jsfiddle aggiornato che assomiglia a questo dimostrazione Puoi trovare la demo aggiornata qui

2. Ogni particella ha una velocità e un'origine. Quando il tuo giocatore tocca il poligono, cambi la velocità di ogni particella in proporzione alla velocità del giocatore. Più una particella è lontana dal tuo giocatore, meno è influenzata dalla velocità del giocatore.

La formula per calcolare una velocità delle particelle sarebbe qualcosa del genere:

//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);

Per calcolare la posizione della particella, inserirla nel metodo di aggiornamento:

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;

Questo dovrebbe darti un "fluido" in cui ogni particella oscilla attorno alla sua origine quando il giocatore agita il fluido. La molla Costante cambia la quantità di una particella che si allontana dalla sua origine e lo smorzamento Fattore della velocità con cui la particella si ferma. Potrebbe essere necessario modificare il codice poiché è la versione modificata di una simulazione 1d che utilizzo nel mio gioco.

Ora con una demo: Demo Basta modificare le 3 costanti in alto fino a quando il fluido si comporta come si desidera.


È un'idea davvero interessante da risolvere n. 1! Mi piace. Come consiglieresti di implementare il movimento del triangolo \ spaziatura?
OpherV,

1
Ho modificato il post originale per rispondere alla domanda n. 2.
zilluss,

aggiunto una piccola demo dell'effetto particella. Penso che potresti ottenere l'effetto desiderato con un piccolo ritocco.
zilluss,

Ho finito per usare la tua soluzione, è il più vicino all'effetto che stavo cercando di ottenere. Grazie! Una domanda però: come potrei bloccare l'elasticità nei tuoi esempi, in modo che movimenti molto lievi non facciano saltare le particelle a distanze così grandi?
OpherV

Puoi giocare con il dampingFactor e il springConstant. Un elevato smorzamento porterà le particelle più velocemente a riposare. Una costante di molla inferiore riduce la velocità delle particelle. Sfortunatamente, entrambi i valori rendono la zuppa di particelle più viscosa. Quindi, invece, quando il tuo giocatore tocca la particella, puoi bloccare la velocità massima che il giocatore aggiunge alla particella, in questo modo: particle.velocity.x = clamp (maxVelocity, -maxVelocity, particle.velocity.x + ((playerInfluenceFactor * deltaVelocityX ) + particle.velocity.x) * (1 / distanceToPlayer)); per morsetto vedere: stackoverflow.com/a/11409944
zilluss

4

Le mie opinioni su questi due punti:

  1. Puoi usare la sfocatura dello shader, ma sarà molto costoso. Disegnerei invece un ulteriore bordo di triangoli che si sbiadiscono da traslucido al centro a trasparente ai bordi, per simulare la "sfocatura". L'ho fatto in un mio gioco e funziona abbastanza bene. Ecco due schermate di un booster arcobaleno nel mio gioco.

    inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

    Il bordo esterno ha una sfumatura. Nella mia situazione, il bordo non inizia con la stessa opacità della parte interna, ma se si impostano quelle opacità uguali, si avrà una bella dissolvenza.

  2. Programmerei un sistema di particelle e farei seguire alle particelle il poligono. In questo modo, non devi preoccuparti di ciò che accadrà ai bordi. La dinamica del tuo sistema particellare farà in modo che le particelle siano all'interno del poligono e distribuite uniformemente. Potresti provare a far allontanare le particelle più vicine, ma fallo con molta "massa" in modo da avere inerzia e sembrare liscia. Per rendere questa cosa veloce, ci sono alcune possibilità, ma il grande problema sarà la complessità temporale della spinta reciproca del meccanismo. Se fai in modo che ogni particella spinga ogni altra particella, avrai O (n ^ 2), il che non è buono, se hai ad esempio 100 particelle nel tuo sistema. Una buona lettura su come ottimizzare questo è questa presentazione di PixelJunk:http://fumufumu.q-games.com/gdc2010/shooterGDC.pdf

    Un approccio più semplice sarebbe quello di collegare ciascuna particella a tre o quattro altre particelle durante la costruzione del sistema di particelle. Ora ogni particella dovrà solo spingere le altre quattro particelle a cui è connessa. Tuttavia, questo approccio rende impossibili le turbolenze nel sistema particellare. Ma questo non sembra essere un problema, poiché la tua situazione attuale utilizza una trama statica. Questo approccio sarà O (n) che è fantastico.


Grazie! 1. Sto facendo fatica a visualizzarlo. Puoi per favore pubblicare un modello di come appare \ funziona nel tuo gioco? 2. Interessante! leggerà su questo
OpherV

Grazie per le immagini Posso vedere come funzionerebbe in una forma basata su tubo o linea, ma come funzionerà con un poligono? I gradienti dei triangoli proiettati da ciascun lato non si allineano bene ...?
OpherV,

Falli stare bene. Questa è l'idea. Ciò comporta alcuni punti matematici e computazionali di intersezione ecc. Potresti anche suddividere il bordo e smussarlo. Tonnellate di possibilità.
Martijn Courteaux,

3

L'idea che ho avuto durante la lettura del tuo post è stata questa:
• costruisci un set di tessere che utilizzerai per le tue aree.
• eseguire il rendering del poligono area su una piccola tela temporanea alla risoluzione delle piastrelle (es: se le piastrelle sono 16X16, renderizzate con una risoluzione (16X, 16X) inferiore).
• usa quella tela temporanea per decidere se renderizzare le tessere o meno sulla tela principale:
se un punto è impostato sulla tela a bassa risoluzione, disegna una tessera 'casuale' sulla tela principale. se un punto è solo un vicino di un set point, disegna una tessera "casuale" con un'opacità inferiore (per effettuare la transizione) sulla tela principale.

Avevo paura che abbassare la risoluzione avrebbe creato un effetto a blocchi, ma anche con tessere 20X20, sembra abbastanza buono:

inserisci qui la descrizione dell'immagine

I passaggi per questo sono: prendi il tuo poligono:
inserisci qui la descrizione dell'immagine

Disegna il poligono alla risoluzione della tua tessera: inserisci qui la descrizione dell'immagine(!! sì, è la cosa rossa del centro commerciale).

Quindi utilizzare imageData della tela a bassa risoluzione per decidere se disegnare una tessera o una nota.
Se un pixel è impostato sulla tela a bassa risoluzione, significa che dovremmo disegnare la tessera: prendi un indice di tessera "casuale" per scegliere quale tessera disegnare. Quell'indice casuale dovrebbe essere sempre lo stesso per una data area / tessera.
Se un punto è vuoto ma accanto a un punto pieno, disegna anche una tessera, ma con metà opacità.

inserisci qui la descrizione dell'immagine

Quindi disegniamo le tessere:

inserisci qui la descrizione dell'immagine

Per il poligono ho semplicemente disegnato più volte il poligono, ridimensionandolo e aumentando l'opacità su ogni disegno (si potrebbe usare anche GlobalCompositeOperation 'accendino').

inserisci qui la descrizione dell'immagine

Una volta aggiunto tutto, si ottiene:

inserisci qui la descrizione dell'immagine

il violino è qui:

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

fammi sapere se questo aiuta.


Grazie per aver elaborato la tua soluzione e fornito il codice! Cosa intendi con "Quindi usa imageData della tela a bassa risoluzione per decidere se disegnare una tessera o una nota". Come si utilizzano i dati di piccole immagini per decidere dove \ come disegnare sull'immagine grande? E usando questo metodo come posso evitare la sovrapposizione dei triangoli in modo da ottenere una spaziatura simile al mio modello?
OpherV,

Voglio dire, è un test booleano completo: devo riempire questa tessera? , vero o falso, è dato dal test del test a bassa risoluzione su imageData [(x + y * larghezza) * 4]! = 0, vale a dire == 'ho disegnato qualcosa sulla tela a bassa risoluzione in quel posto di piastrelle? '. Quindi, se sì, utilizzo una formula elaborata con numero primo (getRandomNumber) per passare da (x, y) a un indice di piastrelle "casuale" che fornirà sempre lo stesso numero per una determinata area + (x, y). Non vedo come le cose potrebbero sovrapporsi se si definisce correttamente il poligono, quindi non ottengo la tua seconda domanda.
GameAlchemist

1

Solo un'idea:

Nella tua tessera, i "pezzi" hanno una larghezza di circa 80 px al massimo. Vorrei suggerire, facendo 2 aree. Disegni il poligono originale e ne realizzi un modello a circa 80 pixel da ciascun bordo. Quindi disegna le tue tessere nel poligono più grande.

Quindi, tutti i "pezzi" che hanno un pixel al di fuori del poligono interno e senza intersezione con il poligono interno è possibile inondarli riempirli di trasparenza.

Questo è di altissimo livello, ma ho pensato di condividerlo con te. Ci sono molti dettagli da determinare qui.

Un'immagine rozza per dimostrare:

inserisci qui la descrizione dell'immagine

Se il poligono nero interno fosse l'originale, cancelleresti tutti i poligoni con un punto rosso.


Come controlleresti l'intersezione per i pezzi incorporati nell'immagine della piastrella con il poligono interno?
OpherV,

@OpherV Uhmm, puoi determinare se il punto X si trova in un poligono giusto? Puoi scorrere tutti i pixel nel poligono esterno e, per ogni pixel bianco, controllare tutti i pixel e vedere se si trovano all'interno / all'esterno. Questo non sembra particolarmente efficiente, però, ma una volta che hai qualcosa puoi pensare a modi per ottimizzare?
user46560,

Questa è la post-elaborazione eseguita sulla CPU. Difficilmente ottimizzabile su se stesso. La tua idea potrebbe funzionare bene se il poligono interno e l'esterno sono collegati da una striscia triangolare. L'OP potrebbe aggiungere informazioni sull'attributo vertice e contrassegnare ciascun vertice come interno o esterno. Quindi, nel vertex shader, l'opacità / alfa può essere interpolata linearmente da un valore meno trasparente a uno completo opaco.
teodron,

@teodron Questo è il punto che ho cercato di formulare nella risposta. È un'idea di alto livello e non sono proprio uno sviluppatore di giochi. Ho appena avuto un'idea.
user46560,

@utente46560 sì, ma in questo modo non è necessario calcolare i pixel in quella banda inter-poligonale .. né sulla GPU, né sulla CPU. Dal momento che non sei abituato ai modi di sviluppo del gioco come dici, meriti un +1 per la tua idea :).
teodron,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.