Thursday, November 3, 2011

Простая игра на HTML5 Canvas – часть 4

Часть 4а. РИСУЕМ ПЛАТФОРМЫ

Есть два типа платформ. Наш персонаж может прыгать по обычной (оранжевой) и зеленой (батут), который дает дополнительное ускорение и гипер-ультра-высокий прыжок. Всегда есть семь платформ на экране (я попробовал другое количество, от 4 до 10 и только 7 прекрасно работает с размером экрана заявленным в начале). Давайте создадим класс платформ (функции платформы будут наследовать).
var Platform = function(x, y, type){
//функция принимает позицию и тип платформы
var that=this;
that.firstColor = '#FF8C00';that.secondColor = '#EEEE00';that.onCollide = function(){player.fallStop();};//если тип платформы отличен от 1, то просто устанавливаем нужный цвет и вызываем функцию
//fallStop() определенную в прошлой части урока
if (type === 1) {//, но если тип равен '1', устанавливаем другие цвета и ускорение взлета jumpSpeed равным 50.
//после этого метод checkJump()примет '50' вместо '17' предусмотренных по умолчанию.
that.firstColor = '#AADD00';that.secondColor = '#698B22';that.onCollide = function(){
player.fallStop();player.jumpSpeed = 50;};}
that.x = ~~x;that.y = y;that.type = type;
return that;
};
Теперь необходимо создать функцию, которая будет генерировать все платформы и складывать их в platforms[] массив, который мы определим в ближайшее время. После этого нарисуем платформы на экране.
var nrOfPlatforms = 7,
platforms = [],platformWidth = 70,platformHeight = 20;//глобальные (пока) переменные не очень подходят для хранения размеров платформ, но
//в нашем случае они необходимы для вычисления столкновений, поэтому размещены здесь
//а не в свойствах класса платформ
var generatePlatforms = function(){var position = 0, type;//'position' это Y координата платформы на экране и вначале она равно нулю
for (var i = 0; i < nrOfPlatforms; i++) {type = ~~(Math.random()*5);
if (type == 0) type = 1;else type = 0;//Обычных платформ будет примерно в пять раз больше, чем батутов
platforms[i] = new Platform(Math.random()*(width-platformWidth),position,type);//случайно выбранная позиция по Xif (position < height - platformHeight)
position += ~~(height / nrOfPlatforms);}//и Y интервал
}();
//эта функция будет вызвана только один раз, перед стартом игры
Добавляем метод Draw () объекту платформы:
var Platform = function(x, y, type){(...)that.draw = function(){ctx.fillStyle = 'rgba(255, 255, 255, 1)';//Это важно заменить прозрачность в rgba на 1 (непрозрачно), потому что Google Chrome помнит
//предыдущее значение, которое мы устанавливали, рисуя облака (круги) на заднем фоне, в
//Firefox и Safari этого не происходит
 var gradient = ctx.createRadialGradient(that.x + (platformWidth/2), that.y + (platformHeight/2), 5, that.x + (platformWidth/2), that.y + (platformHeight/2), 45);
gradient.addColorStop(0, that.firstColor);gradient.addColorStop(1, that.secondColor);ctx.fillStyle = gradient;ctx.fillRect(that.x, that.y, platformWidth, platformHeight);//заполняем прямоугольную платформу градиентной заливкой
};
return that;
};
Платформы должна быть нарисованы на каждом кадре, так что обновление GameLoop () является обязательным.
var GameLoop = function(){(...)platforms.forEach(function(platform){platform.draw();
});
(...)
};

Часть 4б. СТОЛКНОВЕНИЯ 

Чудненько, но нет взаимодействия между ангелом и платформами. Одна маленькая функция исправит ситуацию. Позвольте мне представить checkCollision ():
var checkCollision = function(){platforms.forEach(function(e, ind){//проверяем каждую платформуif ((player.isFalling) &&
//только когда персонаж падает(player.X < e.x + platformWidth) &&
(player.X + player.width > e.x) &&
(player.Y + player.height > e.y) &&
(player.Y + player.height < e.y + platformHeight)//и находится прямо над платформой) {e.onCollide();}})}
Еще одно обновление основного цикла (подходящий момент, чтобы закомментировать функцию MoveCircles (), если платформы стоят на месте, почему фон движется? будет больше смысла, когда мы будем осуществлять прокрутку платформ и фона одновременно). Так GameLoop () функция должна выглядеть в настоящее время:
var GameLoop = function(){clear();//MoveCircles(5);DrawCircles();
if (player.isJumping) player.checkJump();if (player.isFalling) player.checkFall();
platforms.forEach(function(platform){platform.draw();});
checkCollision();
player.draw();gLoop = setTimeout(GameLoop, 1000 / 50);}
Результат этой части урока можно посмотреть по адресу: http://jsbin.com/igeta3/, а скачать исходники тут: http://guthub.com/michalbe/Simple-game-with-HTML5-Canvas. Думаю следующая часть будет последней, но кто знает;)
Копирайты.
Автор: Михал Будзинский https://twitter.com/#!/@michalbe

Автор перевода: Андрей Семенов https://twitter.com/#!/a_semenov79

Wednesday, November 2, 2011

Простая игра на HTML5 Canvas - часть 3


Часть 3а. Физика


Потому что физика в StH очень проста, нет никакой необходимости включать какой-то физический движок, как например Box2d (http://box2d-js.sourceforge.net/). Прыжки главного персонажа настолько просты, что реализуются в нескольких строках кода. Давайте разделим его на две несвязанные части - прыжки и падения. Когда объект начинает прыгать, он имеет некоторую начальную скорость, снижающуюся под действием силы тяжести. Это стадия заканчивается, когда эта скорость полностью сводится к нулю и гравитация начинает тянуть объект вниз с нарастающей силой. Это вторая часть прыжка - падение. Научим ангела, как себя вести в таких ситуациях, давайте расширим объект ‘player’ добавив несколько атрибутов

var  player = new (function(){
  var  that = this;
  that.image  = new Image();
  (...)
//новые атрибуты
  that.isJumping  = false;
  that.isFalling  = false;
//состояние объекта в булевых переменных (взлет или падение)?
  that.jumpSpeed  = 0;
  that.fallSpeed  = 0;
  //ускорение взлета и падения
  
  (...) //остальная часть кода
  })();
  Теперь  давайте внедрять методы ответственные за прыжки. Дальнейшее  расширение объекта ‘player’: 
  that.jump = function() {
  //инициализация прыжка
  if (!that.isJumping &&  !that.isFalling) {
  //сначала  проверим - объект не должен находиться в состоянии взлета или падения,
  //чтобы  не подпрыгивать не имея опоры (из воздуха)
  that.fallSpeed = 0;
  that.isJumping = true;
  that.jumpSpeed = 17;
  //начальная скорость
  }
  }
  that.checkJump = function() {
  //начинаем взлетать
  that.setPosition(that.X,  that.Y - that.jumpSpeed);
  //перемещаемся  вверх с приростом на jumpSpeed пикселей
  that.jumpSpeed--;
  //имитируем  гравитацию уменьшая ускорение взлета
  if (that.jumpSpeed == 0) {
  //и  если ускорение взлета упало до нуля, начинаем падать
  that.isJumping = false;
  that.isFalling = true;
  that.fallSpeed = 1;
  }
  }
  that.checkFall = function(){
  //почти  тоже, что и checkJump()
  if (that.Y < height -  that.height) {
  //проверяем,  не достигнут ли нижний край экрана и увеличиваем fallSpeed 
  //(ускорение  свободного падения)...
  that.setPosition(that.X,  that.Y + that.fallSpeed);
  that.fallSpeed++;
  } else {
  //.. иначе – отскок (снова взлетаем) 
  that.fallStop();
  }
  }
  that.fallStop = function(){
  //хватит  падать, пора снова взлетать
  that.isFalling = false;
  that.fallSpeed = 0;
  that.jump();    
  }

Это обязательно обновлять основные функции цикла для перерисовки позиции нашего персонажа во время прыжков и падений. Обновляем GameLoop (игровой цикл) таким кодом, прежде чем перерисовать персонаж:

if (player.isJumping) player.checkJump();
  if (player.isFalling) player.checkFall();

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

player.setPosition(~~((width-player.width)/2),  ~~((height - player.height)/2));
  player.jump(); //здесь

Хорошо, красиво прыгает, фрагмент удивительного псевдо-физического кода. Теперь давайте сделаем некоторые элементы управления. 

Часть 3b. Управление

Главный герой StH может двигаться только вбок. Он подпрыгивает автоматически, вверх/вниз движения будут зависеть от платформ. Пользователь может только командовать ангелу, переместиться влево или вправо. Опять же, это может быть достигнуто путем расширения объекта ‘player’ дополнительными методами. 

var player = new(function(){
  (...)
  that.moveLeft = function(){
  if (that.X > 0) {
  //проверим не вышли ли мы за  область экрана
  that.setPosition(that.X - 5, that.Y);
  }
  }
  that.moveRight = function(){
  if (that.X + that.width < width) {
  // проверим не вышли ли мы  за область экрана
  that.setPosition(that.X + 5, that.Y);
  }
  }
  (...)
  })();

Теперь привяжем функцию к положению курсора мыши (ангел будет следовать за ним).

document.onmousemove =  function(e){
  if (player.X + c.offsetLeft  > e.pageX) {
  //если мышь слева от персонажа сдвигаем его влево.
  player.moveLeft();
  } else if (player.X +  c.offsetLeft < e.pageX) {
  //иначе направо?
  player.moveRight();
  }
  }

Это все на сегодня. В следующей части ​​я покажу рисование платформ и контроль столкновений. Как обычно, результат этой части урока можно посмотреть по адресу: http://jsbin.com/uhaka3/, а скачать исходники тут: http://guthub.com/michalbe/Simple-game-with-HTML5-Canvas

Копирайты.

Автор: Михал Будзинский https://twitter.com/#!/@michalbe

Автор перевода: Андрей Семенов https://twitter.com/#!/a_semenov79