Showing posts with label HTML5 JavaScript CSS3 JS game. Show all posts
Showing posts with label HTML5 JavaScript CSS3 JS game. Show all posts

Thursday, October 27, 2011

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


Предисловие от автора перевода.

Итак, я наконец-то подготовил перевод статьи Михала Будзинского открывающей нам новый web-стандарт HTML5. Этот стандарт еще не имеет утвержденной спецификации и представлен на сайте w3.org только как рабочий черновик, но уже активно продвигается производителями браузеров. Новшества, вносимые новой версией HTML (язык разметки гипертекстов) сближают его с языками программирования. Благодаря активному развитию социальных сетей, «облачных» сервисов и т.п. все яснее прослеживается необходимость улучшения интеграции мультимедийного контента и новый тэг <canvas> стал одним из решений данного вопроса представленный консорциумом.
Движок игры написан на JavaScript и те, кто еще не знаком с этим языком программирования найдут здесь также замечательные примеры для его начального освоения.

Введение.

StH - очень простой клон Doodle Jump, но чтобы быть до конца честным, я был вдохновлен Icy Tower. Ну да ладно.
Цель игры состоит в том, чтобы управлять маленьким ангелом и скакать на двух видах платформ - оранжевые (обычные) и зеленые (трамплины). Игра заканчивается, когда ангел падает за нижний край экрана.
Я создал эту игру за 8 часов и позже, когда довольно долго играл, я обнаружил немного ошибок,  так что в этом уроке, я хочу исправить их все. Давайте приступим!

Фон.

Поскольку вся игра, включая изображения и сценарии (скрипты), не должна быть больше 10КБ, я не захотел использовать растровое изображение на фоне. Гораздо экономичнее рисовать используя функции рисования <canvas>.
Прежде всего, мы нуждаемся в небольшом HTML, ничего особенного, только один <canvas> элемент с некоторым уникальным id, немного CSS и несуществующий, пока еще, game.js:
<html>
  <head>
    <title> Простая игра с HTML5 Canvas </ title>
  <style>
  body {margin:0px; padding:0px; text-align: center}
  canvas {outline:0; border:1px solid # 000; margin: 0 auto}
  </ style>
  </ head>
  <body>
    <canvas id='c'></ canvas>
    <script src="game.js"></ script>
  </ body>
</ html>
Это и есть весь HTML, который нам понадобится в течение этого урока. Хорошо, теперь давайте создавать Javascript. Прежде всего мы должны создать немного глобальных (хотя, я знаю что это Глобальное зло =) переменных и изменить атрибуты (свойства) <canvas>. Этого будет достаточно:
var width = 320, //ширина canvas
    height = 500, //высота canvas

  c = document.getElementById('c'), //сам canvas

  ctx = c.getContext('2d');
//двумерный контектс canvas (сейчас только он поддерживается всеми
//браузерами)

c.width = width;
c.height = height;
//устанавливаем размеры canvas

Первое, что важно понять про <canvas>, это то, что невозможно просто перемещать объекты на его поверхности. Нужно, обязательно, на каждом кадре его очищать, целиком или частично. Поэтому давайте создадим функцию очистки – clear():
var clear = function(){
  ctx.fillStyle = '#d0e7f9';
//выбираем цвет заливки (чудесный голубой)
//Использование clearRect() вызывало ошибку, в 2-х строках ниже показан
//старый вариант
//ctx.clearRect(0, 0, width, height);
//очистка экрана
  ctx.beginPath();
//запускаем рисование
  ctx.rect(0, 0, width, height);
//рисуем прямоугольник из точки (0, 0) до (widthheight) заполняя весь наш
//холст <canvas>
  ctx.closePath();
//заканчиваем рисование
  ctx.fill();
//заполняем прямоугольник цветом выбранным ранее
}

Одноцветный фон скучен как ад, так что давайте нарисуем несколько облаков на нем. Скорее не правильные облака, а простые, полупрозрачные круги, подражающие облакам. Круги мы будем рисовать в случайных местах холста, каждый с различным размером и прозрачностью. Мы будем держать всю информацию о кругах в 2-ом массиве (в JS их нет, но лучший путь к решению этой проблемы помещение одного массива в другой).

var howManyCircles = 10, circles = [];

for (var i = 0; i < howManyCircles; i++)
  circles.push([Math.random() * width, Math.random() * height, Math.random() * 100, Math.random() / 2]);
//добавляем информацию о кругах
//в массив 'circles'. Это x и y позиция,
//радиус в диапазоне 0-100 и прозрачность
//в диапазоне 0-0.5 (0 это абсолютно прозрачно, 1 непрозрачно)

var DrawCircles = function(){
  for (var i = 0; i < howManyCircles; i++) {
    ctx.fillStyle = 'rgba(255, 255, 255, ' + circles[i][3] + ')';
//белый цвет с прозрачностью в rgba
    ctx.beginPath();
    ctx.arc(circles[i][0], circles[i][1], circles[i][2], 0, Math.PI * 2, true);
//arc(x, y, radius, startAngle, endAngle, anticlockwise)
    ctx.closePath();
    ctx.fill();
  }
};

Хорошо, но скучновато. Почему облака стоят на месте? Давайте сделаем маленькую функцию с одним аргументом, которая сдвигает облака вниз на заданное число пикселей, и, когда определенный круг скрывается за пределами холста, он перемещается  наверх с изменением координаты X, радиуса и прозрачности:
var MoveCircles = function(deltaY){
  for (var i = 0; i < howManyCircles; i++) {
    if (circles[i][1] - circles[i][2] > height) {
//круг достигший нижнего края
//меняет параметры
      circles[i][0] = Math.random() * width;
      circles[i][2] = Math.random() * 100;
      circles[i][1] = 0 - circles[i][2];
      circles[i][3] = Math.random() / 2;
    } else {
//сдвигаем круг на deltaY пикселей вниз
      circles[i][1] += deltaY;
    }
  }
};

Теперь, не в последнюю очередь, давайте создадим основной цикл игры и подключим в нем все, что уже создали. Каждый кадр будет очищать экран, перемещать круги на 5px вниз, рисовать их и после 1/50 секунды вызывать следующий кадр. Я использую два setTimeouts вместо одного setInterval, хотя незнаю почему:). Вроде бы раньше были некоторые проблемы с производительностью в IE, что ли. И не забудьте добавить gLoopв глобальные переменныеобъявленные вначале.
var width = 320, 
//ширина холста <canvas>
  height = 500, 
//высота холста <canvas>
  gLoop,
(...) //остальная часть кода находится здесь

var GameLoop = function(){
  clear();
  MoveCircles(5);
  DrawCircles();
  gLoop = setTimeout(GameLoop, 1000 / 50);
}
GameLoop();

Благодарю Луиса Гирибоуна за комментарии к уроку. Он помог разобраться в чем отличие setTimeOut от setInterval. SetInterval запускает функцию переданную ему в аргументе не дожидаясь окончания предыдущей итерации, а setTimeOut ждет ее завершения даже если вышло время переданное в качестве второго аргумента.
Так же хочу поблагодарить пользователя под ником Ped7g за выявленные ошибки.
Результат этой части урока можно посмотреть по адресу: http://jsbin.com/odoho3, а скачать исходники тут: http://github.com/michalbe/Simple-game-with-HTML5-Canvas

Копирайты.

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