Как создать эффект Мировой Волны Исцеления?

14

Я хочу изменить свой темный и удручающий фон на счастливый травяной фон в реальном времени, чтобы счастливый фон отображался в радиусе вокруг игрового персонажа.

ForceField счастья , если вы будете.

Как это можно сделать максимально эффективно при рендеринге на холст в пользовательском представлении?


ОБНОВЛЕНИЕ: Вот как это работает в моей голове:

    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

}

Я использую, canvas.drawArc()чтобы сделать круг, но я определенно что-то упускаю.

Green_qaue
источник
1
технически это называется Мировой Волной Исцеления
чокнутый урод
Я просто использую холст в пользовательском представлении, которое запускается моим собственным игровым циклом со скоростью 60
кадров в секунду
Не могли бы вы сделать сцену дважды? Один раз для исцеленной версии, один раз для мертвой версии, а затем нарисуйте исцеленных над мертвыми в постоянно увеличивающемся круге, пока круг не охватит весь экран.
Вольфганг Скайлер
Это то, о чем я думал. Просто не знаю, как это сделать с помощью растрового изображения. И я думаю, что, может быть, есть лучший способ, так как рендеринг 2 бг за раз очень дорогой
Green_qaue
2
Я думаю, я понимаю, в чем путаница - Android Canvasработает немного иначе, чем HTML <canvas>, который, как я думал, вы имели в виду! Я отредактировал свой ответ, чтобы объяснить, как работает отсечение в целом, с некоторыми ссылками для Android и примером кода.
Анко

Ответы:

20

демонстрация

GameDev Healing Wave

GameDev Meta : Henshin Main !! : D

Код использует canvas clipрегион и requestAnimationFrameдля максимального качества и эффективности. (Лучше жить .)

Я предположил, что вы имели в виду HTML canvas! Даже если вы этого не сделали, другие движки рендеринга (например, 2D-конвейер рендеринга Android, который вы могли бы иметь в виду) также поддерживают области клипа с аппаратным ускорением . Код, скорее всего, будет выглядеть аналогично.

Запрос кадров анимации с помощью requestAnimationFrame(или решения, предоставленного другой платформой) приводит к повышению качества анимации, позволяя движку определять время рендеринга.

Это плавно воспроизводится на нетбуке с низкой дальностью и на моем телефоне Android.

объяснение

Чтобы сделать это более полезным, давайте разберемся с ограничениями .

Допустим, у нас есть эти два прямоугольника:

два прямоугольника, один перекрывающий другой

Обрезка работает так же хорошо на линиях, точках, изображениях или чем-либо еще, что вы можете визуализировать. Я просто придерживаюсь прямоугольников для простоты.

Мы не хотим, чтобы красный прямоугольник был здесь виден (черный круг) вообще.

два прямоугольника, желаемая область среза красного прямоугольника черного цвета

Таким образом, мы можем дать рендереру команду обрезать красный прямоугольник этим кругом.

два прямоугольника;  красный был обрезан

Другими словами, когда рисуется красный прямоугольник, он рисуется везде, кроме того места, где был бы этот черный круг.

Разные рендереры по-разному определяют регион, который нужно обрезать. В JavaScript, с HTML <canvas>, я сделал по существу

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

Теперь в Android Canvasвы захотите сделать то же самое, но средство визуализации ожидает немного другой код:

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

Документация Android по этому вопросу может быть полезной. В StackOverflow есть такие хорошие вопросы, как этот, о том, что вы можете попробовать с ним.

Анко
источник
3

Рабочая реализация с использованием метода Анкос:

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

Спасибо Анко за помощь!

Green_qaue
источник