Comment créer un effet de vague de guérison mondiale?

14

Je veux changer mon arrière-plan sombre et déprimant en un arrière - plan herbeux joyeux , en temps réel, de sorte que l'arrière-plan joyeux soit affiché dans un rayon autour d'un personnage de jeu.

Un champ de force de bonheur , si vous voulez.

Comment cela peut-il être réalisé de manière aussi performante que possible lors du rendu sur un canevas dans une vue personnalisée?


MISE À JOUR: Voici comment cela fonctionne dans ma tête:

    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

}

J'utilise canvas.drawArc()pour faire un cercle, mais il me manque définitivement quelque chose.

Green_qaue
la source
1
techniquement, cela s'appelle World Healing Wave
ratchet freak
J'utilise simplement le canevas sur une vue personnalisée exécutée par ma propre boucle de jeu à 60 images par seconde
Green_qaue
Pourriez-vous rendre la scène deux fois? Une fois pour la version guérie, une fois pour la version morte, puis dessinez le guéri sur les morts dans un cercle toujours croissant jusqu'à ce que le cercle couvre tout l'écran.
Wolfgang Skyler
C'est le genre de ce que je pensais. Je ne sais pas comment y arriver avec un bitmap. Et je pense qu'il y a peut-être une meilleure façon, car rendre 2 bgs à la fois est très coûteux
Green_qaue
2
Je pense que je vois de quoi était faite la confusion - Android Canvasfait les choses un peu différemment du HTML <canvas>, ce que je pensais que vous vouliez dire! J'ai édité ma réponse pour expliquer le fonctionnement de l'écrêtage en général, avec des liens spécifiques à Android et un exemple de code.
Anko

Réponses:

20

Démo

GameDev Healing Wave

GameDev Meta : Henshin Main !!:RÉ

Le code utilise une canvas cliprégion et requestAnimationFramepour une qualité et une efficacité maximales. (C'est mieux vivre .)

Je suppose que vous vouliez dire HTML canvas! Même si vous ne l'avez pas fait, d'autres moteurs de rendu (comme le pipeline de rendu 2D d'Android, que vous auriez peut-être voulu dire) prennent également en charge les régions de clip accélérées par le matériel . Le code sera probablement similaire.

Demande d'images d'animation avec requestAnimationFrame (ou la solution fournie par une autre plate-forme) entraîne une animation de meilleure qualité en laissant le moteur déterminer la synchronisation du rendu.

Cela se fait en douceur sur un netbook bas de gamme et sur mon téléphone Android.

Explication

Pour rendre cela plus généralement utile, comprenons vraiment l' écrêtage .

Disons que nous avons ces deux rectangles:

deux rectangles, l'un se chevauchant

L'écrêtage fonctionne aussi bien sur les lignes, les points, les images ou tout ce que vous souhaitez rendre. Je m'en tiens aux rectangles pour plus de simplicité.

Nous ne voulons pas du tout que le rectangle rouge soit visible ici (cercle noir).

deux rectangles, la zone de découpe souhaitée du rectangle rouge en noir

Nous pouvons donc demander au moteur de rendu de couper le rectangle rouge par ce cercle.

deux rectangles;  le rouge a été coupé

En d'autres termes, lorsque le rectangle rouge est dessiné, il est dessiné partout sauf là où aurait été ce cercle noir.

Les différents rendus ont différentes manières de spécifier la région à découper. En JavaScript, avec le HTML <canvas>, j'ai fait essentiellement

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

Maintenant, dans un Android Canvas, vous voudrez faire la même chose, mais le moteur de rendu attend un code légèrement différent:

// 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 documentation Android à ce sujet pourrait être utile. Il y a de bonnes questions comme celle-ci sur StackOverflow sur plus de choses que vous voudrez peut-être essayer avec.

Anko
la source
3

Implémentation fonctionnelle à l'aide de la méthode 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();

Merci à Anko pour toute son aide!

Green_qaue
la source