EaselJS и многослойная система холста: настройка производительности, разработка игр, обработка событий

Я инженер, и в настоящее время мы портируем нашу игру Red5 + Flash в приложение Node.js + Easeljs html5.

По сути: это настольная игра, а не рпг. Система слоев означает, что у нас есть несколько холстов, основанных на функциональности. Например, есть статическая фоновая сцена с изображениями. Есть слой только для таймеров.

По умолчанию весь размер холста составляет 1920x1080, при необходимости мы уменьшаем масштаб, чтобы соответствовать разрешению.

В первом подходе использовался кинетический.js, но производительность падала, когда игра становилась сложной. Затем мы переключились на мольберт, потому что уровень абстракции у него ниже, поэтому мы можем решить, как реализовать еще какую-то функцию, а не просто использовать предоставленную робастную.

Я был настроен оптимистично, но теперь он снова начинает показывать медлительность, поэтому я хочу заглянуть глубже внутрь и заняться тонкой настройкой производительности. (Конечно, в Chrome все нормально, проблема в Firefox, но игра должна без проблем работать во всех современных браузерах).

Основной слой (стадия) — карта, содержит ~30 контейнеров, в каждом сложная пользовательская фигура, ~10 изображений. Контейнеры прослушивают события мыши, такие как наведение мыши, выход, щелчок. В настоящее время, например, при наведении курсора я заполняю форму градиентом.

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

Я собрал несколько сложных вопросов:

  1. В описанной ситуации когда можно использовать кеш и как? Я уже пробовал кешировать при инициализации, cacheUpdate после заливки другим цветом или градиентом, затем stage.update(). Без влияния.

  2. Если у меня есть статический, никогда не меняющийся кеш сцены, не имеет смысла на этом слое, верно?

  3. Что именно stage.update() делает? Запуск полной перерисовки слоя? В документе упоминается какой-то интеллектуальный эффект, если его изменить, а затем перерисовать.

  4. Если я хочу заполнить пользовательскую фигуру новым цветом или градиентом, я должен полностью перерисовать ее графику, а не просто использовать метод setFill, верно?

  5. Например, в мольберте нет возможности перерисовать только контейнер, так как же мне умудриться обновить не всю сцену, а только один контейнер, который изменился? Я думал, что смогу добиться этого с помощью кеширования, кешировать все контейнеры и просто обновлять тот, который изменился, но этот способ у меня совсем не работал.

  6. Есть ли смысл кэшировать растровые изображения? Если в контейнере есть пользовательские формы и изображения, что лучше? Кэшируйте контейнер или просто форму в контейнере.

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

  7. Как я могу произвести распространение события клика на перекрывающиеся слои, у которых есть прослушиватели кликов? Я пробовал это с простым DOM, jquery, но объекты событий были далеки от того, что хотели получить слушатели холста.

Вкратце, методы и реквизиты, которые я уже с голым успехом обыграл при попытке настройки: cache(), updateCache(), update(), mouseEnabled, snapToPixel, clear(), autoClear, enableMouseOver, useRAF, setFPS().

Любой ответ, предложение, отправная точка приветствуются.

ОБНОВЛЕНИЕ:

Эта бесплатная настольная игра представляет собой стратегическую игру, так что вы сталкиваетесь с картой мира с примерно 30 территориями. Пользовательские формы — это территории, а контейнер содержит форму территории и значки, которые должны быть над территорией. Это перекрытие контейнеров минимально.

Примером события мыши является эффект наведения. Игрок перемещается по фигуре территории, после чего форма перекрашивается, изменяется размер и т. д., и появляется пузырь с подробной информацией о месте.

В принципе, максимальное количество 1-3 контейнеров может меняться одновременно (кроме фазы инициализации -> все в это время). Не только анимация и перекрашивание медленные в FF, но и задержка слушателя также высока.

Я написал обработчик изменений, поэтому я только stage.update() отмечаю измененные этапы и этапы, на которых выполняется анимация (tweenjs).

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


person Tyborrex    schedule 28.02.2013    source источник
comment
Нам было бы полезно, если бы вы кратко описали свою игру (может быть, ссылку на онлайн-версию, которую мы можем посмотреть). В частности, сколько из 30 контейнеров требуют перерисовки в типичном цикле вашей игры, а также какие объекты в контейнерах требуют перерисовки. Являются ли объекты в контейнерах на самом деле растровыми изображениями или это векторные рисунки или смесь? Как расположены 30 контейнеров на вашей доске 1920x1080. Контейнеры перекрываются так, что перерисовка контейнера A ухудшает контейнер B. Кстати, не кэшируйте растровые изображения — Easel проще выполнять перенос непосредственно из растрового объекта.   -  person markE    schedule 01.03.2013
comment
Прежде всего, спасибо за помощь. Сайт не готов, поэтому игра разрабатывается локально, но я отредактирую вопрос с подробной информацией о контейнере. Изображения являются растровыми.   -  person Tyborrex    schedule 01.03.2013


Ответы (2)


Что касается кеширования: есть некоторые странные проблемы с кешированием, каким-то образом производительность может упасть при определенных размерах прямоугольника кеширования: -certain-size-shapes">CreateJS / EaselJS Strange Performance с фигурами определенного размера

(2) В зависимости от того, как часто вы вызываете stage.update();

(3)

Каждый раз, когда вызывается метод обновления, этап будет отмечать всех потомков, предоставляющих метод галочки (например, BitmapAnimation), и отображать весь свой список отображения на холсте. Любые параметры, переданные для обновления, будут переданы любым обработчикам onTick.

=> Afaik, он перерисовывает все, если не кешируется

(4) Да.

(5) Нет. (Я не знаю ни одного)

(6) Если содержимое контейнера не меняется часто, я бы кэшировал весь контейнер, иначе контейнер будет восстанавливаться каждый кадр.

У меня есть вопрос: почему вы используете несколько холстов? Сколько вы используете? Я мог предположить, что использование нескольких холстов может замедлить игру.

Сколько всего спрайтов вы используете?

person olsn    schedule 28.02.2013
comment
Спасибо Вам за Ваш вклад! Количество слоев 6-8. Я начал использовать несколько холстов, потому что думал, что stage.update() будет тяжелым, поэтому при разработке я разделил элементы по функциональности, например, слою таймера не нужен прослушиватель mosue, поэтому я могу отключить его, но он должен обновляться каждую секунду. Спрайтов нет, анимация управляется tweenjs. Это просто эффекты манипулирования размерами, альфа-каналом и положением. Не все, но один из контейнеров постоянно меняется в зависимости от пользователя. - person Tyborrex; 01.03.2013
comment
По вашим словам, я должен кешировать контейнеры и просто перерисовывать затронутый, снова кешировать. Я также пробовал эту возможность, но безуспешно, однако я мог пропустить sthg, поэтому я попробую еще раз. - person Tyborrex; 01.03.2013
comment
Я столкнулся с аналогичным падением производительности в Firefox, в то время как в любом браузере webkit (Chrome, Safari, iOS...) все очень гладко даже на одном холсте, но все же стоит попробовать протестировать все холсты по отдельности и полностью удалить другие полотна. - person olsn; 01.03.2013
comment
Может быть, вы можете удалить некоторые холсты и вместо этого использовать DIV? Я мог представить, что таймер, например, может иметь лучшую производительность при рендеринге текста в div с фоновым изображением или около того, чем при использовании холста. - person olsn; 01.03.2013

2: если ваш слой или этап не меняется, не вызывайте stage.update() для этого слоя (чтобы он не перерисовывался, это дает мне гораздо более низкий процессор!) Например, оставьте глобальный «stagechanged» переменная и установите для нее значение true, когда что-то изменилось:

createjs.Ticker.addEventListener("tick",
    function() {
        if (stagechanged)
        {
            stagechanged = false;
            stage.update();
        }
    });

(или вы уже используете это, как указано в вашем «обновлении»?)

4: Я нашел способ обновить, например, цвет заливки :)

contaier1.shape1.graphics._fillInstructions[0].params[1] = '#FFFFFF';

(используйте отладчик Chrome, чтобы просмотреть массив _fillInstructions, чтобы увидеть, какая позиция массива содержит ваш цвет)

5: Я нашел способ просто покрасить один контейнер :)

        //manual draw 1 component (!)
        var a = stage.canvas.getContext("2d");
        a.save();
        container1.updateContext(a);  //set position(x,y) on context
        container1.draw(a);
        a.restore();
person André    schedule 24.09.2013