Какой самый быстрый способ рисовать на холст HTML 5?

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

Я достаточно стар, что естественным решением этой проблемы является вызов BitBltMasked. О, подождите, нет, у HTML-холста нет ничего такого простого и приятного, как BitBlt. Кажется, что единственный способ сбросить данные пикселя в холст либо с drawImage(), который не имеет полезных режимов рисования, которые игнорируют альфа-канал, или для использования объектов ImageData, которые имеют данные изображения в массиве, к которым каждый. доступ. является. границы. проверено. а также. следовательно. собака. медленно.

ОК, это скорее напыщенная речь, чем вопрос (вещи, подобные W3C, как правило, провоцируют это от меня), но я действительно хочу знать, как быстро нарисовать холст? Мне очень сложно отбросить ощущение, что выполнение 100-ых drawImages() второе, где каждая ничья относится к альфа-каналу, по сути своей греховна и, вероятно, заставит мое приложение работать как осел во многих браузерах. С другой стороны, единственный способ реализовать BitBlt правильно в значительной степени зависит от браузера, используя технику исполнения, подобную hotspot, чтобы заставить ее работать быстро.

Есть ли способ быстро выполнить все возможные реализации, или мне просто нужно забыть о производительности?

Ответ 1

Это действительно интересная проблема, и есть несколько интересных вещей, которые вы можете сделать для ее решения.

Во-первых, вы должны знать, что drawImage может принимать Canvas, а не только изображение. "Суб-холсты" даже не должны находиться в DOM. Это означает, что вы можете сделать несколько композиций на одном холсте, а затем сделать его другим. Это открывает целый мир возможностей оптимизации, особенно в контексте изометрических фрагментов.

Скажем, у вас есть область, в которой 50 плиток длиной до 50 плиток в ширину (я скажу метры ради собственного здравого смысла). Вы можете разделить площадь на куски 10x10 м. Каждый фрагмент представлен собственным холстом. Чтобы нарисовать полную сцену, вы просто нарисуете каждый из объектов Canvas на основной холст, который отображается пользователю. Если только четыре куска (площадь 20x20 м), вы выполнили бы только четыре операции drawImage.

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

  • Если ваши плитки расширяются в третье измерение (то есть: у вас есть ось Z), вы можете нарисовать каждый "слой" куска в свой собственный холст и обновлять только слои, которые необходимо обновить. Например, если каждый кусок содержит десять уровней глубины, у вас будет десять объектов Canvas. Если что-то на слое 6 было обновлено, вам нужно было бы повторно нарисовать слой 6 Canvas (возможно, один drawImage за квадратный метр, который будет равен 100), а затем выполнить одну операцию drawImage для каждого слоя в куске (десять) перетянуть кусок холста. Уменьшение или увеличение размера фрагмента может увеличить или уменьшить производительность в зависимости от количества обновлений, которые вы делаете в среде в вашей игре. Дальнейшая оптимизация может быть выполнена для устранения вызовов drawImage для скрытых фрагментов и т.д.
  • Если у вас нет третьего измерения, вы можете просто выполнить один drawImage за квадратный метр куска. Если обновляется два куска, то только 200 drawImage звонков за галочку (плюс один вызов на кусок, видимый на экране). Если ваша игра включает в себя очень мало обновлений, уменьшение размера блока уменьшит количество вызовов еще больше.
  • Вы можете выполнять обновление кусков в своем игровом цикле. Если вы используете requestAnimationFrame (как и должно быть), вам нужно всего лишь нарисовать объекты Canvas Canvas на экране. Независимо, вы можете выполнять логику игры в цикле setTimeout или тому подобное. Затем каждый фрагмент может обновляться в своем собственном тике между кадрами, не влияя на производительность. Это также можно сделать в веб-работнике, использующем getImageData и putImageData, чтобы отправить обработанный фрагмент обратно в основной поток всякий раз, когда он нуждается в обновлении, хотя при этом эта работа будет плавно предприниматься с большим трудом.

Другой вариант, который у вас есть, - использовать библиотеку, например pixi.js, для рендеринга сцены с помощью WebGL. Даже для 2D он будет увеличивать производительность за счет уменьшения объема работы, которую должен выполнять процессор, и переноса его на GPU. Я настоятельно рекомендую проверить это.

Ответ 2

Я знаю, что GameJS имеет blit-операции, и я, конечно же, предполагаю, что и другие игровые библиотеки html5 (gameQuery, LimeJS и т.д.) и т.д). Я не знаю, обращались ли эти пакеты к конкретным ограничениям на проверку ограничений по границам, которые у вас были, но на практике их образцы, похоже, работают очень быстро на всех платформах.

Вы не должны делать предположений о том, какие ускорения имеют смысл. Например, разработчик GameJS сообщает, что он собирался реализовать грязное отслеживание прямоугольников, но оказалось, что современные браузеры делают это автоматически --- ссылка.

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

У меня нет личных знаний об этом, но вы можете посмотреть в HTML-элемент appmobi "прямой холст", который предположительно является гораздо более быстрой версией обычного холста, ссылка. Я запутался в том, что это работает во всех браузерах или просто в браузере webkit или просто в собственном специальном браузере appMobi.

Опять же, вы не должны делать предположений о том, какие ускорения имеют смысл, не имея глубоких знаний о внутренних процессах веб-браузера. На этой веб-странице о "прямом холсте" упоминается куча вещей, которые замедляют рисование холста: "Переполнять текст, отображать горячие точки, создавать индексы для ссылок ссылок, вкл. И вперед". Альфа-смешивание и проверка границ массива не упоминаются как выдающиеся причины медленности!

Ответ 3

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

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

Но все-таки браузеру приходится перерисовывать каждый пиксель в другом месте на холсте. Это довольно дорого. Было бы неплохо, если бы существовал метод для простого прокрутки пикселей, но там не повезло.

Одна идея, которая приходит на ум, состоит в том, что вы можете реализовать несколько холстов, переведя каждый холст вместо перерисовки пикселей. Это позволит браузеру решить, как перерисовать эти пиксели более естественным образом, по крайней мере, теоретически. Затем вы можете визуализировать вновь видимые плитки на новом или использованном/кэшированном элементе холста. Поместите его в соответствие с последним рендерингом экрана.

Но это только мои две блики... Я имею в виду бит... duh, я имею в виду центы:]