Como crio um efeito World Healing Wave?

14

Quero mudar meu fundo escuro e deprimente para um fundo gramado feliz , em tempo real, de modo que o plano de fundo feliz seja mostrado em um raio em torno do personagem do jogo.

Um campo de força de felicidade , se você quiser.

Como isso pode ser feito da maneira mais eficiente possível ao renderizar para uma tela em uma exibição personalizada?


UPDATE: Veja como funciona na minha cabeça:

    private int hModeX, hModeY;
    private float hModeRadius = 0.1f;
    private float hModeStart = 0;
    happyModeBg = Bitmap.createScaledBitmap(happyModeBg, getWidth(),getHeight(), true);
    hModeX = getWidth()/2;
    hModeY = getHeight()/2;

private void initHappyMode(Canvas canvas){
    hModeRadius = 75 * thread.getDelta();

    if(hModeRadius > 500) {
        hModeStart = timestep; //What is timestep?
    }

    //context.arc(x, y, radius, 0, 2 * Math.PI, false); <- your version
    canvas.save();
    canvas.drawArc(oval, startAngle, sweepAngle, useCenter, paint) // <- my version
    //context.clip(); <- dont know what this does or if there is an equivilant
    canvas.drawBitmap(happyModeBg, 0, 0, null);
    canvas.restore();
    //requestAnimationFrame(step); <- dont know what this does since I cant seem to find it for android

}

Estou usando canvas.drawArc()para fazer um círculo, mas definitivamente estou perdendo alguma coisa.

Green_qaue
fonte
1
tecnicamente é chamado World Healing Wave
catraca aberração
Eu só uso lona em uma exibição personalizada dirigida por meu próprio jogo de loop a 60fps
Green_qaue
Você poderia renderizar a cena duas vezes? Uma vez para a versão curada, uma vez para a versão morta e, em seguida, desenhe os curados sobre os mortos em um círculo cada vez maior até que o círculo cubra a tela inteira.
precisa saber é o seguinte
Isso é o que eu venho pensando. Só não sei como fazer isso com um bitmap. E eu acho que talvez exista uma maneira melhor, já que renderizar 2 bgs de uma só vez é muito caro
Green_qaue
2
Acho que vejo do que se tratava a confusão - o Android Canvasfaz as coisas um pouco diferente do HTML <canvas>, o que achei que você quis dizer! Editei minha resposta para explicar como o recorte funciona em geral, com alguns links específicos para Android e código de exemplo.
Anko

Respostas:

20

Demo

GameDev Healing Wave

GameDev Meta : Henshin Main !! : D

O código usa uma canvas clipregião e requestAnimationFramepara máxima qualidade e eficiência. (É melhor viver .)

Eu assumi que você quis dizer HTML canvas! Mesmo que você não tenha feito isso, outros mecanismos de renderização (como o pipeline de renderização 2D do Android, o que você poderia querer dizer) também suportam regiões de clipes aceleradas por hardware . O código provavelmente será semelhante.

Solicitar quadros de animação com requestAnimationFrame(ou outra solução fornecida pela plataforma) resulta em animação de qualidade superior, permitindo que o mecanismo determine o tempo de renderização.

Isso é processado sem problemas em um netbook de baixo alcance e no meu telefone Android.

Explicação

Para tornar isso mais útil em geral, vamos realmente entender o recorte .

Digamos que temos esses dois retângulos:

dois retângulos, um sobreposto ao outro

O recorte funciona igualmente bem em linhas, pontos, imagens ou qualquer outra coisa que você queira renderizar. Estou apenas aderindo a retângulos para simplificar.

Não queremos que o retângulo vermelho seja visível aqui (círculo preto).

dois retângulos, a área de corte desejada do retângulo vermelho em preto

Assim, podemos instruir o renderizador a cortar o retângulo vermelho por esse círculo.

dois retângulos;  o vermelho foi cortado

Em outras palavras, quando o retângulo vermelho é desenhado, ele é desenhado em todos os lugares, exceto onde o círculo preto estaria.

Diferentes renderizadores têm maneiras diferentes de especificar em que região cortar. Em JavaScript, com o HTML <canvas>, fiz essencialmente

// Draw the blue rectangle

context.save(); // Save the current state of the graphics context,
                // so we can go back to it.

// Draw the black circle
context.clip(); // Tell the renderer that was our clip region,
                // since the last `context.save()`.

// Draw the red rectangle.
// It will appear clipped by the black circle.

context.restore(); // Tell the renderer we should restore all
                   // the clipping settings back to what they were
                   // `context.save`d as.

// From here on, nothing is clipped anymore.

Agora, em um Android Canvas, convém fazer uma coisa semelhante, mas o renderizador espera um código ligeiramente diferente:

// Draw the blue rectangle

canvas.save(); // Same idea as above -- just setting a point we can
               // restore to later.

// Now, `canvas.clipPath` expects a `Path` object.
// Let's create one that contains a circle.
Path path = new Path();
path.addCircle(100, 100, 100, Direction.CW); 
canvas.clipPath(path);

// Draw the red rectangle
// It will be clipped by the circle defined in the `path` that we
// used as the `clipPath`.

canvas.restore(); // Aaaand restore the state.

// Things drawn here won't be clipped anymore.

A documentação do Android sobre o assunto pode ser útil. Há boas perguntas como esta no StackOverflow sobre mais coisas que você pode querer experimentar.

Anko
fonte
3

Implementação de trabalho usando o método Ankos:

canvas.drawBitmap(depressingBg, 0, 0, null);
canvas.save();
radius += 400*thread.getDelta(); // expansion speed
Path path = new Path();
// draw around player position
path.addCircle(player.x, player.y, radius, Direction.CW);
canvas.clipPath(path);
canvas.drawBitmap(happyBg, 0, 0, null);
canvas.restore();

Obrigado a Anko por toda a ajuda!

Green_qaue
fonte