¿Cómo creo un efecto de Onda Curativa Mundial?

14

Quiero cambiar mi fondo oscuro y deprimente a un fondo de hierba feliz , en tiempo real, de modo que el fondo feliz se muestre en un radio alrededor de un personaje del juego.

Un campo de fuerza de la felicidad , por así decirlo .

¿Cómo se puede hacer esto con el mayor rendimiento posible cuando se procesa en un lienzo en una vista personalizada?


ACTUALIZACIÓN: Así es como funciona en mi cabeza:

    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

}

Estoy usando canvas.drawArc()para hacer un círculo, pero definitivamente me falta algo.

Green_qaue
fuente
1
técnicamente se llama World Healing Wave
monstruo de trinquete
Solo uso el lienzo en una vista personalizada ejecutada por mi propio loop de juego a 60 fps
Green_qaue
¿Podrías representar la escena dos veces? Una vez para la versión curada, una vez para la versión muerta, y luego dibuje la curada sobre los muertos en un círculo cada vez mayor hasta que el círculo cubra toda la pantalla.
Wolfgang Skyler
Eso es lo que he estado pensando. Simplemente no sé cómo hacerlo con un mapa de bits. Y creo que quizás haya una mejor manera, ya que renderizar 2 bgs a la vez es muy costoso
Green_qaue
2
Creo que veo de qué se trataba la confusión: Android Canvashace las cosas un poco diferente al HTML <canvas>, ¡lo que pensé que querías decir! Edité mi respuesta para explicar cómo funciona el recorte en general, con algunos enlaces específicos de Android y código de ejemplo.
Anko

Respuestas:

20

Manifestación

GameDev Healing Wave

GameDev Meta : Henshin Main !! :RE

El código usa uncanvas clip región y requestAnimationFramepara obtener la máxima calidad y eficiencia. (Es mejor vivir ).

¡Supuse que querías decir HTML canvas! Incluso si no lo hizo, otros motores de renderizado (como la canalización de renderizado 2D de Android, que podría haber querido decir) también admiten regiones de clip aceleradas por hardware . El código probablemente se verá similar.

Solicitar cuadros de animación con requestAnimationFrame(u otra solución proporcionada por la plataforma) da como resultado una animación de mayor calidad al permitir que el motor determine el tiempo de renderizado.

Esto funciona sin problemas en una netbook de bajo rango y en mi teléfono Android.

Explicación

Para que esto sea más útil en general, comprendamos realmente recorte .

Digamos que tenemos estos dos rectángulos:

dos rectángulos, uno superpuesto al otro

El recorte funciona igual de bien en líneas, puntos, imágenes o cualquier otra cosa que desee renderizar. Solo me quedo con los rectángulos por simplicidad.

No queremos que el rectángulo rojo sea visible aquí (círculo negro) en absoluto.

dos rectángulos, el área de corte deseada del rectángulo rojo en negro

Entonces podemos indicarle al renderizador que recorte el rectángulo rojo por ese círculo.

dos rectángulos;  el rojo ha sido recortado

En otras palabras, cuando se dibuja el rectángulo rojo, se dibuja en todas partes, excepto donde habría estado ese círculo negro.

Los diferentes renderizadores tienen diferentes formas de especificar por qué región recortar. En JavaScript, con el HTML <canvas>, hice esencialmente

// 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.

Ahora, en un Android Canvas, querrás hacer algo similar, pero el procesador espera un código ligeramente 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.

La documentación de Android al respecto puede ser útil. Hay buenas preguntas como esta en StackOverflow sobre más cosas que quizás quieras probar con él.

Anko
fuente
3

Implementación de trabajo utilizando el 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();

¡Gracias a Anko por toda la ayuda!

Green_qaue
fuente