Своя игра с JavaScript и Canvas

imageНе так давно мне стало любопытно, насколько сносно современные браузеры поддерживают HTML5 и я не нашел лучшего
способа, чем написать простейший 2D платформер. Помимо удовольствия от разработки игрушки и улучшения навыков в использовании JavaScript, в ходе развлечения кропотливой работы был накоплен определенный опыт и эмпирическим путем были найдены основные грабли, на многие из которых мне пришлось наступить. В этой статье я попробую кратко и с примерами резюмировать то, что вынес для себя из проделанной работы. Желающих создать свое высокопроизводительное JavaScript приложение, эффективно работающее с графикой, прошу под кат.

Общие замечания


Код на JavaScript очень критичен к ресурсам платформы. Несмотря, что почти все современные движки перестали тупо интерпретировать JS код, скорость его выполнения по-прежнему очень сильно уступает скорости «родного» кода. Между тем, даже простейшая игра — это много кода, который должен успевать выполниться между отрисовками двух соседних кадров анимации. Кроме того, JS — язык весьма специфический и написание объемного кода на нем сопряжено с рядом трудностей. Все вместе может стать причиной того, что приложение на JS перестанет удовлетворять ожиданиям и быстро принесет разочарование. Попробую немного систематизировать выводы, к которым я пришел путем экспериментов.

1. Совместимость
Если мы решили использовать HTML5 и Canvas в частности, то пусть нас больше не беспокоят вопросы совместимости со старыми браузерами – под ними все равно ничего не заработает. Таким образом, можно смело использовать основные нововведения ECMAScript 5. С другой стороны, не стоит обижать презрением пользователей старого доброго ПО, наподобие IE6. Желательно их уведомить, о причинах, почему они видят фигу серый квадрат, вместо нашей замечательной анимации. Сделать это элементарно, достаточно диагностировать поддержку Canvas и используемых языковых конструкций

<canvas id="gameArea">
  <span style="color:red">Your browser doesn't support HTML5 Canvas.</span>
</canvas>

<script type="text/javascript">
(function(){
if(typeof ({}.__defineGetter__) != "function" && typeof (Object.defineProperty) != "function")
  alert("Your browser doesn't support latest JavaScript version.");})()
</script>

Все бы хорошо, да вот беда – проблемы кроссбраузерной совместимости до конца не исчерпаны. Среди современных браузеров нет единого мнения насчет названий стандартных функций. Выход – либо вообще отказаться от их использования, либо делать дорогостоящие адаптеры. Например, я не смог отказать себе в использовании описателей свойств и это дало свои негативные последствия. О том, как их использовать кроссбраузерно, хорошо описано здесь, и здесь. А вот как их заставить работать быстро — осталось загадкой.

2. Оптимизацию кода легко сломать
Не так давно на Хабре проскакивала очень полезная статья про движок V8 для Chromium. Самое главное, что я сумел почерпнуть для себя – это скрытые классы и оптимизация кода для работы с ними. Действительно, JS зачастую провоцирует менять структуру объекта после его конструирования. Не стоит этого делать, если цель – создать быстрый и легко поддерживаемый код. Как только я это осознал, работа над игрой пошла веселее, а код стал чище и быстрее.

function myObject() { };
var mo = new myObject();
mo.id = 12; //лучше так не делать
//Аккуратнее надо быть и с переменными.
var v;
v = 12; //плохо, лучше var v = 12;
v = “12”; //так не надо, для нового типа лучше использовать новую переменную
var v = 15; //я искренне верю, что так никто не поступает

Так же нужно стремиться сокращать область видимости переменной до минимума – это увеличивает вероятность оптимизации кода.

3. В JS нет классов, наследования и прочего класс-ориентированного программирования.
Не следует напрягать движок реализацией классов при помощи прототипирования – выгода сомнительна, а код замедляется в разы (Opera)! Сложное прототипное наследование и честно организованный перенос базового функционала к наследникам сбивают и без того не самую лучшую оптимизацию.

4. Платим за то, что используем
По ходу разработки игры или любого другого ресурсоемкого приложения, неизбежно приходится кэшировать «дорогие» ресурсы, например, предрасчитанные анимации или динамически загружаемые скрипты. У любого ресурса есть время жизни, после которого он оказывается не нужен. И тут важно правильно от него избавиться.

var resCache = { res1 : new getCostlyResource() }//тут может быть выделено много памяти
resCache.res1 = null; 

Скорее всего, память не будет освобождена сборщиком мусора (GC). Она будет собрана в произвольный момент времени, и он окажется самым неподходящим, потому что GC постарается удалить весь мусор, который накопится к этому моменту. Вот так уже лучше:

delete resCache.res1;
resCache.res1 = null; //полезно для отладки

На первый взгляд – ничего сложного, но в более сложных случаях появляются нюансы, и поведение delete не всегда очевидно.

5. Замыкания и свойства – враги быстродействия
Замыкания – базовая возможность функционального языка. Кажется, что именно это место должно быть максимально оптимизировано движком JS. Но, практика показывает, что это не так. Вот небольшой тест, который сравнивает быстродействие различных способов доступа к данным объекта (код теста).
Результат для разных браузеров и платформ (мс):
Windows XP (x86), Core 2 Duo, 3 GHz Opera 12 FireFox 17 Chrome 23
Нет замыканий, прямой доступ к полям объекта 9 6 17
Нет замыканий, доступ к данным через методы 16 11 28
Замыкания, доступ через методы 34 12 23
Замыкания, доступ через свойства 387 899 489
Windows 7 (x64), Core i3-2100, 3.1 GHz Opera 12 Chrome 23 IE 10
Нет замыканий, прямой доступ к полям объекта 7 5 15
Нет замыканий, доступ к данным через методы 13 11 13
Замыкания, доступ через методы 27 9 14
Замыкания, доступ через свойства 222 315 99
Как ни удивительно, Opera смотрится в тесте лучше других. К сожалению, общий вывод неутешителен, замыкания оптимизированы только в Chrome, а доступ через свойства – это большая роскошь, способная на порядок ухудшить быстродействие приложения.

Замечания о графическом движке


Программирование графики на JavaScript — отдельная большая тема, которую могу затронуть позже, если будет спрос. Здесь я постарался выделить несколько простых приемов, которые было легко использовать и они дали неплохой результат.

1. Покадровая анимация.
Есть два подхода к созданию анимации: событийный и покадровый. Первый пригоден в основном для простых задач, наподобие подсветки кнопки при наведении мышки и может выполняться в соответствующих обработчиках. Второй годится для выполнения сложных анимационных задач, которые должны «жить своей жизнью», вне зависимости от действий пользователя, например, динамические игры.
При создании игры проще всего (и дешевле в плане вычислительных ресурсов) рассчитывать игровой процесс, полагаясь на стабильность частоты кадров (frame). Можно попытаться использовать запрос кадра анимации у тех браузеров, что его поддерживают. Сделать это не так просто, потому что этот метод стал стандартом де-факто и по какой-то причине не попал в ECMAScript 5.

var raf = window.requestAnimationFrame || window.msRequestAnimationFrame ||      window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame;
//И использовать его можно примерно так:
var myRedrawFunc = function () { /*тут мог бы быть ваш код*/ raf(myRedrawFunc) }
raf(myRedrawFunc);

Выгода RequestAnimationFrame в основном состоит в том, что при ненагруженной анимации (когда сам процесс отрисовки занимает меньше половины времени кадра), он позволяет добиться большей плавности анимации и сокращает потребление ресурсов на мобильных платформах. Но на деле это может оказаться не так. К неудобствам от его использования можно отнести фиксированную частоту кадров (60 fps) и отсутствие компенсации продолжительности следующего кадра, если задержалась отрисовка предыдущего.
Однако, что делать, если raf === null? Так может произойти, если ваше приложение попало в руки Opera, которая традиционно идет своим путем. Тогда нам поможет старый добрый setTimeout. В итоге код будет выглядеть примерно так:

var fps = 60;
var frameTimeCorrection = 0;
var lastFrameTime = new Date();
var to = 1000/fps;
var myRedrawFunc = function()
{
  /* Код анимации и физического движка */
  var now_time = new Date();
  frameTimeCorrection += now_time - lastFrameTime - to;
  if(frameTimeCorrection >= to)
    frameTimeCorrection = to - 1; //ограничиваем большую коррекцию
  lastFrameTime = now_time;
 
  if(raf)
    raf(redrawFunc);
  else
    setTimeout(myRedrawFunc, to - frameTimeCorrection);
};
myRedrawFunc ();

Недостаток у такого подхода очевиден – если расчёт кадров будет подтормаживать больше, чем можно скорректировать – игровой процесс перестанет рассчитываться в реальном времени. Но можно пойти на хитрость. Как правило, причина тормозов — отрисовка элементов очередного кадра, т.к. для движка браузера это накладная операция. Поэтому можно написать код так, что в случае, когда коррекция времени не справляется (срабатывает условие if(frameTimeCorrection >= to)), в следующем кадре можно производить только расчет игрового мира без его перерисовки. Появится т.н. «лаг» который в игре выглядит менее раздражающе, чем slow motion.

2. Рисуем только то, что видно на холсте.
Наиболее простой и проверенный годами способ анимации – спрайты. Особенность этого способа заключается в том, что для создания иллюзии движения, спрайты перемещаются в игровом пространстве, путем изменения координат их отрисовки. Как правило, игровое пространство значительно превышает по размеру область отрисовки кадра и если игровое пространство большое, и спрайтов много их отрисовка станет занимать ощутимое время. Методы контекста канвы являются элементами DOM, а обращение к ним весьма накладно. Одна из оптимизаций заключается в том, чтобы рисовать только то, что видно в кадре. В приведенном тесте, вначале создаются и выводятся на канву 9000 «умных» спрайтов, которые при перерисовке следят за своими координатами, и не обращаются к методам канвы, если они вне кадра. Затем создаются 9000 «глупых» спрайтов, которые не следят за областью видимости (код теста).
Результаты теста (fps):
Windows XP (x86), Core 2 Duo, 3 GHz Opera 12 FireFox 17 Chrome 23
«Умные» спрайты 47 35 25
«Глупые» спрайты 15 14 12
Windows 7 (x64), Core i3-2100, 3.1 GHz Opera 12 Chrome 23 IE 10
«Умные» спрайты 56 32 61
«Глупые» спрайты 19 15 51
Разница ощутима (а Хромой снова подкачал – миф развенчан).

3. Кэшируем растеризацию
Растеризация средствами графического движка – довольно ресурсоемкое занятие. Поэтому важной оптимизацией является кэширование результатов растеризации в памяти. Самый простой способ – создать отдельную канву и в ней растеризовать векторную графику. Запомнить указатель на нее в кэше и в основной области отрисовки выводить запомненный результат. Для иллюстрации возьмем растеризацию 1000 текстовых спрайтов. В тесте производительности , попеременно с интервалом 20 сек отрисовываются 800 текстовых спрайтов. Вначале с кэшированием результата растеризации, затем без кэширования (код теста).
Результаты теста (fps):
Windows XP (x86), Core 2 Duo, 3 GHz Opera 12 FireFox 17 Chrome 23
Кэширование растеризации 23 32 60
Без кэширования 5 12 47
Windows 7 (x64), Core i3-2100, 3.1 GHz Opera 12 Chrome 23 IE 10
Кэширование растеризации 33 61 61
Без кэширования 5 56 23
При таком подходе важно соблюдать баланс между памятью, частотой сброса кэша и быстродействием растеризации. Так, если текст меняется динамически и довольно интенсивно (скажем, раз в 10 кадров анимации), то его кэширование может только ухудшить общее быстродействие, т.к. сама операция кэширования будет вносить больше накладных расходов, чем растеризация.

4. Динамическая загрузка ресурсов
Если анимация строится на спрайтах из битовых карт (bitmap), то прежде, чем их можно будет рисовать на холсте, следует загрузить эти самые карты в кэш изображений браузера. Для этого достаточно создать элемент Image и в качестве источника передать url ресурса картинки. Сложность состоит в том, чтобы дождаться момента, когда браузер загрузит картинку в свой кэш. Для этого можно использовать событие onload, в котором, увеличивать счетчик уже загруженных картинок. Как только значение это счетчика совпадет с числом картинок, добавленных к загрузке, ресурс станет персистентным, и мы можем выполнять основной игровой код.

function Cache()
{
  var _imgs = {};
  var _addedImageCount = 0;
  var _loadedImgsCount = 0;
  this.addSpriteSource = function(src)
  {
    var img = new Image();
    img.onload = function()
    {
      _loadedImgsCount++;
    };
    img.src = src;
    _imgs[src] = img;
    _addedImageCount++;
  }
  this.getLoadedImagePc()
  {
    return _loadedImgsCount * 100 / _addedImageCount;
  }
  this.getImage = function(src)
  {
    return _imgs[src];
  }
}
//добавляем картинки
Cache.addSpriteSource("img1.jpg");
Cache.addSpriteSource("img2.jpg");
//ждем, пока они загрузятся
function waitImagesLoading()
{
  var pc = Cache. getLoadedImagePc();
  if(pc < 100)
    setTimeout(waitImagesLoading, 200);
  /* при необходимости тут можно анимировать процент загрузки картинок*/
}
waitImagesLoading();

В своей игрушке я решил каждый уровень описывать отдельным скриптовым файлом. Понятно, что статическая загрузка таких скриптов вредна, т.к. в каждый момент времени нужен только один из них. Решению задачи помог тот же подход, что и в случае загрузки изображений.
Есть только один нюанс — у объекта Script нет событий, но это и не беда, т.к. в код динамически загружаемых скриптов можно вставить глобальную функцию регистрации скрипта в кэше. Дальше поступаем аналогично загрузке картинок — асинхронно ждем, пока скрипт зарегистрирует описанные в нем типы, а затем создаем нужные нам экземпляры зарегистрированных типов.
Для того чтобы пользователь не скучал — можно показать процент загрузки всех необходимых ресурсов.

5. Дробные координаты
Рисуя на канве растровые или векторные примитивы, можно указывать дробные координаты и размеры. В результате графический движок браузера вынужден сглаживать выводимое на экран изображение. Если упрощать, то это происходит, потому что виртуальный пиксель растеризованного изображения не будет совпадать с пикселем на экране. Как результат — включатся алгоритмы сглаживания изображения (smoothing), что может заметно сказаться на производительности.
В тесте производительности , попеременно с интервалом 20 сек спрайты с целыми и с дробными координатами (код теста).
Результаты теста (fps):
Windows XP (x86), Core 2 Duo, 3 GHz Opera 12 FireFox 17 Chrome 23
Целые координаты и размеры 57 60 60
Дробные координаты и размеры 50 52 60
Windows 7 (x64), Core i3-2100, 3.1 GHz Opera 12 Chrome 23 IE 10
Целые координаты и размеры 60 61 61
Дробные координаты и размеры 60 61 61
Тут следует пояснить, что в случае 64-битной платформы положение спасает более хороший графический адаптер, который очевидно берет на себя задачу сглаживания и антиалиасинга. В случае относительно быстро перемещаемых спрайтов (десятки пикселов за секунду) можно обходиться целыми координатами и размерами. Однако сами координаты и размеры нужно считать в дробных величинах, чтобы не терять точность при плавном изменении параметров. Вполне оправдывает себя такой подход, когда все значения координат и размеров рассчитываются и хранятся без округлений, а перед непосредственным выводом на канву, они округляются с помощью Math.floor.

Вместо заключения.


Современное развитие JavaScript, HTML5 и поддержка этих возможностей различными браузерами уже вполне позволяют писать производительные интерактивные графические приложения, которые в большинстве задач дадут фору традиционному flash программированию.
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 102

    +23
    Удивительно, но большинство содержательных технических статей приходит из песочницы)
      +3
      Где игру можно посмотреть? =)
        0
        Это оно нет?
          +1
          • UFO just landed and posted this here
            • UFO just landed and posted this here
                +6
                Потому что автор даже ссылку на игру в посте не дал, потому что не в игре суть. Вы блог перепутали.
                • UFO just landed and posted this here
                    0
                    Конкретно про фору flash вам человек привел цифры.

                    И да, игра примитивная, некрасивая и скучная. Но она бегает очень резво и об это как раз и идет речь.
                    • UFO just landed and posted this here
                        0
                        Если вы цепляетесь к этой фразе, то, возможно, она действительно плохо сформулирована и ее следует поправить.

                        В выводе речь о том, что уже сейчас можно не бояться начинать использовать HTML5 вместо флэш, так как он может выдавать достойные результаты — это и пытается донести автор. Если у вас есть претензии к этому тезису, вам нужно было с самого начала их формулировать и писать в развернутой форме, а не писать «во говно, автор лох». Естественно вы с таким подходом огребли минусов в карму, не удивляйтесь.
                        • UFO just landed and posted this here
                            +1
                            вот вам ссылка, поглядите на игру на html5. Кроме того, фреймворк, на котором сделана эта игра и ее соседи — в опернсорсе. На подходе использование 3D в мобильных браузерах, откуда флеш почему-то ушел.
                            И да, те, кого не интересует кармодрочерство не говорят о нем вовсе.
                            • UFO just landed and posted this here
                                –2
                                Окей, давайте я вам немного помогу найти нужное — вот оно
                                • UFO just landed and posted this here
                                    0
                                    Там есть двойной рендер, это во-первых, во-вторых — процент оперы на мировом рынке довольно мал (хотя есть еще любимый ослик), в-третьих — это только один пример. Вот вам еще один движок, который вполне можно использовать в коммерческих играх (поглядите на механику и техническую реализацию топовых игр ВК и ФБ например)
                                    • UFO just landed and posted this here
                                        0
                                        Конечно они на флеше, я не об этом говорю. Я говорю о том, что механика игр вполне походит под реализацию их на HTML5 и конкретно на этом движке. То есть, технически, ничего сложного в отрисовке изометрии на канвасе нет, а значит уже можно зарабатывать на этой технологии. Проблема в другом — на флеше можно и обезьяну научить программировать, так хорошо там сформирована иерархия классов, а вот толковых людей пишущих на JS — весьма мало, это либо энузиасты, как автор статьи, либо уходящие в дебри веб-приложений, ООП и node.js.
                                          +1
                                          Может звук и был через Флеш раньше, но сейчас я проверил (Флеш у меня только по клику включается), всё ок, звук идёт через ХТМЛ5.
                                          0
                                          Про процент оперы Вы это зря, процент достаточный чтобы решать разрабатывать что-то на какой-либо не поддерживаемой ей технологии или не разрабаты.

                                          Чёрт, не туда комент ушёл.( к посту там где процент использования оперы оговаривался)
                                          +1
                                          А «Опера» знает, что она не поддерживает ВебГЛ?

                                          • UFO just landed and posted this here
                                    +5
                                    > Меня не интересует кармодрочество. Ваши друзья и вы можете засыпать меня минусами, мне всё равно.

                                    Вы спросили, почему вас минусуют, я вам ответил. Извините, если что не так.

                                    > фейсбук отказывается от html5, большинство авторитетных разработчиков наконец-то начинают говорить, что html5 отвратительно работает на мобильных платформах. А количество успешных игр можно пересчитать по пальцам. Какие аргументы имеются на этот счет?

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

                                    Так вот, единый открытый стандарт под Web — это очень круто и это должно быть. И я не вижу ничего плохого в том, что автор, приводя конкретную аргументацию, пытается популяризировать этот стандарт. И если вы видели в этой аргументации слабые стороны, вы бы могли бы написать об этом, и сделать хабр лучше, светлее и чище. Но вы вместо этого полезли бросаться говном, а потом вздыхать, что хабр уже не тот.
                                    • UFO just landed and posted this here
                                        +1
                                        Я не оспаривал вашу точку зрения, я лишь привел вас к тому, что вы наконец начали приводить объективные аргументы, а не клеймить автора непонятно за что.

                                        А по теме я сказал одно — единый стандарт это хорошо, другого стандарта кроме HTML5 на арене не виднеется, даже если технология пока немного сырая (хотя, судя по комментариям, есть варианты), популяризировать ее — это правильное и хорошее дело. Если вы считаете это глупым, то ок, удачи.

                                        И если бы вы не задали вопрос «За что минусуете», я бы вам вообще не отвечал.
                                          +3
                                          > другие незаслуженно получают минусы.

                                          Некармодрочер, ок.
                                          • UFO just landed and posted this here
                                              +1
                                              Конкретику вам предоставил автор. Если вас не устраивают «результаты, которые были 8-9 лет назад», вас никто не заставляет этим пользоваться.

                                              И как только вы перестали бычить и стали подробно объяснять, почему это плохо и неправильно — к вам сразу потянулись люди. А агрессию в комментариях никто не любит.
                                        0
                                        Судя по этой статье, можно сделать вывод, что ребята с фейсбука не до конца разобрались с технологией.
                                      0
                                      Да, цифры не касаются flash, но и фору можно дать не только в производительности. Попробуйте получить 60 fps во flash приложении на Android-ном устройстве и все станет понятно (кстати, Вы уже удалили его со своего телефона?). я не собирался как-то обидеть флэшистов, просто на мой взгляд, JS сейчас, с появлением Canvas, вполне себе конкурент flash-у.
                                      • UFO just landed and posted this here
                                          +1
                                          То, о чем вы говорите — AIR. И кстати, он не так давно стал пригоден к употреблению, только с 3 версии. Не имею ничего против, сам пишу на нем код. Но HTML5 это все таки в браузере.
                                          • UFO just landed and posted this here
                                              +1
                                              Согласен, толку сейчас от HTML5 на мобилках практически никакого, в контексте создания игр. Если остальные браузеры подтянутся за оперой и мы сможем ипользоватьб WebGL, то тогда уже можно будет о чем-то говорить. С другой стороны, на мой взгляд, более перспективным будет поддержка открытых стандартов и инструментов.
                                                0
                                                Извините, был не прав. Буквально на выходных занялся вопросом изучения HTML5 на мобилках. Существуют программные оболочки, в которые вы можете запаковать свою HTML5 игру без изменения кода и оболочка будет рендерить вашу игру на мобильном устройстве используя аппаратное ускорение. Как минимум 2 таких движка я уже нашел — Cocoonjs и appMobi, возможно есть еще.
                                                А вот пример игры, использующая cocoonjs и которая на моей старенькой первой галактике отлично работает
                                                Biolab Disaster
                                          0
                                          Исходя из моего опыта, на eee pc 901 потенциальный фпс с таким количеством рендеринга должеен быть порядка 30000 во флеше. Конечно, такой фпс сделать никто не даст, а вот увеличить количество рендеринга в 500 раз можно.
                                –1
                                ФЗ: ФФ 17, Убунта — кнопки в самом начале просто тупо не жмутся…
                                +1
                                Ну, собственно, там тот же адрес, что и у тестов, только без # (который просто позволяет вводить чит-коды, без заморочек с консольным режимом, хоть и он тоже есть). Только на данном этапе развития, называть ее игрой, откровенно говоря, я бы не рискнул пока. Это скорее proof of concept движка игры + некоторые идеи, воплощенные вчерне (так сказать — задел на будущее).
                              • UFO just landed and posted this here
                                  +14
                                  Вам не приходило в голову, что автор просто изучает технологию, а не пытается сделать что-то великое?
                                  • UFO just landed and posted this here
                                      +13
                                      Извините его, что он потратил пару дней своей жизни, чтобы рассказать нам что-то интересное и новое, и вам это показалось скучным и неправильным.

                                      Простите его.

                                      Он не нарочно.
                                      • UFO just landed and posted this here
                                          +14
                                          Я его бабушка.
                                          • UFO just landed and posted this here
                                              +8
                                              Как вы пишите — такой и троллинг, извините. Я не смог придумать более достойного ответа.

                                              И если на статью автора, который явно потратил на нее определенные усилия, пишут «говно», не объясняя толком человеку причин, то хабр изменился, да.
                                              • UFO just landed and posted this here
                                                  +5
                                                  Полностью потдержу!
                                                  Все время следил за HTML5, и доси не понимаю всего бреда вокруг него, как и с шумихой вокруг Ajax в свое время, притом что DHTML изначально был, хрен знате сколько лет и прекрасно работал.
                                                  Потдавшись шумихе… таки решил попробовать переписать свою игру с Flash на HTML5… в итоге убил тучу времени, но понял что это тупик.!!! Причем тупик по всем фронтам.
                                                  1. Код полностью открытый! Нафиг оно мне такое нужно? Я сам взломал много таких игр и быстро пропал интерес… код раскрыт и делай что хочешь.
                                                  2. Как мою игру отдать всем в онлайн, на томже Facebook если оргомная аудитория пользователей прекрасно сидит на ХП с IE8 в котором толком ничего не заработает. даже не все framework стабильно работают под IE9.
                                                  3. Провел пару тестов на плантшетах с АРМ 6/7 и был в ужосе.

                                                  т.е. Чтобы создать свою, допустим соц.игру на HTML5, мне придется убить просто огромное кол-во времени, собирая все покусочкам, оптимизируя безконечно. И писать тучи вариантов игры, чтобы не потерять часть аудитории?

                                                  И при всем при этом, вижу почти каждый день, как минусуют любого кто хоть както заступится за Flash. Похоже на хабре это слово стало синонимом с Microsoft, и несет за собой падение кармы упоминувшего в суе. И это IT-шники? :(
                                                    0
                                                    Facebook перестал принимать игры на html?
                                                      0
                                                      вы о чем? как ваш вопрос относится к выше сказаному?
                                                        0
                                                        Тем, что не обязательно использовать Flash, чтобы делать игры для Facebook.
                                                      +5
                                                      Вы так говорите, как будто игры на Флеше не ломаются или не декомпилируются.
                                                        –1
                                                        Любой exe тоже можно вскрыть, но это могут еденицы и код программы еще не дает шанса все сломать. Также и Флеш игры, получив ресурсы и часть скриптов Флеша еще не значит что вы тутже вмешаетесь в процесс игры. А вот с HTML5 можно прямо в браузере толи IE толи Хром, следить за соурсом и вмешиваться в процесс.
                                                        А тем более это важно для Энтерпрайз приложений. Я планировал перейти с Flex на HTML5, из-за шунихи вокруг смерти Флеша и Флекса… но я не рискну написать энтерпрайз приложение на открытом коде, это бред полный.
                                                        Да и не каждый Флеш можно декомпилировать. У Адоба давно есть методы защиты Флеша от декомпиляции той о которой вы говорите.
                                                          0
                                                          Не знаю как на других платформах, а на Маке есть iHaxGamez, ломает что угодно на чём угодно. Вводишь цифру жизней, помираешь, вводишь на цифру меньше, ищешь ещё раз. «Морозишь» это значение, всё.
                                                            0
                                                            это больше говорит о ламерстве девелоперов, которые не защищают свой продукт от таких вот вмешательств. Продуманная онлайн игра, обычно закрыта от таких вмешательств и н еобщается с сервером в октрытом виде. Это аналогично sql иньеккциям в веб продуктах, если девелопер безрукий, то это незначит что PHP убогий и в него можно вмишаться.
                                                            Мы с вами говорим совсем о разных вещах.
                                                              0
                                                              Наверное о разных. Но вы знаете, я как-то пытался смотреть код Gmail… Это мне ничего не дало.
                                                      +1
                                                      Пусть каждый занимается своим делом. Для создания коммерчески успешной игры необходима работа дизайнеров разного толка, менеджеров, рекламистов и так далее.

                                                      И конечно, программистов. И автор, в качестве программиста, показал мне, как непрограммисту, что технология работает и может быть использована для создания целостных продуктов. Другим же программистам указал на некоторые подводные камни разработки.
                                        +1
                                        Если по существу, то я программист, а не гейм-дизайнер, не игровой сценарист, и ни не Кармак. Впрочем я и не претендовал. Тем не менее, мне кажется, что все идет к тому, что браузерные приложения очень даже скоро станут конкурентоспособными, а на мобильных девайсах будут доминировать. И мне показалось интересным пощупать возможности современного JS и HTML5. Если Вас смущает тег Game Development, то это просто следствие выбора темы для экспериментов (я вроде ее постарался обосновать вначале).
                                          –3
                                          вставив фразу «даст фору флешу»… вы сделали огромную ошибку, и не потому что ибидели флеш, а потому что совершенно незнаете ничего о его достижениях. Видимо вы потдались общей теме Хабры, что Флеш уже похоронили…
                                          Флеш как раз все дальше и дальше отрывается от HTML5 и шансов что HTML5 когдато догонит Флеш, практически никаких. Разве что если Adobe таки решиться его похоронить.
                                          Конкретно на сегодня:
                                          — Флеш уже давно не рендерит весь слой в 2D а только ту часть, в которой происходит изминение что дает максимальный ФПС. Тотже HTML5 все еще делает по старому, каждый фрейм идет рендеринг, и еще не скоро дойдет до этапа аналогичному во Флеш.
                                          — Флеш уже прошел все пути в 2D, и сейчас просто ищет оставшиеся пути его ускорения и оптимизации… больше там развивать нечего для них
                                          — развитие в 3D у Флеша уже дальше чем HTML5 в 2D

                                          По этому «фора Флешу»… вы или неправельно выразились, так нужно было сразу исправить. Или вы далеки от понимания, но решили чисто не забыть кинуть камень в сторону Флеша как это любят делать на Хабре и заработать себе лишнюю карму.
                                            0
                                            Oh Really? Вы, если следите за флешом и НЕ следите за Canvas — изучите матчасть для начала, дабы не «ибидеть» всех остальных.

                                            1. Canvas может перерисовывать как часть себя, так и себя всю полностью. Все зависит от радиуса кривизны рук программиста, а не технологии.
                                            2. То же самое можно сказать и о Canvas'e! Как ускорить «setPixelColor()» я, честно говоря, сомневаюсь, что кто-то знает.
                                            3. Canvas — всего-лишь инструмент, а не сборка технологий с IDE в упряжке. Не сравнивайте токарный станок Порше с автомобилем Порше.

                                            В общем, RTFM/
                                              0
                                              Вижу что безсмыслено чтото доказывать тем кто решил для себя что Флеш зло и ему пора исчезнуть.
                                              Отвечу просто — нету нИ одной задачи на канвасе которую флеш не сможет выполнить да еще с лучшими показателями. В тоже самое время — колосальное кол-во задачь которые HTML5 просто не в состоянии осилить, даже при большом желании.

                                              После долго мучение с портированием Флеш игры в HTML5 я для себя понял одно! Мне проще и быстрее в сотни раз, переписать 2D игру в 3D. И это было проверено на практике. Имея такие фреймворки как Away3d, Alternativa3D, Flare3D и др., уже вчера можно было в очень короткие сроки, реализовать свои идеи.

                                              Потому HTML5 завтра все еще будет предлагать сырую 2D платформу, а Флеш уже вчера предлагал полноценную 3D платформу и не только.
                                                +1
                                                Ни одной? Вот так уж действительно?

                                                Вот вам первая задачка — загрузить флеш-игру при установленном в Chrome плагине FlashBlock.
                                                Вторая вторая задачка — не съедать 120% CPU при размере отрисовки 300х400px на MacOS.

                                                Да, и еще. Раз вы такой большой фанат 3D — в уме пересчитать матрицу поворота сможете? Знаете, почему она вообще нужна? Если нет и знания будут добываться в википедии — скажите, какой смысл доказывать о том, что флеш предлагает 3D «искаропки»? Вы же не знаете, о чем говорите. Тем более в Canvas'e так же давно есть 3D — github.com/mrdoob/three.js/
                                                0
                                                Дело не в RTFM и заявленных фичах, а в реализации конкретных задач. В реальных задачах Канвас очень слаб. Безусловно, это временное явление и с годами допилят производительность и появятся сотни удобных фреймворков. Но на данный момент времени, если вам требуется хоть сколько-нибудь сложная анимация — никаких альтернатив флешу нет.
                                                Мы делали анимацию звездных систем, планеты вращающиеся вокруг звезды с некоторыми эффектами подсветки при наведении мыши на объекты анимации. В итоге мы потратили больше года на манипуляции и попытки заставить работать анимацию одинаково хорошо в разных браузерах. В ФФ анимация на основе канваса как в чистом виде, так и с использованием самых разных фреймворков просто обрушивала браузер, предварительно нагружая любой процессор до 100%. Анимация на чистом HTML (манипуляция обычными div'ами) не была плавной. Попробовали решить эту задачу на SVG, но тут выяснилось, что Chrome положил болт на векторную графику и там даже не работают элементарные события вроде mousemove или click для многих видов объектов.
                                                Промучавшись год с этой задачей мы в итоге были вынуждены отказаться полностью от анимации, тк либо нужно писать несколько разных ее видов на основе разных технологий, чтобы это работало во всех основных браузерах, либо использовать флеш. Так что как гейм программист могу вам сказать, что в данном виде, в котором пребывают на данный момент HTML5.Canvas и SVG им флеш не победить никогда. Однако уверен, что с годами ситуация изменится.
                                                  0
                                                    0
                                                    Никакого холивара. Я вам говорю о конкретной задаче, а не о статике. Вы суете всем в нос то, что сделано другими людьми для других целей.
                                                    Давайте я вам выдам ТЗ по той анимации, о которой я говорил и вы сами попробуете сделать. Вы пытаетесь убедить людей, работавших с канвасом в реальных задачах, но сами при этом, судя по всему, понятия не имеете о чем говорите. Даже вот ваш пример — красивая картинка. А как насчет обработки событий? А в опере пробовали открывать? А на планшете? Красивые демонстрашки это круто, но это не имеет никакого отношения к повседневным задачам.
                                                      +1
                                                      А вот давайте. Присылайте ТЗ.
                                                        +3
                                                        Суровые мужики =)))
                                                0
                                                Ну, слово — не воробей, однако, я не думаю, что предпоследнее слово в последнем абзаце не стоит затеянного холливара. А бросать камни в кого-бы то ни было, и тем более в своих коллег-программистов я бы уж точно не стал. Замечу, что я немного поизучал клиентскую сторону вот этого движка. Так что я не совсем уж не разбираюсь в вопросе. Тем не менее, для большинства областей применения, в которых сейчас используется flash, более чем достаточно «нативной» поддержки JS и Canvas. И вот тут-то эта пара уже вполне конкурентна.
                                              +1
                                              gasizdat пишет:
                                              Не так давно мне стало любопытно, насколько сносно современные браузеры поддерживают HTML5 и я не нашел лучшего
                                              способа, чем написать простейший 2D платформер. Помимо удовольствия от разработки игрушки и улучшения навыков в использовании JavaScript, в ходе развлечения кропотливой работы был накоплен определенный опыт и эмпирическим путем были найдены основные грабли, на многие из которых мне пришлось наступить. В этой статье я попробую кратко и с примерами резюмировать то, что вынес для себя из проделанной работы.


                                              Вопрос вам MixailV, где тут хоть что-нибудь про комерциализацию, продажу игры за $1000, поиск издателя и т.д.? Автор же явно дал понять, что его цель — изучить HTML5, Canvas, и особенности реализации их в браузерах.

                                              Хабр (ИМХО) в первую очередь технический сайт, тут принято общаться на технические темы, обсуждать код и т.д. И если вы действительно ожидали увидеть тут статью про коммерческий успех игрушки, то хабр действительно изменился, изменился в худшую сторону.
                                                +1
                                                Аргумент «сперва добейся». Типичная софистика.
                                              0
                                              По рендеру есть еще хитрый способ — можно кадровую логику (перемещения например) расчитывать при помощи таймаута, а рендерить уже состояние по requestAnimationFrame
                                                0
                                                Пока мне не очень ясно какие преимущества это даст. Если у Вас есть какой-то положительный опыт с таким подходом, было бы интересно услышать. Но, КМК, браузеры выполняют JS в одном потоке и все отложенные вызовы будут выполняться псевдоасинхронно. Потому суммарное время выполнение кода не сократится, а может даже вырасти, т.к. движку придется планировать несколько вызовов в контексте одного единственного потока.
                                                  0
                                                  Понятное дело, что однопоточно, но таким образом можно избежать «захлебывания» кадра, когда пора уже рисоватся новому, а еще старый ненарисован.
                                                  то есть, попробуйте такой код, быть может покажет прирост производительности:
                                                  var renderLoop = function () {
                                                  //game logic
                                                  setTimeout(renderLoop, 30);
                                                  }
                                                  

                                                  0
                                                  смысла рисовать 2 раз один и тот же кадр нету
                                                    0
                                                    Согласен. Но рендер будет только по необходимости и если переключена вкладка — рендера не будет. А вот игровая логика все так же будет отрабатывать.
                                                      0
                                                      Не надо рисовать. Если состояние не изменилось, ничего не делаем.

                                                      Примерно так:
                                                      this.doDraw = function()
                                                      {
                                                      	if(fNeedRedraw)
                                                      	{
                                                      		fNeedRedraw = false;
                                                      		fGameMap.Draw(fBuffer);
                                                      	}
                                                      }
                                                      
                                                      this.doAnimationLoop = function()
                                                      {
                                                      	requestAnimFrame(fInstance.doAnimationLoop);
                                                      	fInstance.doDraw();
                                                      }
                                                      
                                                        0
                                                        но при этом будет перерисовываться весь фрейм? а не область изминения? в отличие от Флеш который анализирует и смотрит, какую область фрема отреднерить а какую не трогать и оставить статичной.
                                                          0
                                                          Условно, requestAnimationFrame — это событие «Я отрисовал предыдущее задание и готов рисовать снова». Что Вы положите в функцию отрисовки — решать Вам.
                                                    +2
                                                    Вы для заманухи взяли картинку из очень крутых экспериментов по анимации через смещение в палитре www.effectgames.com/demos/canvascycle/?sound=0 рассказали бы об этом еще ;)
                                                      0
                                                      Мне самому бы разобраться. Но, согласитесь, вдохновляет!
                                                        +1
                                                        Посмотрите вниметельно на этот вызов:
                                                        www.effectgames.com/demos/canvascycle/image.php?file=V08AM&callback=CanvasCycle.processImage
                                                          +1
                                                          В дополнение к предыдущему. Хабр съел:

                                                          И после этого — на файл Bitmap.js
                                                          Грубо говоря — вся картинка передается в виде массива пикселей, в котором есть обозначения, какие пиксели анимировать, какие — нет. После этого анимированные пиксели перерисовываются циклично в пределах одного цвета (R/G/B) на совсем малое смещение.
                                                          Но работа, конечно, очень. У меня бы терпения отлаживать не хватило ^_^
                                                            0
                                                            Спасибо! Я после просмотра этих экспериментов влюбился в работы художника Mark'а Ferrari! Потрясающе красивые миры!
                                                            0
                                                            Плюсую. Но измерение в «попугаях» — не серьёзно.
                                                            Посмотрите на kothic.org/js/ (гуглить kothic.js)
                                                              0
                                                              Не следует напрягать движок реализацией классов при помощи прототипирования – выгода сомнительна, а код замедляется в разы (Opera)! Сложное прототипное наследование и честно организованный перенос базового функционала к наследникам сбивают и без того не самую лучшую оптимизацию.

                                                              5. Замыкания и свойства – враги быстродействия

                                                              Эээ.
                                                              Я бы таки хотел посмотреть на тесты, в которых выявлены такие интересные факты.
                                                                0
                                                                Для того, чтобы в тесте сравнить быстродействие псевдоклассов и наследования, построенных на прототипировании, нужно сильно перекроить имеющуюся объектную модель. Скажу только, что начинал я именно с этого, но результат, мягко скажем, был никакой, как в плане производительности, так и в плане поддержки. Что касается замыканий и свойств, то ссылка на код теста есть прямо в том же пункте. Я не исключаю, что я где-то сильно заблуждаюсь, но вероятность этого мне кажется мала.
                                                                  0
                                                                  > Для того, чтобы в тесте сравнить быстродействие псевдоклассов и наследования, построенных на прототипировании, нужно сильно перекроить имеющуюся объектную модель. Скажу только, что начинал я именно с этого, но результат, мягко скажем, был никакой, как в плане производительности, так и в плане поддержки.

                                                                  Ну тогда так и пишите — перевести существующий код на прототипы оказалось дорого. Откуда такие широкие обобщения?

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

                                                                  А, нашел, прошу прощения.

                                                                    function type1()
                                                                    {
                                                                      var _x1 = 0, _x2 = 0;
                                                                      this.setx1 = function(v) { _x1=v; };
                                                                      this.setx2 = function(v) { _x2=v; };
                                                                      this.sum = function() { return _x1+_x2; };
                                                                    }
                                                                  
                                                                    function type2()
                                                                    {
                                                                      this.x1 = 0;
                                                                      this.x2 = 0;
                                                                      this.setx1 = function(v) { this.x1=v; };
                                                                      this.setx2 = function(v) { this.x2=v; };
                                                                      this.sum = function() { return this.x1 + this.x2; };
                                                                    }
                                                                  
                                                                    function type3()
                                                                    {
                                                                      var _x1 = 0, _x2 = 0;
                                                                      Object.defineProperty(this, "x1", {get: function(){  return _x1; }, set: function(v){ _x1 = v; } });
                                                                      Object.defineProperty(this, "x2", {get: function(){  return _x2; }, set: function(v){ _x2 = v; } });
                                                                      Object.defineProperty(this, "sum", {get: function() { return _x1 + _x2; } });
                                                                    }
                                                                  


                                                                  Два вопроса:
                                                                  1. Как вы полагаете, что вы проверили этим тестом?
                                                                  2. Каким образом из этих тестов вы делаете широкий вывод, что «замыкания и свойства — враги быстродействия»?
                                                                    0
                                                                    1.
                                                                    var t1 = new type1(); var t2 = new type2(); var t3 = new type3(); 
                                                                    for(var i = 0; i < loops; i++)  { t2.x1 = i; t2.x2 = i + 5; sum += t2.sum(); } //прямой доступ к полям объекта и вызов метода (без замыкания)
                                                                    for(var i = 0; i < loops; i++)  { t1.setx1(i); t1.setx2(i + 5); sum -= t1.sum(); } //доступ к внутренним переменным через замыкания
                                                                    for(var i = 0; i < loops; i++)  { t2.setx1(i); t2.setx2(i + 5); sum += t2.sum(); } //доступ к полям объекта через методы (без замыкания)
                                                                    for(var i = 0; i < loops; i++)  { t3.x1 = i;  t2.x2 = i + 5;  sum -= t2.sum;  } //доступ к внутренним переменным через свойства с замыканиями.
                                                                    

                                                                    2. Методом индукции.
                                                                    Но, тон Вашего вопроса мне говорит, что Вы на него ответите лучше меня :)
                                                                  0
                                                                  В хороших книжках по оптимизации JS сказано, что время на поиск свойства в объекте — критичная штука. И в рендерЛупе вообще лучше _все_ переменные по возможности делать локальными. А некоторые даже рекомендуют, что если к свойству или элементу массива вы обращаетесь более 1 раза, то их надо тоже вносить в локальную переменную, особенно это касается DOM элементов.
                                                                  P.S. Под хорошими книжками я понимаю книжки написанные Николасом Закасом, Дугласом Крокфордом и Стефаном Стояновым.
                                                                    0
                                                                    А некоторые, например, проверяют, а не доверяют.
                                                                    jsperf.com/local-var-vs-3-dots
                                                                    В FF, к примеру, в некоторых кейсах обращение к параметру через три точки на 17% быстрее, чем сохранение в локальную переменную.

                                                                    В хороших книжках по оптимизации написан не свод правил, а предложение думать головой, проверять и подходить к каждому кейсу индивидуально, а не заниматься обобщениями «замыкания тормозят».
                                                                      0
                                                                      Большинство оптимизаций, к которым я пришел — вышло из практики их применения. Раньше я обращался через точку, потом решил попробовать локальную переменну — случился прирост FPS, что, кстати, подтверждает приведенная вами ссылка. А думать головой надо всегда, даже когда написан «свод правил»;)
                                                                      И наверное я некорректно выразился, когда говорил о локальных переменных, вот я сделал тест, который отражает положение дел в моем коде.
                                                                        0
                                                                        Вы шутите? Мелкопроцентный прирост при пустом теле? Это полностью нивелируется погрешностями. Когда внутри цикла есть серьёзные вычисления — эти все спичечные оптимизации не дают никакого эффекта. Прирост даёт оптимизация отрисовки в первую очередь — отрисовка в целые координаты, перерисовка только необходимого, избегание сглаживания, кеширование вектора. А переносить свойства в локальную — это для редких случаев, когда есть один метод, который обрабатывает десятки тысяч раз в секунду и требуется его локальная оптимизация. Ну, например, просчёт лучей в ray-casting'е. Но это два-три метода на весь код, а не основная практика.
                                                                          0
                                                                          я говорю именно о renderLoop, где у меня проходятся объекты в массивах. оптимизации, о которых вы говорите уже сделаны, в том числе и те оптимизации, о которых вы говорили в своих статьях.
                                                                            0
                                                                            Ну возможно есть узкий стек приложений, где оптимизации из серии выноса в локальную переменную актуальны, не спорю)
                                                                            Но такие вещи стоит ловить профайлером и убирать, а не писать в статьи, как best practices, имхо)
                                                                  0
                                                                  А я помню откуда картинка к статье! habrahabr.ru/post/100255/. Уж больно оно мне запомнилось тогда.
                                                                    +1
                                                                    Какой неожиданно эффективный вброс! Я уже надеялся что холивары на тему «флеш мертв» вышли из тренда. )) gasizdat, вы всего одной фразой смогли в статье изначально акцентированной на технических нюансах вызвать бурление. За статью — спасибо, мне нравится такая сжатая подача информации, вы молодец.
                                                                      +1
                                                                      Спасибо. Впредь мне наука — пишешь про один ЯП, не упоминая всуе другой. В общем сам не ожидал.
                                                                      0
                                                                      "gasizdat… вполне позволяют писать производительные интерактивные графические приложения, которые в большинстве задач дадут фору традиционному flash программированию"
                                                                      100%! HTML+JS дадут фору Macromedia Flash 1.x-6.x, но вот тем что позже и тем, которые стали Adobe Flash — уже нет. Назначение разное, возможность использования ресурсов, исполнение кода и т.д. На JS разве что СуперМарио делать. Хотел бы я взглянуть на Танки Онлайн, сделанные на JS )))))

                                                                      А за исследование — респект, замечательный материал.
                                                                        0
                                                                        Исследование дельное, но объясните мне пожалуйста, ЧТО толкает вас на использование Comic Sans в тестах?

                                                                      Only users with full accounts can post comments. Log in, please.