Como implementar áreas de borda macia com partículas

13

Meu jogo é criado usando Phaser, mas a pergunta em si é independente de mecanismo.

No meu jogo, tenho vários ambientes, áreas essencialmente poligonais pelas quais os personagens dos jogadores podem se mover e serem afetados. Por exemplo, gelo, fogo, veneno, etc. 'O elemento gráfico dessas áreas é a própria área de polígono preenchida com cores e partículas do tipo adequado (neste exemplo, fragmentos de gelo). É assim que estou implementando isso atualmente - com uma máscara de polígono cobrindo um mosaico com o padrão de partículas:

insira a descrição da imagem aqui

A borda dura parece ruim. Eu gostaria de melhorar fazendo duas coisas: 1. Fazendo com que a área de preenchimento do polígono tenha uma borda suave e se misture ao fundo. 2. Faça com que alguns dos fragmentos saiam da área do polígono, para que não sejam cortados no meio e a área não tenha uma linha reta

por exemplo (maquete):

insira a descrição da imagem aqui

Penso que é possível obter um desfoque do polígono, mas não sei ao certo como proceder com o 2.

Como você implementaria isso?

OpherV
fonte
2
Isso parece incrível. Posso ter um link para o seu jogo, por favor? :)
ashes999
@GameAlchemist Aqui está a imagem do bloco i.imgur.com/y54CeQ9.png
OpherV
@ ashes999 Ainda está em andamento. Definitivamente vou postar um link aqui depois que o tiver :) :)
OpherV 30/05
Observe que é um PNG transparente com objetos brancos. Se você o visualizar em um fundo branco (como sempre acontece ao abrir uma imagem em um navegador), não verá nada
OpherV
@OpherV isso seria ótimo. Por favor, basta editar a sua pergunta e postar um link - que é provavelmente a maneira mais sobre o tema para o mercado-lo neste site :)
ashes999

Respostas:

2

1.Se você quiser algo parecido com o seu modelo, eu usaria partículas (ele não precisa ser um sistema de partículas totalmente explodido).

Renderize suas partículas na forma de polígono em uma RenderTexture. Certifique-se de usar a mistura aditiva nas partículas. As partículas dentro do polígono se misturam suavemente, enquanto as partículas do lado de fora dão a borda macia que você deseja. (Um exemplo do efeito pode ser visto neste vídeo do youtube: Vídeo de partículas aditivas Agora, renderize a RenderTexture na tela principal e pronto. A RenderTexture é necessária para que as partículas não se misturem com o fundo.

Você pode tentar colocar os triângulos diretamente na textura das partículas e ver como isso funciona. Caso contrário, processe-os em cima da sua "sopa de partículas" como uma camada separada.

Criou uma maquete rápida em um jsfiddle atualizado com esta aparência. Demo Você pode encontrar a demonstração atualizada aqui

2.Cada partícula tem uma velocidade e uma origem. Quando o seu jogador toca no polígono, você altera a velocidade de cada partícula proporcional à velocidade do jogador. Quanto mais longe uma partícula estiver do seu jogador, menos ela será afetada pela velocidade do jogador.

A fórmula para calcular a velocidade das partículas seria algo como isto:

//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 a posição da partícula, coloque isso no seu método de atualização:

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;

Isso deve fornecer um "fluido", onde cada partícula gira em torno de sua origem quando o jogador agita o fluido. O springConstant altera o quanto uma partícula se afasta de sua origem e o fator de amortecimento a rapidez com que a partícula pára. Você pode precisar ajustar o código, já que é a versão modificada de uma simulação 1d que uso no meu jogo.

Agora com uma demonstração: Demo Basta ajustar as 3 constantes no topo até que o fluido se comporte como você deseja.

zilluss
fonte
Essa é uma ideia realmente interessante para resolver # 1! Eu gosto disso. Como você sugeriria implementar o movimento \ espaçamento do triângulo?
OpherV
1
Editei a postagem original para responder à pergunta 2.
Zilluss 31/05
adicionou uma pequena demonstração do efeito das partículas. Eu acho que você pode obter o efeito desejado com um pouco de ajustes.
zilluss
Acabei usando a sua solução, é a mais próxima do efeito que pretendia alcançar. Obrigado! Porém, uma pergunta - como restringir a elasticidade em seus exemplos, para que movimentos realmente leves não façam com que as partículas pulem distâncias tão grandes?
OpherV
Você pode brincar com o dampingFactor e o springConstant. Um alto amortecimento levará as partículas mais rapidamente a um descanso. Uma constante mais baixa da mola diminui a velocidade das partículas. Infelizmente, ambos os valores deixam a sopa de partículas mais viscosa. Portanto, quando seu player toca a partícula, você pode fixar a velocidade máxima que o player adiciona à partícula, assim: particle.velocity.x = clamp (maxVelocity, -maxVelocity, particle.velocity.x + ((playerInfluenceFactor * deltaVelocityX ) + particle.velocity.x) * (1 / distanceToPlayer)); para braçadeira, consulte: stackoverflow.com/a/11409944
zilluss
4

Meus pensamentos sobre esses dois pontos:

  1. Você pode usar o shader blur, mas isso vai ser muito caro. Em vez disso, eu desenharia uma borda extra de triângulos que desbotam de translúcido no centro para transparente nas bordas, para simular o "desfoque". Eu fiz isso em um jogo meu e funciona muito bem. Aqui estão duas capturas de tela de um reforço de arco-íris no meu jogo.

    insira a descrição da imagem aqui insira a descrição da imagem aqui

    A borda externa tem um gradiente. Na minha situação, a borda não começa com a mesma opacidade que a parte interna, mas se você definir essas opacidades iguais, terá um bom desbotamento.

  2. Eu programaria um sistema de partículas e faria as partículas seguirem o polígono. Ao fazer isso, você não precisa se preocupar com o que acontecerá nas bordas. A dinâmica do seu sistema de partículas garantirá que as partículas estejam dentro do polígono e sejam distribuídas uniformemente. Você pode tentar fazer com que as partículas mais próximas se afastem, mas com muita "massa", para que você tenha inércia e pareça suave. Para tornar isso rápido, existem algumas possibilidades, mas o grande problema será a complexidade do tempo do mecanismo de pressionar um ao outro. Se você fizer cada partícula empurrar qualquer outra partícula, você terá O (n ^ 2), o que não é bom, se você estiver tendo, por exemplo, 100 partículas em seu sistema. Uma boa leitura sobre como otimizar isso é esta apresentação do PixelJunk:http://fumufumu.q-games.com/gdc2010/shooterGDC.pdf

    Uma abordagem mais simples seria conectar cada partícula a três ou quatro outras partículas ao construir o sistema de partículas. Agora, cada partícula terá apenas que empurrar as outras quatro partículas às quais está conectada. No entanto, essa abordagem impossibilita turbulências no seu sistema de partículas. Mas isso não parece ser um problema, pois sua situação atual usa uma textura estática. Essa abordagem será O (n), o que é ótimo.

Martijn Courteaux
fonte
Obrigado! 1. Estou tendo dificuldade para visualizar isso. Você pode postar uma maquete de como ele parece \ funciona no seu jogo? 2. Interessante! vai ler sobre isso
OpherV
Obrigado pelas imagens. Posso ver como isso funcionaria em forma de tubo ou linha, mas como isso funcionará com um polígono? Os gradientes dos triângulos projetados de cada lado não se alinham muito bem ...?
OpherV
Faça com que caibam bem. Essa é a ideia. Isso envolve alguns pontos matemáticos e computacionais de interseção, etc. Você também pode subdividir a borda e suavizá-la. Toneladas de possibilidades.
Martijn Courteaux
3

A idéia que tive ao ler sua postagem foi a seguinte:
• construa um conjunto de peças que você usará em suas áreas.
• renderize o polígono da área em uma pequena tela temporária com a resolução do bloco (ex: se os blocos tiverem 16X16, renderize com uma resolução menor (16X, 16X)).
• use essa tela temporária para decidir se deseja renderizar ou não a tela principal:
se um ponto estiver definido na tela de baixa resolução, desenhe uma tela 'aleatória' na tela principal. se um ponto for apenas um vizinho de um ponto definido, desenhe um bloco 'aleatório' com uma opacidade mais baixa (para fazer a transição) na tela principal.

Eu tinha medo que diminuir a resolução criaria um efeito de bloco, mas mesmo com blocos de 20X20, parece muito bom:

insira a descrição da imagem aqui

As etapas para isso são: pegue seu polígono:
insira a descrição da imagem aqui

Desenhe o polígono com a resolução do seu bloco: insira a descrição da imagem aqui(!! Sim, é o vermelho do shopping).

Em seguida, use o imageData da tela de baixa resolução para decidir se deseja desenhar um bloco ou anotação.
Se um pixel é definido na tela de baixa resolução, significa que devemos desenhar o bloco: escolha um índice 'aleatório' para escolher qual bloco desenhar. Esse índice aleatório deve sempre ser o mesmo para uma determinada área / peça.
Se um ponto estiver vazio, mas próximo a um ponto preenchido, desenhe também um ladrilho, mas com meia opacidade.

insira a descrição da imagem aqui

Então, vamos desenhar as peças:

insira a descrição da imagem aqui

Para o polígono, basta desenhar várias vezes o polígono, reduzi-lo e aumentar a opacidade em cada desenho (pode-se também usar o globalCompositeOperation 'mais leve').

insira a descrição da imagem aqui

Depois de adicionar tudo, ele fornece:

insira a descrição da imagem aqui

violino está aqui:

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

avise-me se isso ajudar.

GameAlchemist
fonte
Obrigado por elaborar sua solução e fornecer o código! O que você quer dizer com "Em seguida, use os dados de imagem da tela de baixa resolução para decidir se deseja desenhar um bloco ou uma nota". Como você usa os dados de imagem pequena para decidir onde \ como desenhar a imagem grande? E usando esse método, como posso evitar a sobreposição dos triângulos para obter um espaçamento semelhante ao da minha maquete?
OpherV 31/05
Quero dizer, é um teste booleano completo: preciso preencher esse bloco? , true ou false, é dado pelo teste de baixa resolução em imageData [(x + y * width) * 4]! = 0, ou seja, == 'eu desenhei algo na tela de resolução mais baixa em aquele lugar de azulejos? '. Então, se sim, eu uso alguma fórmula elaborada preenchida com número primo (getRandomNumber) para ir de (x, y) para um índice de bloco 'aleatório' que sempre fornecerá o mesmo número para uma determinada área + (x, y). Não vejo como as coisas poderiam se sobrepor se você definir corretamente seu polígono, para que eu não tenha sua segunda pergunta.
GameAlchemist
1

Apenas uma ideia:

No seu bloco, as "peças" têm no máximo cerca de 80 px de largura. Eu sugeriria, fazendo 2 áreas. Você desenha seu polígono original e faz uma maquete cerca de 80 pixels de cada borda. Você desenha suas peças no polígono maior.

Então, todas as "peças" que possuem um pixel fora do polígono interno e nenhuma interseção com o polígono interno que você pode inundar os preenche com transparência.

Este é um nível muito alto, mas achei que o compartilharia com você. Há muitos detalhes a serem determinados aqui.

Uma imagem bruta para demonstrar:

insira a descrição da imagem aqui

Se o polígono preto interno fosse o original, você apagaria todos os polígonos com um ponto vermelho.

user46560
fonte
Como você verificaria a interseção das peças incorporadas na imagem do bloco com o polígono interno?
OpherV
@OpherV Uhmm, você pode determinar se o ponto X está em um polígono, certo? Você pode percorrer todos os pixels do polígono externo e, para cada pixel branco, verifique todos os pixels e verifique se há algum na parte interna / externa. Porém, isso não parece particularmente eficiente, mas depois de ter algo, você pode pensar em maneiras de otimizar?
User46560
Isso é pós-processamento feito na CPU. Dificilmente otimizável em si mesmo. Sua idéia pode funcionar bem se o polígono interno e o externo forem conectados por uma faixa triangular. O OP pode adicionar informações sobre o atributo do vértice e marcar cada vértice como interno ou externo. Então, no sombreador de vértice, a opacidade / alfa pode ser interpolada linearmente de um valor menos transparente para um valor opaco completo.
Teodron 30/05
@teodron Este é o ponto que tentei fazer na resposta. É uma ideia de alto nível, e eu não sou realmente desenvolvedor de jogos. Acabei de ter uma idéia.
User46560
@ user46560 sim, mas desta forma você não precisa calcular quais pixels estão nessa faixa entre polígonos, nem na GPU nem na CPU. Como você não está acostumado às formas de desenvolvimento de jogos, como você diz, merece um +1 para a sua ideia :).
Teodron 30/05