Разработка 2D-игр на HTML5: Реализация поведения спрайтов

Наделение героев Snail Bait поведением

В предлагаемом цикле статей знаток HTML5 Дэвид Гири шаг за шагом демонстрирует процесс создания 2D-видеоигры на HTML5. Эта статья посвящена реализации квинтэссенции любой видеоигры: поведению спрайтов.

Дэвид Джири, президент, Clarity Training, Inc.

David GearyАвтор, лектор и консультант Дэвид Джири является президентом компании Clarity Training, Inc., Он обучает разработчиков создавать Web-приложения с использованием JSF и Google Web Toolkit (GWT). Он участвовал в экспертных группах JSTL 1.0 и JSF 1.0/2.0, был соавтором сертификационного экзамена Web Developer Certification Exam компании Sun, а также принимал участие в проектах с открытым кодом, в том числе Apache Struts и Apache Shale. Книга Дэвида Graphic Java Swing стала одной из самых продаваемых книг о Java, а Core JSF (в соавторстве с Кэем Хорстманом) - одна из самых продаваемых книг о JSF. Дэвид регулярно выступает на конференциях и встречах пользовательских групп. Он является регулярным участником конференций NFJS с 2003 года, проводил курсы в университете Java и дважды удостаивался звания JavaOne rock star.



19.02.2013

У великих историй великие герои. А у видеоигр, в отличие от книг и кинофильмов, эти герои еще и наделены интересным поведением. Например, главный герой Braid — самой популярной игровой платформы всех времен — умеет манипулировать временем. Эта гениальная способность выделяет данную игру среди ей подобных.

Поведение героев ― душа любой видеоигры, и наделение поведением инертных спрайтов Snail Bait, реализованных в предыдущей статье, делает игру интереснее, как показано на рисунке 1.

Рисунок 1. Snail Bait по состоянию на конец этой статьи
Snail Bait по состоянию на конец этой статьи

В разделе Объекты спрайтов предыдущей статьи говорилось о том, что спрайты Snail Bait не имеют своего собственного поведения, такого как бег, прыжки или взрывы. Вместо этого их действиями управляют другие объекты —манипуляторы.

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

  • бегун бежит;
  • кнопки снуют туда-сюда на своих платформах;
  • рубины и сапфиры сверкают.

Эти элементы поведения перечислены в таблице 1:

Таблица 1. Элементы поведения, описанные в этой статье
СпрайтыЭлемент поведения (манипулятор)Описание
Кнопки, улитки paceBehavior Снуют взад и вперед вдоль платформы
Бегун runBehavior Циклически сменяет изображения бегуна для создания эффекта бега
Улитка snailShootBehavior Выплевывает ядра
Улитка cycleBehavior Циклически перебирает изображения спрайта
Ядро улитки snailBombMoveBehavior Перемещает ядро по горизонтали влево, пока оно не выйдет за край холста

Управление временем

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

Манипуляторы, перечисленные в таблице 1, составляют менее половины всех манипуляторов игры ― как следует из таблицы Спрайты и манипуляторы Snail Bait, приведенной в первой статье этого цикла. К тому же это наиболее простые манипуляторы спрайтов; прыжки, например, значительно сложнее, как вы увидите в будущих статьях. Тем не менее, реализуя простые элементы поведения из этой статьи, можно многому научиться, в том числе:

  • создавать манипуляторы и назначать их спрайтам;
  • циклически перебирать последовательность изображений спрайта;
  • создавать манипуляторы-приспособленцы для экономии памяти;
  • комбинировать манипуляторы;
  • использовать манипуляторы для стрельбы ядрами.

Основы реализации поведения

Манипуляторы Replica Island

Идея манипуляторов происходит из Replica Island ― популярной игры с открытым исходным кодом для платформы Android. Многие из манипуляторов Snail Bait также взяты из Replica Island. Ссылки на эту игру и на сообщение в блоге, в котором создатель игры рассказывает о манипуляторах, см. в разделе Ресурсы.

Манипулятором может быть любой объект, обладающий методом execute(). Этот метод принимает три аргумента: спрайт, время и частоту кадров для анимации в игре. Метод execute() манипулятора изменяет состояние спрайта в зависимости от времени и частоты кадров анимации.

Манипуляторы ― это мощные инструменты:

  • они наделяют спрайты индивидуальным поведением;
  • поведение спрайта можно менять во время выполнения;
  • можно реализовать манипуляторы, которые работают с любым спрайтом;
  • можно использовать манипуляторы без спрайта - приспособленцы (flyweight).

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


Элементы поведения бегуна

У бегуна Snail Bait четыре элемента поведения, которые перечислены в таблице 2.

Таблица 2. Элементы поведения (манипуляторы) бегуна
МанипуляторОписание
runBehavior Циклически перебирает изображения бегуна со страницы спрайтов для создания эффекта бега.
jumpBehavior Управляет всеми элементами прыжка: подъем, спуск и приседание.
fallBehavior Управляет вертикальным перемещением бегуна, когда тот падает.
runnerCollideBehavior Обнаруживает и реагирует на столкновения бегуна с другими спрайтами.

Я определяю манипуляторы бегуна с помощью массива объектов, которые передаются конструктору Sprite, как показано в листинге 1.

Листинг 1. Создание бегуна Snail Bait
var SnailBait = function () {
   ...

   this.runner = new Sprite('runner',              // Тип
                            this.runnerArtist,    //  Начертатель
                            [this.runBehavior,  //  Манипуляторы
                          this.jumpBehavior,
                          this.fallBehavior,
                          this.runnerCollideBehavior

                           ]);
};

В листинге 2 показаны манипуляторы бегуна без деталей реализации.

Листинг 2. Объекты манипуляторов бегуна
var SnailBait = function () {
   ...

   this.runBehavior = {
      execute: function(sprite, time, fps) { // спрайт-это бегун
         ...
      }
   };
   this.jumpBehavior = {
      execute: function(sprite, time, fps) { // спрайт-это бегун
         ...
      }
   };
   this.fallBehavior = {
      execute: function(sprite, time, fps) { // спрайт-это бегун
         ...
      }
   };
   this.runnerCollideBehavior = {
      execute: function(sprite, time, fps) { // спрайт-это бегун
         ...
      }
   };
};

На каждом кадре анимации Snail Bait перебирает массив спрайтов, вызывая метод update() каждого спрайта, как показано в листинге 3.

Листинг 3. Выполнение манипуляторов
Sprite.prototype = {
   update: function (time, fps) {
      for (var i=0; i < this.behaviors.length; ++i) {
         if (this.behaviors[i] === undefined) { // никогда не знаешь 
            return;
         }

         this.behaviors[i].execute(this, time, fps);
      }
   }
};

Метод Sprite.update() выполняет перебор манипуляторов спрайта, вызывая метод execute() каждого манипулятора. Snail Bait постоянно — один раз за кадр анимации — вызывает все манипуляторы всех видимых спрайтов. Таким образом, метод execute() манипулятора не похож на большинство других методов, которые вызываются относительно редко; каждый метод execute() напоминает моторчик, который постоянно работает.

Теперь, когда вы понимаете, как сочетаются спрайты и манипуляторы, я сосредоточусь на их индивидуальной реализации.

Модель проектирования Strategy

Манипуляторы представляют собой реализацию модели проектирования Strategy, которая инкапсулирует алгоритмы в объекты (см. раздел Ресурсы). Во время выполнения эти алгоритмы можно смешивать и сочетать друг с другом, назначая спрайту набор манипуляторов. Манипуляторы обеспечивают большую гибкость по сравнению с жестким кодированием алгоритмов непосредственно в отдельных спрайтах.

Бег

Чтобы создать впечатление, что бегун бежит, Snail Bait делает две вещи. Во-первых, игра постоянно прокручивает фон, создавая впечатление, что бегун движется горизонтально, как я говорил в разделе Прокручивание фона второй статьи этого цикла. Во-вторых, манипулятор бега бегуна циклически перебирает последовательные изображения со страницы спрайтов игры, как показано на рисунке 2.

Рисунок 2. Последовательность бега
Бегун Snail Bait

Код, приведенный в листинге 4, реализует поведение бега.

Листинг 4. Манипулятор бегуна runBehavior
  var SnailBait = function () {  
   ...
   this.BACKGROUND_VELOCITY = 32, // пикселей в секунду
   this.RUN_ANIMATION_RATE = 17, // кадров в секунду
   ...

   this.runAnimationRate,

   this.runBehavior = {
      // Каждые runAnimationRate миллисекунд этот манипулятор переводит
      // начертатель бегуна на следующий кадр со страницы спрайтов.

      lastAdvanceTime: 0,

      execute: function(sprite, time, fps) {
         if (sprite.runAnimationRate === 0) {
            return;
         }

         if (this.lastAdvanceTime === 0) {  // пропуск первого раза
            this.lastAdvanceTime = time;
         } 
         else if (time - this.lastAdvanceTime > 1000 / sprite.runAnimationRate) {
            sprite.artist.advance();
            this.lastAdvanceTime = time;
         }
      }
   },
   ...
};

Метод execute() объекта runBehavior периодически переводит начертатель бегуна к следующему изображению в последовательности бегуна со страницы спрайтов. (Страница спрайтов Snail Bait приведена в разделе Начертатели спрайтов и страницы спрайтов четвертой статьи этого цикла).

От того, как часто runBehavior перебирает изображения бегуна, зависит, как быстро он бежит. Этот временной интервал задается с помощью атрибута бегуна runAnimationRate. Бегун не бежит при запуске игры, поэтому первоначально его runAnimationRate равен нулю. Однако когда игрок поворачивает влево или вправо, Snail Bait задает значение этого атрибута в 17 кадров в секунду, как показано в листинге 5, и бегун начинает бежать.

Листинг 5. Поворот запускает анимацию бега
SnailBait.prototype = {
   ...

   turnLeft: function () {
      this.bgVelocity = -this.BACKGROUND_VELOCITY;
      this.runner.runAnimationRate = this.RUN_ANIMATION_RATE; //17 кдр./с, см.листинг 4
      this.runnerArtist.cells = this.runnerCellsLeft;
      this.runner.direction = this.LEFT;
   },

   turnRight: function () {
      this.bgVelocity = this.BACKGROUND_VELOCITY;
      this.runner.runAnimationRate = this.RUN_ANIMATION_RATE; //17 кдр./с, см.листинг 4
      this.runnerArtist.cells = this.runnerCellsRight;
      this.runner.direction = this.RIGHT;
   },

};

Ход времени

Как и бег бегуна, почти все манипуляторы основываются на времени. А так как анимация игры работает постоянно, многие функции, изменяющие поведение игры, такие как turnLeft() и turnRight() в листинге 5, добиваются этого, просто устанавливая переменные игры. Когда игра рисует следующий кадр анимации, эти переменные влияют на ее поведение.

Методы turnLeft() и turnRight(), которые вызываются обработчиками событий клавиатуры в игре, управляют тем, как быстро бегун циклически перебирает последовательность изображений, с помощью атрибута runAnimationRate, как описано выше. Эти методы управляют и тем, как быстро бегун перемещается слева направо, устанавливая атрибут bgVelocity, который соответствует скорости прокрутки фона.


Манипуляторы-приспособленцы

Манипулятор бега бегуна, описанный в предыдущем разделе, запоминает состояние — а именно, момент времени, когда манипулятор в последний раз переместил изображение спрайта. Это состояние прочно связывает бегуна с манипулятором. Если нужно, чтобы бежал еще один спрайт, вам понадобится другой манипулятор бега.

Манипуляторы, которые не запоминают состояние, обладают большей гибкостью; например, их можно использовать в качестве приспособленцев. Приспособленец (flyweight) – это экземпляр объекта, который используется многими другими объектами одновременно. На рисунке 3 показан манипулятор хода без запоминания состояния, с помощью которого спрайты снуют взад и вперед по платформе. Один экземпляр этого манипулятора используется для кнопок игры и улиток, которые перемещаются по своим платформам, как показано на рисунке 3.

Рисунок 3. Последовательность перемещения кнопки
Последовательность перемещения кнопки в игре Snail Bait

Листинг 6 демонстрирует метод createButtonSprites() Snail Bait, который добавляет по одному манипулятору хода к каждой кнопке.

Листинг 6. Создание снующих кнопок
SnailBait.prototype = {
   ...

   createButtonSprites: function () {
      var button,
          buttonArtist = new SpriteSheetArtist(this.spritesheet,
                                               this.buttonCells),
      goldButtonArtist = new SpriteSheetArtist(this.spritesheet,
                                               this.goldButtonCells);

      for (var i = 0; i < this.buttonData.length; ++i) {
         if (i === this.buttonData.length - 1) {
            button = new Sprite('button',
                                 goldButtonArtist,
                                 [ this.paceBehavior ]);
         }
         else {
            button = new Sprite('button',
                                 buttonArtist,
                                 [ this.paceBehavior ]);
         }

         button.width = this.BUTTON_CELLS_WIDTH;
         button.height = this.BUTTON_CELLS_HEIGHT;

         button.velocityX = this.BUTTON_PACE_VELOCITY;
         button.direction = this.RIGHT;

         this.buttons.push(button);
      }
   },
   ...
};

Объект paceBehavior приведен в листинге 7.

Листинг 7. Манипулятор хода
var SnailBait = function () {
   ...

   this.paceBehavior = {
      checkDirection: function (sprite) {
         var sRight = sprite.left + sprite.width,
             pRight = sprite.platform.left + sprite.platform.width;

         if (sRight > pRight && sprite.direction === snailBait.RIGHT) {
            sprite.direction = snailBait.LEFT;
         }
         else if (sprite.left < sprite.platform.left &&
                  sprite.direction === snailBait.LEFT) {
            sprite.direction = snailBait.RIGHT;
         }
      },

      moveSprite: function (sprite, fps) {
         var pixelsToMove = sprite.velocityX / fps;

         if (sprite.direction === snailBait.RIGHT) {
            sprite.left += pixelsToMove;
         }
         else {
            sprite.left -= pixelsToMove;
         }
      },

      execute: function (sprite, time, fps) {
         this.checkDirection(sprite);
         this.moveSprite(sprite, fps);
      }
   },

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


Независимые манипуляторы

Приспособленцы и состояние

paceBehavior не запоминает свое состояние, и его можно использовать в качестве приспособленца. В этом случае состояние — положение и направление движения каждого спрайта — хранится в самом спрайте.

Первый манипулятор, который я обсуждал в этой статье, — runBehavior — представляет собой манипулятор без запоминания состояния, который жестко связан с одним спрайтом. Следующий манипулятор, paceBehavior, ― это манипулятор без запоминания состояния, отделенный от конкретных спрайтов, поэтому один его экземпляр может использоваться несколькими спрайтами.

Манипуляторы можно обобщить еще больше: их можно отделить не только от индивидуальных спрайтов, но и от самой игры. В Snail Bait используется три манипулятора, которые могут фигурировать в любой игре:

  • bounceBehavior
  • cycleBehavior
  • pulseBehavior

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

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

Сверкающие рубины

Рубины и сапфиры Snail Bait сверкают, как показано на рисунке 4.

Рисунок 4. Последовательность сверкания рубина
Снимок экрана Snail Bait

Страница спрайтов Snail Bait содержит последовательности изображений для рубинов и сапфиров; циклический перебор этих изображений создает иллюзию сверкания.

В листинге 8 показан метод Snail Bait, создающий рубины. Почти идентичный метод (не показан) используется для создания сапфиров. Метод createRubySprites() также создает циклический манипулятор, который через каждые 500 мс отображает следующее изображение из последовательности сверкания рубина на 100 мс.

Листинг 8. Создание рубинов
SnailBait.prototype = {
   ...
   createRubySprites: function () {
      var ruby,
          rubyArtist = new SpriteSheetArtist(this.spritesheet, this.rubyCells);

      for (var i = 0; i < this.rubyData.length; ++i) {
         ruby = new Sprite('ruby', rubyArtist,
                           [ new CycleBehavior(100,     // длительность анимации
                                                 500) ]); // интервал между анимациями
         ...
      }
   },
   ...
};

В листинге 9 приведен манипулятор цикла.

Листинг 9. Манипулятор CycleBehavior
// Этот манипулятор сменяет
// начертателей спрайта с указанной частотой анимации.

CycleBehavior = function (duration, interval) {
   this.duration = duration || 0;  //  миллисекунды
   this.interval = interval || 0;
   this.lastAdvance = 0;
};

CycleBehavior.prototype = { 
   execute: function(sprite, time, fps) {
      if (this.lastAdvance === 0) { 
         this.lastAdvance = time;
      }

      // В течение интервала начинается движение, если интервал окончен

      if (this.interval && sprite.artist.cellIndex === 0) {
         if (time - this.lastAdvance < this.interval) {
            sprite.artist.advance();
            this.lastAdvance = time;
         }
      }
      // В противном случае, когда манипулятор находится в цикле, 
      // он сменяет изображение, если его время истекло

      else if (time - this.lastAdvance > this.duration) {
         sprite.artist.advance();
         this.lastAdvance = time;
      }
   }
};

Обобщение манипуляторов

Хорошая идея ― найти возможность для обобщения манипуляторов, чтобы они использовались как можно шире.

Циклический манипулятор работает с любым спрайтом, у которого есть свой начертатель, что означает, что это не специфический манипулятор для Snail Bait, так что его можно использовать и в других играх. Специфический манипулятор спрайта из листинга 4 имеет много общего с независимым циклическим манипулятором из листинга 9; на самом деле этот циклический манипулятор получен из манипулятора бега. (Манипулятор бега мог бы быть более общим циклическим манипулятором, но он учитывает частоту анимации бегуна).


Комбинирование манипуляторов

Отдельные манипуляторы инкапсулируют определенные действия, такие как бег, ходьбу или сверкание. Манипуляторы можно объединять для создания более сложных эффектов; например, когда улитка снует взад и вперед по своей платформе, она периодически выпускает ядро, как показано на рисунке 5.

Рисунок 5. Последовательность перемещения улитки
Снимок экрана Snail Bait

Последовательность стрельбы улитки представляет собой комбинацию трех манипуляторов:

  • paceBehavior
  • snailShootBehavior
  • snailBombMoveBehavior

paceBehavior и snailShootBehavior связаны с улиткой; snailBombMoveBehavior связан с ядрами улитки. Когда Snail Bait создает спрайты, она указывает два первых манипулятора в конструкторе Sprite, как видно в листинге 10.

Листинг 10. Создание улиток
SnailBait.prototype = {
   ...

   createSnailSprites: function () {
      var snail,
          snailArtist = new SpriteSheetArtist(this.spritesheet, this.snailCells);

      for (var i = 0; i < this.snailData.length; ++i) {
         snail = new Sprite('snail',
                            snailArtist,
                            [ this.paceBehavior,
                              this.snailShootBehavior,
                              new CycleBehavior(300,  // 300 мс на изображение
                                                1500) // 1,5 с между последовательностями
                            ]);

         snail.width  = this.SNAIL_CELLS_WIDTH;
         snail.height = this.SNAIL_CELLS_HEIGHT;

         snail.velocityX = this.SNAIL_PACE_VELOCITY;
         snail.direction = this.RIGHT;

         this.snails.push(snail); // Введение улитки в массив улиток
      }
   },
};

Каждые 1,5 секунды манипулятор улитки CycleBehavior циклически перебирает изображения улитки со страницы спрайтов, показанные на рисунке 6, и отображает каждое из них в течение 300 мс, что создает впечатление, что улитка периодически открывает и закрывает рот. Манипулятор улитки paceBehavior перемещает улитку по платформе.

Рисунок 6. Изображения со страницы спрайтов для последовательности выстреливания ядра улитки
Снимок с экрана изображений спрайта

Ядра улитки создаются методом armSnails(), показанным в листинге 11, который Snail Bait вызывает в начале игры. Этот метод перебирает улиток игры, создает ядра для каждой улитки, оснащает каждое ядро манипулятором snailBombMoveBehavior и сохраняет в ядре указатель на свою улитку.

Листинг 11. Стреляющие улитки
SnailBait.prototype = {
   ...

   armSnails: function () {
      var snail,
          snailBombArtist = new SpriteSheetArtist(this.spritesheet, this.snailBombCells);

      for (var i=0; i < this.snails.length; ++i) {
         snail = this.snails[i];

         snail.bomb = new Sprite('snail bomb',
                                  snailBombArtist,
                                  [ this.snailBombMoveBehavior ]);

         snail.bomb.width  = snailBait.SNAIL_BOMB_CELLS_WIDTH;
         snail.bomb.height = snailBait.SNAIL_BOMB_CELLS_HEIGHT;

         snail.bomb.top = snail.top + snail.bomb.height/2;
         snail.bomb.left = snail.left + snail.bomb.width/2;
         snail.bomb.visible = false;

         this.sprites.push(snail.bomb);
      }
   },
};

Манипулятор улитки snailShootBehavior выстреливает ядра, как показано в листинге 12.

Листинг 12. Стрельба ядрами улитки
SnailBait.prototype = {
   ...

   this.snailShootBehavior = { // Спрайт-это улитка
      execute: function (sprite, time, fps) {
         var bomb = sprite.bomb;

         if (! bomb.visible && sprite.artist.cellIndex === 2) {
            bomb.left = sprite.left;
            bomb.visible = true;
         }
      }
   },

};

Игры на основе манипуляторов

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

Раз манипулятор snailShootBehavior связан с улиткой, то спрайтом, передаваемым его методу execute(), будет улитка.

Улитка сохраняет связь со своим ядром, поэтому snailShootBehavior обращается к ядру через улитку. Затем snailShootBehavior проверяет, не является ли текущее изображение улитки крайним правым изображением из тех, что показаны на рисунке 6, что означает, что улитка открывает рот; в этом случае манипулятор вставляет ядро в рот улитки и делает его видимым.

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

Листинг 13. Манипулятор ядра улитки
SnailBait = function () {
   this.SNAIL_BOMB_VELOCITY = 450,
   ...
};

SnailBait.prototype = {
   this.snailBombMoveBehavior = {
      execute: function(sprite, time, fps) {  // спрайт ― это ядро
         if (sprite.visible && snailBait.spriteInView(sprite)) {
            sprite.left -= snailBait.SNAIL_BOMB_VELOCITY / fps;
         }

         if (!snailBait.spriteInView(sprite)) {
            sprite.visible = false;
         }
      }
   },

Пока ядро находится в поле зрения, snailBombMoveBehavior перемещает его влево со скоростью snailBait.SNAIL_BOMB_VELOCITY (450) пикселей в секунду. Когда ядро выходит из поля зрения, манипулятор делает его невидимым.


В следующей статье

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


Загрузка

ОписаниеИмяРазмер
Пример кодаj-html5-game5.zip1,2 МБ

Ресурсы

Научиться

Получить продукты и технологии

  • Replica Island: загрузите открытый исходный код этого популярного платформера для Android.

Обсудить

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

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java, Web-архитектура
ArticleID=858518
ArticleTitle=Разработка 2D-игр на HTML5: Реализация поведения спрайтов
publish-date=02192013