От <object> к <iframe> - другие технологии внедрения - Изучение веб-разработки

От <object> к <iframe> - другие технологии внедрения
====================================================

* Назад
* Обзор: Multimedia and embedding
* Далее

К настоящему моменту вы уже должны уметь прикреплять вложения на свои веб-страницы, включая изображения, видео и аудио. На этом этапе мы хотели бы сделать шаг в сторону, рассматривая некоторые элементы, которые позволяют встраивать в ваши веб-страницы самые разнообразные типы контента: `<iframe>` (en-US), `<embed>` и `<object>` (en-US). <iframe> предназначен для встраивания других веб-страниц, а два других позволяют встраивать PDF-файлы, SVG и даже Flash - устаревшую технологию, которую вы всё равно иногда увидите.

| Предпосылки: | Базовая компьютерная грамотность, установка базового программного обеспечения, базовые знания работы с файлами, знакомство с основами HTML (как описано в разделе Начало работы с HTML) и предыдущими статьями в этом модуле. |
| --- | --- |
| Задача: | Узнать, как встраивать элементы в веб-страницы, используя `<object>` (en-US), `<embed>` и `<iframe>` (en-US), например, флеш-ролики и другие веб-страницы |

Краткая история внедрения
-------------------------

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

Спустя некоторое время (конец 90-х, начало 2000-х годов) технологии плагинов, такие как Java-апплеты и Flash, стали очень популярными - это позволило веб-разработчикам встраивать богатый контент в веб-страницы, такие как видео и анимации, которые просто не были доступны только через HTML. Внедрение этих технологий осуществлялось посредством таких элементов, как `<object>` (en-US) и менее используемого `<embed>`, и они были очень полезны в то время. С тех пор они вышли из моды из-за многих проблем, включая доступность, безопасность, размер файла и многое другое; в наши дни большинство мобильных устройств больше не поддерживают такие плагины, и поддержка на компьютерах также уменьшается.

Наконец, появился элемент `<iframe>` (en-US) (наряду с другими способами встраивания контента, например `<canvas>`, `<video>` и т. д. ) Он позволяет встраивать целый веб-документ внутри другого, как если бы это был `<img>` или другой подобный элемент, и сегодня используется повсеместно.

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

Активное обучение: использование классического внедрения
--------------------------------------------------------

В этой статье мы собираемся перейти прямо в раздел активного обучения, чтобы сразу дать вам реальное представление о том, для чего используются технологии внедрения. Нам очень хорошо знаком Youtube, но многие не знают о некоторых доступных для него средствах совместного доступа. Давайте посмотрим, как Youtube позволяет нам встраивать видео на любую страницу, которая нам нравится, используя `<iframe>` (en-US).

1. Сначала перейдите на Youtube и найдите понравившееся вам видео.
2. Под видео вы найдёте кнопку «Поделиться» - нажмите, чтобы отобразить параметры совместного доступа.
3. Выберите кнопку «Вставить», и вам будет предоставлен код <iframe> - скопируйте его.
4. Вставьте его в поле ввода ниже и посмотрите на результат в Output.

Дополнительно вы также можете попробовать внедрить карту Google следующим образом:

1. Перейдите в Карты Google и найдите подходящую вам карту.
2. Нажмите «Меню» (три горизонтальные линии) в верхнем левом углу пользовательского интерфейса.
3. Выберите параметр Ссылка/код.
4. Выберите параметр Встраивание карт, который даст вам код <iframe> - скопируйте его.
5. Вставьте его в поле ввода ниже и посмотрите на результат в Output.

Если вы допустили ошибку, вы всегда можете сбросить её с помощью кнопки «Сброс». Если вы действительно застряли, нажмите кнопку «Показать решение», чтобы увидеть ответ.
```

<h2>Live output</h2>

<div class="output" style="min-height: 250px;"></div>

<h2>Editable code</h2>
<p class="a11y-label">
  Press Esc to move focus away from the code area (Tab inserts a tab character).
</p>

<textarea
 id="code"
 class="input"
 style="width: 95%;min-height: 100px;"></textarea>

<div class="playable-buttons">
  <input id="reset" type="button" value="Reset" />
  <input id="solution" type="button" value="Show solution" />
</div>
```

```
html {
  font-family: sans-serif;
}

h2 {
  font-size: 16px;
}

.a11y-label {
  margin: 0;
  text-align: right;
  font-size: 0.7rem;
  width: 98%;
}

body {
  margin: 10px;
  background: #f5f9fa;
}
```

```
var textarea = document.getElementById("code");
var reset = document.getElementById("reset");
var solution = document.getElementById("solution");
var output = document.querySelector(".output");
var code = textarea.value;
var userEntry = textarea.value;

function updateCode() {
  output.innerHTML = textarea.value;
}

reset.addEventListener("click", function () {
  textarea.value = code;
  userEntry = textarea.value;
  solutionEntry = htmlSolution;
  solution.value = "Show solution";
  updateCode();
});

solution.addEventListener("click", function () {
  if (solution.value === "Show solution") {
    textarea.value = solutionEntry;
    solution.value = "Hide solution";
  } else {
    textarea.value = userEntry;
    solution.value = "Show solution";
  }
  updateCode();
});

var htmlSolution =
  '<iframe width="420" height="315" src="https://www.youtube.com/embed/QH2-TGUlwu4" frameborder="0" allowfullscreen>\n</iframe>\n\n<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d37995.65748333395!2d-2.273568166412784!3d53.473310471916975!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x487bae6c05743d3d%3A0xf82fddd1e49fc0a1!2sThe+Lowry!5e0!3m2!1sen!2suk!4v1518171785211" width="600" height="450" frameborder="0" style="border:0" allowfullscreen>\n</iframe>';
var solutionEntry = htmlSolution;

textarea.addEventListener("input", updateCode);
window.addEventListener("load", updateCode);

// stop tab key tabbing out of textarea and
// make it write a tab at the caret position instead

textarea.onkeydown = function (e) {
  if (e.keyCode === 9) {
    e.preventDefault();
    insertAtCaret("\t");
  }

  if (e.keyCode === 27) {
    textarea.blur();
  }
};

function insertAtCaret(text) {
  var scrollPos = textarea.scrollTop;
  var caretPos = textarea.selectionStart;

  var front = textarea.value.substring(0, caretPos);
  var back = textarea.value.substring(
    textarea.selectionEnd,
    textarea.value.length,
  );
  textarea.value = front + text + back;
  caretPos = caretPos + text.length;
  textarea.selectionStart = caretPos;
  textarea.selectionEnd = caretPos;
  textarea.focus();
  textarea.scrollTop = scrollPos;
}

// Update the saved userCode every time the user updates the text area code

textarea.onkeyup = function () {
  // We only want to save the state when the user code is being shown,
  // not the solution, so that solution is not saved over the user code
  if (solution.value === "Show solution") {
    userEntry = textarea.value;
  } else {
    solutionEntry = textarea.value;
  }

  updateCode();
};
```

Подробно об Iframes
-------------------

Итак, это было легко и весело, не так ли? Элементы `<iframe>` (en-US) предназначены для размещения других веб-документов в текущем документе. Это отлично подходит для включения стороннего контента на ваш сайт, который, возможно, не имеет прямого контроля и не хочет реализовывать вашу собственную версию - например, видео от поставщиков онлайн-видео, системы комментариев, такие как Disqus, карты от поставщиков онлайн-карт, рекламных баннеров и т. д. Живые редактируемые примеры, которые вы использовали в этом курсе, реализованы с помощью <iframe>.

Есть несколько серьёзных Проблем безопасности при использовании <iframe>, которые мы обсудим ниже, но это не значит, что вы не должны использовать их на своих сайтах - они просто требуют некоторых знаний и тщательного обдумывания. Давайте рассмотрим код немного подробнее. Скажем, вы хотите добавить глоссарий MDN на одну из своих веб-страниц. Вы можете попробовать что-то вроде этого:
```

<iframe src="https://developer.mozilla.org/ru/docs/Glossary"
        width="100%" height="500" frameborder="0"
        allowfullscreen sandbox>
  <p> <a href="https://developer.mozilla.org/ru/docs/Glossary">
    Fallback link for browsers that don't support iframes
  </a> </p>
</iframe>
```

Этот пример включает основы, необходимые для использования <iframe>:

`allowfullscreen` (en-US)

Если установлено, <iframe> может быть помещён в полноэкранный режим с использованием полноэкранного API (что несколько выходит за рамки этой статьи).

`frameborder` (en-US)

Если установлено значение 1, это указывает браузеру нарисовать границу между этим фреймом и другими фреймами, что является поведением по умолчанию. 0 удаляет границу. Использование этого на самом деле не рекомендуется, так как тот же эффект можно улучшить, используя `border`: none; в CSS.

`src` (en-US)

Этот атрибут, как и `<video>` / `<img>`, содержит путь, указывающий на URL-адрес внедряемого документа.

`width` (en-US) and `height` (en-US)

Эти атрибуты определяют ширину и высоту, в которых вы хотите использовать iframe.

Резервный контент

Точно так же, как и другие подобные элементы, такие как `<video>`, вы можете включить резервный контент между тегами открытия и закрытия <iframe> </ iframe>, которые появятся, если браузер не поддерживает < IFRAME>. В этом случае мы включили ссылку на страницу. Вряд ли вы столкнётесь с таким браузером, который не поддерживает <iframe> в наше время.

`sandbox` (en-US)

Этот атрибут, который работает в более современных браузерах, чем остальные функции <iframe> (например, IE 10 и выше). Он запрашивает повышенные настройки безопасности. Об этом мы расскажем в следующем разделе.

**Примечание:** Чтобы повысить скорость загрузки, рекомендуется установить атрибут src в элементе iframe с помощью JavaScript после того, как основное содержимое будет загружено. Это ускорит вашу страницу и уменьшит время загрузки официальной страницы (важный показатель SEO.)

### Проблемы безопасности

Выше мы упомянули о проблемах безопасности. Давайте рассмотрим это чуть подробнее. Мы не ожидаем, что вы всё поймёте с первого раза. Мы просто хотим сообщить вам о проблеме и предоставить ссылку, чтобы вы могли вернуться к ней, когда станете более опытными и начнёте рассматривать использование iframe в своих экспериментах и работе. Кроме того, нет необходимости бояться и не использовать <iframe> - вам просто нужно быть осторожным. Продолжим...

Разработчики браузеров и веб-разработчики на горьком опыте усвоили, что iframe - частая цель (официальный термин: вектор атаки) плохих людей в Интернете (часто называемых хакерами, или, более точно, крекерами) для атаки при попытке злонамеренно изменить ваши веб-страницы или обманом заставить посетителей делать то, чего они не хотят, например, раскрыть конфиденциальную информацию вроде имени пользователя и пароли. Чтобы избежать этого, авторы спецификаций и разработчики браузеров разработали различные механизмы безопасности для обеспечения защиты <iframe>, лучшие из которых мы рассмотрим ниже.

**Примечание:** Кликджекинг – это один из видов обычной атаки iframe, когда хакеры внедряют невидимый iframe в ваш документ (или внедряют ваш документ на свой собственный вредоносный веб-сайт) и используют его для захвата взаимодействия пользователей. Это обычный способ ввести пользователей в заблуждение или украсть конфиденциальные данные.

Быстрый пример - попробуйте загрузить предыдущий пример, который мы показали выше, в ваш браузер (вы можете найти его живой пример на Github (см. Также исходный код). На самом деле, вы ничего не увидите на странице, т.к. если вы посмотрите в консоль в инструментах разработчика браузера, вы увидите сообщение, объясняющее вам, почему. В Firefox вы получите сообщение *«Отказано в доступе» в связи с X-Frame-Options: `https://developer.mozilla.org/ru/docs/Glossary` не разрешает кадрирование*. Это связано с тем, что разработчики, которые построили MDN, включили параметр на сервере, который обслуживает страницы веб-сайта, запрещая им внедряться внутри <iframe> (см. Настройка директивы CSP ниже). Суть здесь такова - целой странице MDN на самом деле нет смысла встраиваться в другие страницы - конечно, если вы не хотите сделать что-то вроде встраивания их на свой сайт и выставлять их как свои собственные; или пытаться украсть данные с помощью clickjacking, что очень плохо. Плюс, если все начнут это делать, вся дополнительная пропускная способность начнёт стоить Mozilla больших денег.

#### Используйте только при необходимости

Иногда имеет смысл вставлять сторонний контент - например, видео и карты, но вы избежите головной боли, если будете вставлять сторонний контент только тогда, когда это абсолютно необходимо. Хорошее эмпирическое правило для веб-безопасности: «Вы никогда не можете быть слишком осторожным. Если вы что-то сделали, дважды проверьте это. Если кто-то другой сделал это, считайте, что это опасно, пока не будет доказано обратное».

Помимо безопасности, вы также должны знать об интеллектуальной собственности. Большинство контента находится под защитой авторских прав, даже тот, от которого вы не могли ожидать (например, большинство картинок на Wikimedia Commons). Никогда не выводите контент на свою страницу, если он вам не принадлежит или если нет однозначного письменного разрешения от правообладателя. Наказания за нарушения авторских прав строги. И, повторимся, вы никогда не можете быть слишком осторожными.

Если контент лицензирован, вы должны соблюдать условия лицензии. Например, контент на MDN лицензирован на licensed under CC-BY-SA. Это означает, что вы должны относиться к нам с уважением, когда цитируете наш контент, даже если внесли в него существенные изменения.

#### Используйте HTTPS

HTTPS это зашифрованная версия HTTP. Вы должны обслуживать свои веб-сайты, используя HTTPS, всегда, когда это возможно :

1. HTTPS уменьшает вероятность того, что контент был изменён по пути;
2. HTTPS запрещает доступ внедрённого контента к контенту в вашем исходном документе и наоборот.

Использование HTTPS требует сертификат безопасности, что может обходиться в копеечку (хотя есть Let's Encrypt, что облегчает задачу). Если вы не можете его получить, вы можете отдавать свой родительский документ с помощью HTTP. Однако, из-за второго преимущества HTTPS *во что бы то ни стало* вы не должны внедрять сторонний контент с HTTP. (В лучшем случае ваш браузер выдаст угрожающее предупреждение.) Все уважаемые компании, которые делают контент доступным для внедрения через <iframe>, доступны через HTTPS - посмотрите URL-адреса внутри <iframe> src при встраивании, например, содержимого из Карт Google или Youtube.

**Примечание:** Github pages позволяют предоставлять контент через HTTPS по умолчанию, поэтому это полезно для размещения контента. Если вы используете другой хостинг и не уверены, спросите хостинг-провайдера об этом.

#### Всегда используйте атрибут `sandbox`

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

Контент, не ограниченный sandbox, может сделать слишком многое (выполнение JavaScript, отправка форм, всплывающие окна и т. д.). По умолчанию включайте все возможные ограничения, используя атрибут `sandbox` без параметров, как показано в предыдущем примере.

Если это необходимо, вы можете добавлять разрешения один за другим (внутри значения атрибута `sandbox=""`) — смотри `sandbox` (en-US) ссылка для всех доступных опций. Важно отметить, что вы *никогда* не должны добавлять атрибуты `allow-scripts` и `allow-same-origin` в свой `sandbox` атрибут одновременно — в таком случае, встроенный контент может обходить политику безопасности, которая запрещает сайтам выполнять скрипты и использовать JavaScript для отключения "песочницы" sandbox .

**Примечание:** "Песочница" не обеспечивает защиту, если злоумышленники могут обманывать людей через прямое посещение вредоносного контента (вне iframe). Если есть вероятность, что определённый контент может быть вредоносным (например, созданный пользователями контент), пожалуйста, используйте его из другого domain на ваш основной сайт.

#### Настройка директив CSP

CSP означает **политику безопасности контента** и обеспечивает набор заголовков HTTP (en-US) (метаданные, отправленные вместе с вашими веб-страницами, когда они обслуживаются с веб-сервера), предназначенных для улучшения безопасности вашего HTML-документа. Когда дело доходит до обеспечения безопасности `<iframe>`, вы можете *настроить сервер для отправки соответствующего `X-Frame-Options` заголовка. (en-US)* Это может помешать другим веб-сайтам встраивать ваш контент на их веб-страницы (что позволило бы использовать кликджекинг и множество других атак), что и было сделано разработчиками MDN, как мы видели ранее.

**Примечание:** Вы можете прочитать пост Фредерика Брауна On the X-Frame-Options Security Header для более детальной информации по теме. Разумеется, объяснение в этой статье далеко не полное.

Элементы <embed> и <object>
---------------------------

В отличие от `<iframe>` (en-US), элементы `<embed>` и `<object>` (en-US) выполняют другую функцию. Они являются инструментами общего назначения для встраивания нескольких типов внешнего контента, включая плагиновые технологии, такие как Java Applets и Flash, PDF (которые могут отображаться в браузере с плагином PDF) и даже такой контент, как видео, SVG и изображения!

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

Тем не менее, вы вряд ли будете использовать эти элементы очень часто. Апплеты не использовались годами, Flash в настоящее время не очень популярен из-за ряда причин (см. Дело против плагинов, ниже), PDF-файлы, как правило, лучше открывать по ссылке, а другой контент - такой, как изображения и видео, могут обрабатываться намного проще. Плагины и эти методы внедрения действительно являются устаревшими технологиями, и мы упоминаем их здесь на случай, если вы столкнётесь с ними в определённых обстоятельствах, таких как интрасети или корпоративные проекты.

Если вам нужно внедрить контент плагина, ниже исчерпывающая информация, которая вам понадобится:

|  | `<embed>` | `<object>` (en-US) |
| --- | --- | --- |
| URL встраиваемого контента | `src` | `data` (en-US) |
| *точный* media type встраиваемого контента | `type` | `type` (en-US) |
| высота и ширина (в пикселях) элемента, управляемого плагином | `height` `width` | `height` (en-US) `width` (en-US) |
| имена и значения, предоставляемые плагину в качестве параметров | Особые атрибуты,с их именами и значениями | одиночные элементы `<param>` (en-US), находящиеся внутри `<object>` |
| независимый HTML-контент в качестве резерва для отсутствующего ресурса | не поддерживается (`<noembed>` является устаревшим) | содержится внутри `<object>`, после элементов `<param>` |

**Примечание:** Элементу `<object>` необходим атрибут `data` , атрибут `type` , или оба сразу. Если вы используете их вместе, вы также можете использовать атрибут `typemustmatch` (en-US) (имеющийся в наличии только в Firefox, на момент написания данной статьи). Атрибут `typemustmatch` предотвращает запуск файла, только если в в атрибут type не записан соответствующий медиа-тип. Следовательно, атрибут `typemustmatch` может предоставлять значительные преимущества в безопасности в случае встраивания контента из других источников origin (Таким образом, не давая возможности злоумышленникам запускать произвольные скрипты посредством плагинов).

Ниже представлен пример использования элемента `<embed>` для вставки Flash-фильма (загляните на live on Github, а также на check the source code):

```html
<embed
 src="whoosh.swf"
 quality="medium"
 bgcolor="#ffffff"
 width="550"
 height="400"
 name="whoosh"
 align="middle"
 allowScriptAccess="sameDomain"
 allowFullScreen="false"
 type="application/x-shockwave-flash"
 pluginspage="http://www.macromedia.com/go/getflashplayer" />
```

Достаточно ужасно, не так ли? Html-код, генерируемый Flash, имел склонность быть значительно хуже. Он использовал элемент `<object>` вместе со встроенным элементом `<embed>` для скрытия всего фундамента (взгляните на пример). Flash ранее использовался в качестве резерва для HTML5-видео (в случае его отсутствия), но со временем необходимость в этом отпала.

Давайте взглянем на пример `<object>` , встраивающего PDF в страницу (взгляните live example и source code):

```html
<object
 data="mypdf.pdf"
 type="application/pdf"
 width="800"
 height="1200"
 typemustmatch>
  <p>
    You don't have a PDF plugin, but you can
    <a href="mypdf.pdf">download the PDF file.</a>
  </p>
</object>
```

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

### Дело против плагинов

Когда-то плагины были незаменимы в Интернете. Помните дни, когда вам приходилось устанавливать Adobe Flash Player для просмотра онлайн-фильма? И потом постоянно возникали раздражающие предупреждения об обновлении Flash Player и Java Runtime Environment. С тех пор веб-технологии стали намного надёжнее. Почти всем сервисам пришло время прекратить доставлять контент с помощью плагинов и вместо этого использовать веб-технологии.

* **Расширьте свою досягаемость для всех**. У каждого есть браузер, но плагины используются все реже, особенно среди мобильных пользователей. Поскольку Web в значительной степени можно использовать без плагинов, люди предпочли бы просто перейти на сайты ваших конкурентов, чем установить плагин.
* **Немного передохните от лишних головных болей, связанных с общедоступностью Flash-плагинов и др.( extra accessibility headaches).**
* **Избегайте лишних проблем безопасности.** Ни для кого не секрет,что Adobe Flash является небезопасным, даже после многочисленных патчей. В 2015, Алекс Стэймос (бывший главный сотрудник по вопросам информационной безопасности компании Facebook) даже делал запрос, чтобы Adobe прекратил поддержку Flash.

Итак, что нужно делать? Если вам нужна интерактивность, HTML и JavaScript могут легко выполнить задание для вас без необходимости использования апплетов Java или устаревшей технологии ActiveX / BHO. Вместо того, чтобы полагаться на Adobe Flash, вы можете использовать видео HTML5 для своих медиа-потребностей, SVG для векторной графики и Canvas для сложных изображений и анимаций. Питер Элст уже писал несколько лет назад, что Adobe Flash редко является подходящим инструментом для работы, за исключением специализированных игр и бизнес-приложений. Что касается ActiveX, браузер Microsoft Edge (en-US) больше не поддерживает его.

Заключение
----------

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

Существует много других технологий, которые включают в себя внедрение внешнего контента, помимо тех, которые мы обсуждали здесь. Мы видели некоторые из них в предыдущих статьях, например `<video>`, `<audio>` и `<img>`, но есть и другие. Например, `<canvas>` для 2D-и 3D-графики, сгенерированной JavaScript, и `<svg>` для встраивания векторной графики. Мы рассмотрим SVG в следующей статье модуля.

* Назад
* Обзор: Multimedia and embedding
* Далее


Проверьте свои знания: Изображения в HTML - Изучение веб-разработки

Проверьте свои знания: Изображения в HTML
=========================================

Цель этого теста навыков - оценить, поняли ли вы нашу статью Изображения в HTML.

**Примечание:** Вы можете опробовать решения в интерактивных редакторах ниже, однако может быть полезно загрузить код и использовать онлайн-инструмент, такой как CodePen, jsFiddle или Glitch для работы с задачами.

Изображения в HTML №1
---------------------

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

* Добавьте путь к изображению в соответствующий атрибут, чтобы встроить его на страницу. Изображение называется `blueberries.jpg` и оно находится в папке с именем `images` внутри текущей папки.
* Добавьте альтернативный текст к соответствующему атрибуту, чтобы описать изображение для людей, которые его не видят.
* Дайте элементу `<img>` соответствующие значения `width` и `height` чтобы он отображался с правильным соотношением сторон и достаточно места на странице для отображения. Размер изображения 615 x 419 пикселей.

Попробуйте обновить живой код ниже, чтобы воссоздать готовый пример:

**Примечание:** Загрузите файл для этой задачи, чтобы работать в вашем редакторе или в онлайн-редакторе.

Изображения в HTML №2
---------------------

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

Попробуйте обновить живой код ниже, чтобы воссоздать законченный пример:

**Примечание:** Загрузите файл для этой задачи, чтобы работать в вашем редакторе или в онлайн-редакторе.

Изображения в HTML №3
---------------------

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

Попробуйте обновить живой код ниже, чтобы воссоздать готовый пример:

**Примечание:** Загрузите файл для этой задачи, чтобы работать в вашем редакторе или в онлайн-редакторе.

Оценка или дополнительная помощь
--------------------------------

Вы можете попрактиковаться с этими примерами в интерактивных редакторах выше.

Если вы хотите, чтобы ваша работа была оценена, или если вы застряли и хотите обратиться за помощью:

1. Поместите свою работу в онлайн-редактор, например CodePen, jsFiddle или Glitch. Вы можете написать код самостоятельно или использовать файлы, ссылки на которые приведены в приведённых выше разделах.
2. Напишите сообщение с просьбой об оценке и / или помощи в MDN Discourse forum Learning category. Ваш пост должен включать:
    * Описательный заголовок, например "Требуется оценка для проверки навыков 1 по основам изображений HTML".
    * Подробная информация о том, что вы уже пробовали, и что бы вы хотели, чтобы мы сделали, например если вы застряли и нуждаетесь в помощи или хотите пройти оценку.
    * Ссылка на пример, который вы хотите оценить или с которым вам нужна помощь, в онлайн-редакторе (как указано в шаге 1 выше). Это хорошая практика - очень сложно помочь кому-то с проблемой кодирования, если вы не видите его код.
    * Ссылка на страницу фактического задания или оценки, чтобы мы могли найти вопрос, в котором вам нужна помощь.


Ввод в разработку Web-игр - Разработка игр

Ввод в разработку Web-игр
=========================

Современный web позволяет не только передавать различную информацию, но и создавать интерактивный контент. Например, потрясающие, высококачественные игры.

Диапазон игр, которые вы можете встретить в web поражает и не уступает "нативным" играм, реализованным с использованием языка программирования c++ и java.Причём это касается не только относительно небольших игр, но и объёмных игр жанра РПГ, 3d шутерах и многом другом. Это уже не аналоги простых карточных игр или многопользовательских социальных играх, реализованных с помощью Flash®, а гораздо более сложные вещи. Благодаря значительным улучшениям языка программирования JavaScript и появлению новых API браузера, вы можете создавать игры, не зависящие от операционной системы. Для их работы необходим только браузер. А иногда, например на устройствах с поддержкой HTML5, таких как Firefox OS, не нужен даже он.

Игровая платформа HTML5
-----------------------

Вы действительно можете подумать, что Web - лучшая платформа для вашей игры. Как мы любим говорить:"Web - это тоже платформа." Давайте посмотрим на главные аспекты Web платформы:

| Функционал | Технология |
| --- | --- |
| **Аудио** | Web Audio API (en-US) |
| **Графика** | WebGL (OpenGL ES 2.0) |
| **Ввод** | Touch events (en-US), Gamepad API (en-US), датчики устройства, WebRTC (en-US), Full Screen API (en-US), Pointer Lock API (en-US) |
| **Язык** | JavaScript (или C/C++ используйте Emscripten для компиляции в JavaScript) |
| **Сеть** | WebRTC (en-US) и/или WebSockets |
| **Данные** | IndexedDB или "облако" |
| **Веб** | HTML, CSS, SVG (en-US), Social API (и многое другое!) |

Экономическое обоснование
-------------------------

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

1. Охват паутины огромен, она повсюду. Игры, построенные на HTML5, работают на смартфонах, планшетах, ПК и смарт-телевизорах.
2. Маркетинг и открытость улучшаются. Вы не ограничиваетесь продвижением своего приложения в чужом магазине приложений. Вместо этого вы можете рекламировать и продвигать свою игру по всему интернету, а также в других средствах массовой информации, используя преимущества присущей сети связности и доступности для новых клиентов.
3. У вас есть контроль, где это имеет значение: Платежи. Вы не должны отдавать 30% своих доходов кому-то другому только потому, что ваша игра в их экосистеме. Вместо этого, взимать плату, что вы хотите, и использовать любую услугу обработки платежей вам нравится.
4. Опять же, с большим контролем, вы можете обновить игру, когда захотите. Не жди, затаив дыхание, одобрения, пока кто-то прячется внутри другого.
5. Контролируйте свою аналитику! Вместо того чтобы полагаться на кого-то другого в принятии решений о том, какая аналитика вам нужна, вы можете собрать свою собственную-или выбрать третью сторону, которая вам больше всего нравится, - чтобы собрать информацию о ваших продажах и досягаемости вашей игры.
6. Вы можете управлять своими отношениями с клиентами более тесно, по-своему. Больше не придётся работать с обратной связью магазина приложений. Взаимодействуйте со своими клиентами так, как вы хотите, без посредника.
7. Ваши игроки могут играть в вашу игру в любом месте, в любое время. Поскольку Web распространён повсеместно, ваши клиенты могут проверить статус своей игры на своих телефонах, планшетах, домашних ноутбуках, рабочих столах или на чем-либо ещё.
Web-технологии для разработчиков игр
------------------------------------

Давайте покопаемся в API веба, которое приносит на стол и обслуживает разработчиков игр. Вот подробный список, чтобы дать вам представление о том, что Web может сделать для вас:

Full Screen API (en-US)

Этот простой API позволяет вашей игре использовать весь экран, тем самым погружая игрока в действие.

Gamepad API (en-US)

Если вы хотите, чтобы ваши пользователи могли использовать геймпады и прочие игровые контроллеры для работы с игрой, вам потребуется этот API

HTML и CSS

Эти технологии помогут вам создать и разместить UI вашей игры, а HTML-элемент `<canvas>` это один из способов создать 2D-графику

HTML audio (en-US)

Элемент `<audio>` позволяет легко воспроизводить простые звуковые эффекты и музыку. Если ваше потребности выше, ознакомьтесь с Web Audio API для полной мощности обработки звука!

IndexedDB

Мощный API для хранения пользовательских данных на собственном компьютере или устройстве. Отличный способ локально сохранить состояние игры и другую информацию, без необходимости подгружать её каждый раз при необходимости. Также полезно для того, чтобы сделать ваш проект играбельным, даже если пользователь не подключён к Интернету (например, когда он оказался в самолёте на несколько часов).

JavaScript

JavaScript, язык программирования, используемый в Интернете, быстро развивается в современных браузерах и становится ещё быстрее. Используйте его возможности для написания кода своей игры или используйте такие технологии, как Emscripten или Asm.js, чтобы с лёгкостью переносить существующие игры.

Pointer Lock API (en-US)

API Pointer Lock позволяет блокировать мышь или другое указывающее устройство в интерфейсе вашей игры. Вместо абсолютного позиционирования курсора вы получаете координаты дельты, которые дают вам более точные измерения того, что делает пользователь, и предотвращают случайную отправку ввода где-то ещё, тем самым упуская важные пользовательские действия.

SVG (en-US) (масштабируемая векторная графика)

Позволяет создавать векторную графику, которая плавно масштабируется независимо от размера или разрешения дисплея пользователя.

Typed Arrays (en-US)

Типизированные массивы JavaScript дают вам доступ к необработанным двоичным данным из кода, что позволяет вам манипулировать текстурами GL, игровыми данными или чем-то ещё, даже если код не в формате JavaScript.

Web Audio API (en-US)

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

WebGL

Позволяет создавать высокопроизводительную аппаратно-ускоренную 3D (и 2D) графику из веб-контента. Это веб-реализация OpenGL ES 2.0.

WebRTC (en-US)

API WebRTC (Real-Time Communications) даёт вам возможность управлять аудио- и видеоданными, включая телеконференции и передачу данных из других приложений между двумя пользователями. Хотите, чтобы ваши игроки могли общаться друг с другом, взрывая монстров? Это API для вас!

WebSockets

The WebSocket API позволяет подключить ваше приложение или сайт к серверу для передачи данных в реальном времени. Идеально подходит для многопользовательских игр, чатов и т. д.

Web Workers

Web Workers даёт вам возможность создавать фоновые потоки, выполняющие собственный код JavaScript, используя преимущества современных многоядерных процессоров.

XMLHttpRequest (en-US) и File API

Комбинация XMLHttpRequest и File API позволяет отправлять и получать любые нужные для вас данные (не позволяйте «XML» выкинуть вас!) с веб-сервера. Это отличный способ сделать что угодно: от загрузки новых игровых уровней и иллюстраций, до передачи информации о статусе игры в режиме non-real-time и обратно.


Уроки - Разработка игр

Уроки
=====

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

2D игра Breakout на чистом JavaScript (en-US)

В этом пошаговом руководстве вы сможете реализовать простой клон игры Breakout с использованием чистого JavaScript. Попутно вы узнаете основы использования элемента `<canvas>` для реализации фундаментальной игровой механики, такой как рендеринг и движущиеся изображения, обнаружение столкновения, механизмы управления и выигрышные и проигрышные состояния.

2D-игра Breakout с использованием Phaser (en-US)

В этом пошаговом руководстве вы будете использовать тот же самый клон Breakout, что и предыдущая серия уроков, за исключением того, что на этот раз вы сделаете это, используя HTML5 игровой фреймворкPhaser. Идея состоит в том, чтобы научить некоторым основам (и преимуществам) работы с фреймворками наряду с фундаментальной игровой механикой.

2D-игра Лабиринт с применением ориентации устройства (en-US)

В этом учебном пособии показано, как создать 2D-игру Лабиринт с использованием HTML5, включая основы, такие как обнаружение столкновения и размещение спрайтов на `<canvas>`. Это мобильная игра, в которой используются **API** Ориентация устройства и Вибрация (en-US) для улучшения игрового процесса и построенная с использованием фреймворка Phaser.

2D-игра платформер с использованием Phaser

В этой серии уроков показано, как создать простую платформенную игру с использованием Phaser, освещаются такие основы, как спрайты, столкновения, физика, коллекции и многое другое.


Анатомия видеоигры - Разработка игр

Анатомия видеоигры
==================

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

Показать, получить, преобразовать, вычислить, повторить
-------------------------------------------------------

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

Особенности игр.

Некоторые игры управляют своим циклом при помощи пользовательского ввода. Представьте, что вы разрабатываете игру типа *"найди разницу между этими двумя похожими картинками"*. Такого рода игры **показывают** пользователю две картинки; они **получают** их клики (или касания); они **преобразуют** ввод в успешный , не успешный, пауза, работа с меню, и так далее; в конечном итоге, в зависимости от данных действий, они **вычисляют** обновлённое состояние сцены. Игровой цикл продвигается пользовательскими действиями и "спит" пока таковые отсутствуют. Это пример так называемой пошаговой игры, которая не зависит от постоянного обновления каждого кадра, а только от действий пользователя.

Другие игры требуют контроля над каждым из минимально возможных индивидуальных временных интервалов. Те же принципы, что и выше, применяются с небольшим изменением: каждый кадр анимации продолжает цикл, и любое изменение пользовательского ввода фиксируется на первом доступном ходе. Эта покадровая модель реализована в так называемом **основном цикле**. Если ваша игра зацикливается на времени, то это будет её полномочия, которые будут соблюдать ваши симуляции.

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

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

Построение основного цикла в JavaScript
---------------------------------------

Лучше всего JavaScript работает с событиями и callback функциями. Современные браузеры стремятся вызывать методы по мере необходимости и бездействовать (или выполнять другие задачи) в промежутках. Привязать код к моменту, который для него подходит — это отличная идея. Подумайте о том, действительно ли ваша функция должна вызываться на строго определённом интервале времени, в каждом кадре или только после того, как произойдёт что-то ещё. Подумайте о том, действительно ли функцию нужно вызывать в определённом интервале времени, на каждый кадр или только после того, как что-то произойдёт. Больше конкретики с браузером в том, когда функция должна быть вызвана, позволяет ему лучше оптимизировать этот процесс. Так же, вероятно, это облегчит вам работу.

Некоторый код должен выполняться кадр за кадром, так зачем же прикреплять эту функцию к чему-то другому, кроме графика перерисовки браузера? В Web, ``window.requestAnimationFrame()`` будет основой большинства хорошо запрограммированных покадровых основных циклов. Callback функция должна быть передана ему при вызове. Callback функция будет выполнена в подходящее время перед следующей перерисовкой. Вот пример простого основного цикла:

```js
window.main = function () {
  window.requestAnimationFrame(main);

  // Код, который цикл должен выполнить
};

main(); // Start the cycle
```

**Примечание:** В каждом из методов `main()`, обсуждаемых здесь, мы планируем новый requestAnimationFrame перед выполнением нашего содержимого цикла. Это не случайно и считает лучшей практикой. Ранний вызов следующего `requestAnimationFrame` гарантирует, что браузер получит его вовремя, чтобы спланировать соответствующим образом, даже если ваш текущий кадр пропустит своё окно VSync.

Приведённый выше фрагмент кода содержит два оператора. Первый оператор создаёт функцию как глобальную переменную с именем `main()`.Эта функция выполняет некоторую работу, а также сообщает браузеру, что нужно вызвать следующий кадр с помощью `window.requestAnimationFrame()`. Второй оператор вызывает функцию `main()`, описанную в первом операторе. Поскольку `main()` вызывается один раз во втором операторе и каждый его вызов помещает себя в очерёдность действий, чтобы отрисовать следующий кадр, `main()` синхронизируется с вашей частотой кадров.

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

Синхронизация основного цикла с тем, когда браузер рисует на дисплее, позволяет запускать цикл так часто, как браузер хочет рисовать. Вам предоставляется контроль над каждым кадром анимации. Это также очень просто, потому что `main()` - единственная функция, которая зацикливается. Шутер от первого лица (или подобная игра) представляет новую сцену один раз в каждом кадре. Вы не можете добиться большей плавности и быстродействия.

Но не стоит сразу предполагать, что анимация требует покадрового управления. Простые анимации можно легко выполнять даже с ускорением на GPU с помощью CSS-анимации и других инструментов, включённых в браузер. Их очень много и они сделают вашу жизнь проще.

Создание улучшенного основного цикла в JavaScript
-------------------------------------------------

У нашего цикла есть две очевидные проблемы: `main()` загрязняет ``window`` объект (в нем хранятся все глобальные переменные) и код не оставляет нам возможность остановить цикл, если только вся вкладка не будет закрыта или обновлена. Для решения первой проблемы, если нужно, чтобы основной цикл просто выполнялся и вам не нужен лёгкий (прямой) доступ к нему, вы можете поместить его внутрь самовызывающейся Function Expression (IIFE).

```js
/\*
 \* Начинаем с точки с запятой в случае, если какая-либо строка кода выше данного примера
 \* полагается на автоматическую вставку точки с запятой (ASI). Браузер может случайно решить,
 \* что весь этот код начинается с предыдущей строки. Первая точка с запятой отмечает начало
 \* новой строки, если предыдущая не была пустой или завершённой.
 \*/

(function () {
  function main() {
    window.requestAnimationFrame(main);

    // Содержание вашего основного цикла
  }

  main(); // Вызов цикла
})();
```

Когда браузер наткнётся на IIFE (Immediately Invoked Function Expression), он определит основной цикл и сразу же поставит его в очередь для следующего кадра. Он не будет привязан ни к какому объекту, и `main` (или `main()` для методов) будет неиспользуемым именем, доступным в остальной части приложения для определения чего-то другого.

**Примечание:** На практике распространено предотвращать следующий `requestAnimationFrame()` используя оператор if вместо вызова `cancelAnimationFrame()`.

Чтобы остановить основной цикл, вам понадобиться отменить вызов `main()` с помощью ``window.cancelAnimationFrame()``. Необходимо передать в `cancelAnimationFrame()` идентификатор последнего вызова `requestAnimationFrame()`. Давайте предположим, что функции и переменные вашей игры были определены в пространстве имён, которое вы назвали `MyGame`. В таком случае, основной цикл будет выглядеть следующим образом:

```js
/\*
 \* Начинаем с точки с запятой в случае, если какая-либо строка кода выше данного примера
 \* полагается на автоматическую вставку точки с запятой (ASI). Браузер может случайно решить,
 \* что весь этот код начинается с предыдущей строки. Первая точка с запятой отмечает начало
 \* новой строки, если предыдущая не была пустой или завершённой.
 \*
 \* Давайте также предположим, что MyGame уже определена.
 \*/

(function () {
  function main() {
    MyGame.stopMain = window.requestAnimationFrame(main);

    // Содержание вашего основного цикла
  }

  main(); // Вызов цикла
})();
```

Теперь у нас есть переменная `stopMain`, объявленная в нашем пространстве имён `MyGame`, которая содержит идентификатор последнего вызова `requestAnimationFrame()` нашего основного цикла. В любой момент мы может остановить основной цикл, сказав браузеру, чтобы тот отменил запрос, соответствующий последнему маркеру.

```js
window.cancelAnimationFrame(MyGame.stopMain);
```

Ключ к программированию основного цикла в JavaScript заключается в том, чтобы прикрепить его к любому событию, которое должно управлять вашими действиями, и обращать внимание на то, как различные системы участвуют во взаимодействии. У вас может быть несколько компонентов, управляемых несколькими различными типами событий. Это может показаться излишним усложнением, но также может быть просто хорошей оптимизацией (не обязательно, конечно). Проблема в том, что вы не выстраиваете типичный основной цикл. В JavaScript вы используйте основной цикл браузера и стараетесь сделать это эффективно.

Построение *более оптимизированного* основного цикла в JavaScript
-----------------------------------------------------------------

В конце контов, в JavaScript браузер выполняет свой собственный основной цикл, и ваш код существует на некоторых его этапах. В приведённых выше разделах описываются основные циклы, которые стараются не отнимать контроль у браузера. Их методы прикрепляют себя к `window.requestAnimationFrame(),` который запрашивает контроль над предстоящим кадром у браузера. Браузер решает, как связать эти запросы с их основным циклом. Спецификация W3C для requestAnimationFrame на самом деле точно не определяет, когда браузеры должны выполнять колбэки `requestAnimationFrame`. Это может быть преимуществом, поскольку позволяет поставщикам браузеров свободно экспериментировать с решениями, которые они считают лучшими, и настраивать их с течением времени.

Современные версии Firefox и Google Chrome (вероятно, и другие) *пытаются* подключить колбэки `requestAnimationFrame` к своему основному потоку в самом начале временного интервала фрейма\*.\* Таким образом основной поток браузера *пытается* выглядеть следующим образом:

1. Запустить новый кадр (пока предыдущий обрабатывается на дисплее.).
2. Пройтись по колбэкам `requestAnimationFrame` и вызвать их.
3. Выполнить сборку мусора и другие задачи для каждого кадра, когда вышеупомянутые колбэки перестают контролировать основной поток.
4. Спать (если только какое-либо событие не прервёт сон браузера) до тех пор, пока монитор не будет готов к вашему изображению (VSync), и повторить его.

Вы можете думать о разработке realtime applications, как о запасе времени для работы. Все вышеперечисленные шаги должны выполняться каждые 16 с половиной миллисекунд, чтобы не отставать от дисплея с частотой 60Гц. Браузеры вызывают ваш код таким образом, чтобы предоставить ему максимум времени для вычислений. Ваш основной поток часто запускает рабочие нагрузки, которые даже не находятся в основном потоке (Например, растеризация или шейдеры в WebGL). Большие вычисления могут выполняться на Web Worker-e или GPU одновременно с тем, как браузер использует свой основной поток для управления сборкой мусора, обработки асинхронных вызовов или других задач.

Пока мы обсуждаем распределение нашего временного бюджета, многие браузеры имеют инструмент под названием *High Resolution Time. Объект* `Date` больше не используется в качестве основного метода синхронизации событий, поскольку он очень не точен и может быть изменён системными часами. High Resolution Time, с другой стороны, подсчитывает количество миллисекунд начиная с `navigationStart` (при выгрузке предыдущего документа). Это значение возвращается в виде десятичного числа с точностью до миллисекунды. Он известен как `DOMHighResTimeStamp`, но для всех целей и задач считайте его числом с плавающей запятой.

**Примечание:** Системы (аппаратные или программные), которые не могу обеспечить точность в микросекундах, могут по крайней мере обеспечить точность в миллисекундах. Однако, они должны обеспечивать точность до 0,001 мс, если способны на это.

Это значение нельзя использовать само по себе, потому что оно относиться к неинтересному событию, но его можно вычесть из другой временной ветки, чтобы чётко и точно определить, сколько времени прошло между этими двумя точками. Чтобы получить одну из этих временных меток, вы можете вызвать `window.performance.now()` и сохранить результат в переменную.

```js
var tNow = window.performance.now();
```

Возвращаемся к основному циклу. Часто вам понадобиться узнать, когда ваша основная функция была вызвана. Это обычное дело, `window.requestAnimationFrame()` при выполнении всегда предоставляет метку `DOMHighResTimeStamp` в качестве аргумента для колбэк-функций. Это приводит к очередному улучшению нашего основного цикла.

```js
/\*
 \* Начинаем с точки с запятой в случае, если какая-либо строка кода выше данного примера
 \* полагается на автоматическую вставку точки с запятой (ASI). Браузер может случайно решить,
 \* что весь этот код начинается с предыдущей строки. Первая точка с запятой отмечает начало
 \* новой строки, если предыдущая не была пустой или завершённой.
 \*
 \* Давайте также предположим, что MyGame уже определена.
 \*/

(function () {
  function main(tFrame) {
    MyGame.stopMain = window.requestAnimationFrame(main);

    // Содержимое вашего основного цикла
    // tFrame, из "function main ( tFrame )", это DOMHighResTimeStamp предоставленный requestAnimationFrame.
  }

  main(); // Начало цикла
})();
```

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

Several other optimizations are possible and it really depends on what your game attempts to accomplish. Your game genre will obviously make a difference but it could even be more subtle than that. You could draw every pixel individually on a canvas or you could layer DOM elements (including multiple WebGL canvases with transparent backgrounds if you want) into a complex hierarchy. Each of these paths will lead to different opportunities and constraints.

It is decision... time
----------------------

You will need to make hard decisions about your main loop: how to simulate the accurate progress of time. If you demand per-frame control then you will need to determine how frequently your game will update and draw. You might even want update and draw to occur at different rates. You will also need to consider how gracefully your game will fail if the user's system cannot keep up with the workload. Let us start by assuming that you will handle user input and update the game state every time you draw. We will branch out later.

**Примечание:** Changing how your main loop deals with time is a debugging nightmare, everywhere. Think about your needs carefully before working on your main loop.

### What most browser games should look like

If your game can hit the maximum refresh rate of any hardware you support then your job is fairly easy. You can simply update, render, and then do nothing until VSync.

```js
/\*
 \* Starting with the semicolon is in case whatever line of code above this example
 \* relied on automatic semicolon insertion (ASI). The browser could accidentally
 \* think this whole example continues from the previous line. The leading semicolon
 \* marks the beginning of our new line if the previous one was not empty or terminated.
 \*
 \* Let us also assume that MyGame is previously defined.
 \*/

(function () {
  function main(tFrame) {
    MyGame.stopMain = window.requestAnimationFrame(main);

    update(tFrame); // Call your update method. In our case, we give it rAF's timestamp.
    render();
  }

  main(); // Start the cycle
})();
```

If the maximum refresh rate cannot be reached, quality settings could be adjusted to stay under your time budget. The most famous example of this concept is the game from id Software, RAGE. This game removed control from the user in order to keep its calculation time at roughly 16ms (or roughly 60fps). If computation took too long then rendered resolution would decrease, textures and other assets would fail to load or draw, and so forth. This (non-web) case study made a few assumptions and tradeoffs:

* Each frame of animation accounts for user input.
* No frame needs to be extrapolated (guessed) because each draw has its own update.
* Simulation systems can basically assume that each full update is ~16ms apart.
* Giving the user control over quality settings would be a nightmare.
* Different monitors input at different rates: 30 FPS, 75 FPS, 100 FPS, 120 FPS, 144 FPS, etc.
* Systems that are unable to keep up with 60 FPS lose visual quality to keep the game running at optimal speed (eventually it outright fails, if quality becomes too low.)
### Other ways to handle variable refresh rate needs

Other methods of tackling the problem exist.

One common technique is to update the simulation at a constant frequency and then draw as much (or as little) of the actual frames as possible. The update method can continue looping without care about what the user sees. The draw method can view the last update and when it happened. Since draw knows when it represents, and the simulation time for the last update, it can predict a plausible frame to draw for the user. It does not matter whether this is more frequent than the official update loop (or even less frequent). The update method sets checkpoints and, as frequently as the system allows, the render method draws instants of time around them. There are many ways to separate the update method in web standards:

* Draw on `requestAnimationFrame` and update on a `window.setInterval` (en-US) or `window.setTimeout` (en-US).
    + This uses processor time even when unfocused or minimized, hogs the main thread, and is probably an artifact of traditional game loops (but it is simple.)
* Draw on `requestAnimationFrame` and update on a `setInterval` or `setTimeout` in a Web Worker (en-US).
    + This is the same as above, except update does not hog the main thread (nor does the main thread hog it). This is a more complex solution, and might be too much overhead for simple updates.
* Draw on `requestAnimationFrame` and use it to poke a Web Worker containing the update method with the number of ticks to compute, if any.
    + This sleeps until `requestAnimationFrame` is called and does not pollute the main thread, plus you are not relying on old fashioned methods. Again, this is a bit more complex than the previous two options, and *starting* each update will be blocked until the browser decides to fire rAF callbacks.

Each of these methods have similar tradeoffs:

* Users can skip rendering frames or interpolate extra ones depending on their performance.
* You can count on all users updating non-cosmetic variables at the same constant frequency minus hiccups.
* Much more complicated to program than the basic loops we saw earlier.
* User input is completely ignored until the next update (even if the user has a fast device).
* The mandatory interpolation has a performance penalty.

A separate update and draw method could look like the following example. For the sake of demonstration, the example is based on the third bullet point, just without using Web Workers for readability (and, let's be honest, writability).

**Предупреждение:** This example, specifically, is in need of technical review.

```js
/\*
 \* Starting with the semicolon is in case whatever line of code above this example
 \* relied on automatic semicolon insertion (ASI). The browser could accidentally
 \* think this whole example continues from the previous line. The leading semicolon
 \* marks the beginning of our new line if the previous one was not empty or terminated.
 \*
 \* Let us also assume that MyGame is previously defined.
 \*
 \* MyGame.lastRender keeps track of the last provided requestAnimationFrame timestamp.
 \* MyGame.lastTick keeps track of the last update time. Always increments by tickLength.
 \* MyGame.tickLength is how frequently the game state updates. It is 20 Hz (50ms) here.
 \*
 \* timeSinceTick is the time between requestAnimationFrame callback and last update.
 \* numTicks is how many updates should have happened between these two rendered frames.
 \*
 \* render() is passed tFrame because it is assumed that the render method will calculate
 \* how long it has been since the most recently passed update tick for
 \* extrapolation (purely cosmetic for fast devices). It draws the scene.
 \*
 \* update() calculates the game state as of a given point in time. It should always
 \* increment by tickLength. It is the authority for game state. It is passed
 \* the DOMHighResTimeStamp for the time it represents (which, again, is always
 \* last update + MyGame.tickLength unless a pause feature is added, etc.)
 \*
 \* setInitialState() Performs whatever tasks are leftover before the mainloop must run.
 \* It is just a generic example function that you might have added.
 \*/

(function () {
  function main(tFrame) {
    MyGame.stopMain = window.requestAnimationFrame(main);
    var nextTick = MyGame.lastTick + MyGame.tickLength;
    var numTicks = 0;

    // If tFrame < nextTick then 0 ticks need to be updated (0 is default for numTicks).
    // If tFrame = nextTick then 1 tick needs to be updated (and so forth).
    // Note: As we mention in summary, you should keep track of how large numTicks is.
    // If it is large, then either your game was asleep, or the machine cannot keep up.
    if (tFrame > nextTick) {
      var timeSinceTick = tFrame - MyGame.lastTick;
      numTicks = Math.floor(timeSinceTick / MyGame.tickLength);
    }

    queueUpdates(numTicks);
    render(tFrame);
    MyGame.lastRender = tFrame;
  }

  function queueUpdates(numTicks) {
    for (var i = 0; i < numTicks; i++) {
      MyGame.lastTick = MyGame.lastTick + MyGame.tickLength; // Now lastTick is this tick.
      update(MyGame.lastTick);
    }
  }

  MyGame.lastTick = performance.now();
  MyGame.lastRender = MyGame.lastTick; // Pretend the first draw was on first update.
  MyGame.tickLength = 50; // This sets your simulation to run at 20Hz (50ms)

  setInitialState();
  main(performance.now()); // Start the cycle
})();
```

Another alternative is to simply do certain things less often. If a portion of your update loop is difficult to compute but insensitive to time, you might consider scaling back its frequency and, ideally, spreading it out into chunks throughout that lengthened period. An implicit example of this is found over at The Artillery Blog for Artillery Games, where they adjust their rate of garbage generation to optimize garbage collection. Obviously, cleaning up resources is not time sensitive (especially if tidying is more disruptive than the garbage itself).

This may also apply to some of your own tasks. Those are good candidates to throttle when available resources become a concern.

Summary
-------

I want to be clear that any of the above, or none of them, could be best for your game. The correct decision entirely depends on the trade-offs that you are willing (and unwilling) to make. The concern is mostly with switching to another option. Fortunately, I do not have any experience with this, but I have heard it is an excruciating game of Whack-a-Mole.

An important thing to remember for managed platforms, like the web, is that your loop may stop execution for significant periods of time. This could occur when the user unselects your tab and the browser sleeps (or slows) its `requestAnimationFrame` callback interval. You have many ways to deal with this situation and this could depend on whether your game is single player or multiplayer. Some choices are:

* Consider the gap "a pause" and skip the time.
    + You can probably see how this is problematic for most multiplayer games.
* You can simulate the gap to catch up.
    + This can be a problem for long drops and/or complex updates.
* You can recover the game state from a peer or the server.
    + This is ineffective if your peers or server are out-of-date too, or they don't exist because the game is single player and doesn't have a server.

Once your main loop has been developed and you have decided on a set of assumptions and tradeoffs which suit your game, it is now just a matter of using your decisions to calculate any applicable physics, AI, sounds, network synchronization, and whatever else your game may require.


Инструменты для разработки игр - Разработка игр

Инструменты для разработки игр
==============================

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

asm.js

asm.js это очень ограниченное подмножество языка JavaScript, которое можно значительно оптимизировать и запустить в опережающем времени (AOT), компилируя движок гораздо быстрее, чем при типичной производительности языка. А это, конечно же, замечательно для игр.

Emscripten

Низкоуровневая виртуальная машина(LLVM) для JavaScript; с Emscripten вы можете компилировать C++ и другие языки, которые можно копировать в байт-код LLVM с высокой производительностью JavaScript. Это отличный веб-инструмент! Вот полезный туториал по Emscripten, доступный на вики. Заметьте, что мы стремимся охватить Emscripten в своих разделах на MDN.

Gecko profiler

Gecko profiler позволяет профилировать код, чтобы понять, где имеются проблемы производительности, и добиться максимальной скорости в .

Игровые движки и инструменты

Список движков, шаблонов и технологий, полезных для разработчиков.

Shumway

Shumway это рендер для Adobe Flash построенный полностью на JavaScript, WebGL, etc., преодолевающий разрыв между Flash и web-стандартами. Это статья поясняет, как пользоваться Shumway,и как вносить исправления в проекте.

Инструментарий для разработки и отладки игр

Чем это отличается от обычной отладки веб-приложения? Какие специальные инструменты доступны? Многое из этого доступно в инструментах, но здесь мы должны обеспечить своего рода практический учебник для отладки игры, с ссылками :

* Обзор базовых инструментов
* Редактор шейдеров
* Производственные инструменты (все ещё находятся в производстве, по оценкам, в начале 2014 года)


asm.js - Разработка игр

asm.js
======

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

Что такое asm.js?
-----------------

Это небольшое, более строгое подмножество JavaScript которое ограничивает стандартный язык только конструкциями, типа `while`, `if` и данными в виде чисел, именованных функций, и другими простыми вещами. Оно не разрешает использование объектов, строк, и всего, что требует больших нагрузок. Asm.js напоминает C во многих вещах, но он является полностью валидным кодом на JavaScript и работает на всех имеющихся движках. Он позволяет JS движкам, поддерживающим asm.js, оптимизировать такой код и даёт компиляторам, типа Emscripten, чёткое определение того, как нужно компилировать. Мы покажем, как asm.js код выглядит, чем он полезен и как с ним работать.

Это подмножество JavaScript уже автоматически используется во многих движках, использующих технологию компиляции Just-In-Time (JIT). Однако, указав явный стандарт, мы можем улучшить оптимизацию такого кода и получить максимальную производительность. Благодаря этому, упрощается совместная работа нескольких JS движков, потому что легче договориться о стандартах. Идея в том, что этот вид кода должен работать очень быстро в каждом движке, и если это не так, это ошибка, и есть чёткая спецификация, что именно движки должны оптимизировать.

Это также делает asm.js достаточно простым для людей, которые пишут компиляторы высокопроизводительного кода под web. Они могут обратиться к спецификации asm.js, чтобы найти более быстрые паттерны для него. Emscripten, компилятор C/C++ в JavaScript, выдаёт код asm.js, работающий в некоторых браузерах с производительностью, близкой к машинному коду.

Кроме того, если движок специально распознает код asm.js, то можно сделать ещё больше оптимизаций. На данный момент Chrome (статус) и Firefox обладают поддержкой asm.js. Firefox имеет поддержку передовых фич asm.js

В общем об asm.js
-----------------

asm.js - это вспомогательное подмножество языка JavaScript. Он имеет предсказуемый уровень производительности, т.к. ограничен только лишь некоторыми строгими типами и конструкциями. Рабочие характеристики близки скорее к машинному коду, чем к стандартам JS. Использование этого подмножества уже поддерживается главными веб браузерами. Работа asm.js также зависит от браузера и от оборудования.


2D игра на Phaser - Разработка игр

2D игра на Phaser
=================

* Следующая статья »

В этом пошаговом руководстве мы создадим простую мобильную игру **MDN Breakout** с помощью JavaScript и фреймворка Phaser.

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

Чтобы получить наибольшую пользу от этого руководства, вам необходимо иметь базовые знания JavaScript. После прочтения вы научитесь создавать собственные простые веб-игры с помощью Phaser.

![Gameplay screen from the game MDN Breakout created with Phaser where you can use your paddle to bounce the ball and destroy the brick field, with keeping the points and lives.](/ru/docs/Games/Tutorials/2D_breakout_game_Phaser/mdn-breakout-phaser.png)

Дополнительно
-------------

Все уроки и различные версии MDN Breakout, которые мы сделаем вместе, доступны на GitHub:

1. Инициализация фреймворка
2. Масштабирование
3. Загрузка ресурсов и их вывод
4. Движение мяча
5. Физика
6. Отскакивание от стен
7. Управление
8. Конец игры
9. Создание поля блоков
10. Определение столкновения
11. Счёт
12. Победа в игре
13. Добавление жизней
14. Анимация (en-US)
15. Кнопки (en-US)
16. Создание случайных событий (en-US)

Также мы хотели бы заметить, что лучший способ научиться создавать веб-игры - это чистый (pure) JavaScript. Если вы ещё не знакомы с разработкой на чистом JavaScript, то мы предлагаем вам первым делом пройти туториал 2D игра на чистом JavaScript.

После этого вы можете выбрать любой фреймворк и использовать его в своих проектах. Мы выбрали Phaser, потому что это прочный фреймворк с хорошей поддержкой, открытым сообществом и набором различных плагинов. Фреймворки ускоряют разработку и заботятся о скучных вещах, позволяя вам сосредоточиться на самом весёлом. Однако они не идеальны, так что если что-то пойдёт не так или вы захотите написать функцию, которую фреймворк не поддерживает, то вам пригодятся знания чистого JavaScript.

**Примечание:** Эта серия статей может быть использована, как материал для создания игр в мастерских разработчиков. Также вы можете использовать Gamedev Phaser Content, который сделан на основе этого руководства, если захотите углубиться в разработку игр с помощью Phaser.

Следующие шаги
--------------

Давайте начнём! Первая часть руководства — это Инициализация фреймворка.

* Следующая статья »


2D игра на чистом JavaScript - Разработка игр

2D игра на чистом JavaScript
============================

* Следующая статья »

В этом пошаговом руководстве мы создадим простую игру **MDN Breakout,** написанную на чистом JavaScript и отрендеренную на HTML5 `<canvas>`.

К каждому шагу прилагаются редактируемые live-примеры, с которыми можно поиграть, чтобы увидеть, как должна выглядеть игра на промежуточных этапах. Вы изучите основы использования элемента `<canvas>` для реализации таких фундаментальных игровых механик, как рендеринг и перемещение изображений, обнаружение столкновений, механизмы управления, а также состояния выигрыша и проигрыша.

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

![Gameplay screen from the game MDN Breakout where you can use your paddle to bounce the ball and destroy the brick field, with keeping the score and lives.](/ru/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/mdn-breakout-gameplay.png)

Детали к урокам
---------------

Все уроки и версии игры MDN Breakout доступны в GitHub:

1. Создание Canvas и рисование на нем (en-US)
2. Движение мяча (en-US)
3. Реакция при столкновении со стеной (en-US)
4. Управление (en-US)
5. Конец игры (en-US)
6. Построение поля кирпичей (en-US)
7. Реакция при столкновении (en-US)
8. Счёт и выигрыш (en-US)
9. Контроль мышью (en-US)
10. Заключение (en-US)

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

**Примечание:** Если вам интересно узнать о разработке двухмерных игр с помощью игровой библиотеки, ознакомьтесь с альтернативной серией статей 2D игра Breakout с использованием Phaser (en-US).

**Примечание:** Эту серию статей можно использовать как материал для практических занятий по разработке игр. Также можно воспользоваться набором инструментов Gamedev Canvas Content Kit, основанном на этом уроке, если нужно сделать доклад о разработке игр в целом.

Следующий шаг
-------------

Ладно, давайте начнём! Перейдите к первой главе — Создание Canvas и рисование на нем (en-US).

* Следующая статья » (en-US)


Инициализация фреймворка - Разработка игр

Инициализация фреймворка
========================

* « Предыдущая статья
* Следующая статья »

Это первый из 16 уроков о том, как пользоваться Gamedev Phaser. После прочтения вы можете найти исходный код для этого урока на Gamedev-Phaser-Content-Kit/demos/lesson01.html.

Перед тем, как мы начнём разрабатывать функциональность игры, нам нужно создать базовую структуру, чтобы рендерить её. Это может быть сделано с помощью HTML: фреймворк Phaser создаст обязательный элемент `<canvas>`.

HTML-код игры
-------------

Структура HTML-документа достаточно простая. Игра будет отображаться в элементе `<canvas>`, который будет сгенерирован фреймворком. Используя свой любимый редактор, создайте новый HTML-документ, сохраните его как `index.html` и добавьте в него следующий код:

```html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Gamedev Phaser Workshop - lesson 01: Initialize the framework</title>
    <style>
 \* {
 padding: 0;
 margin: 0;
 }
 </style>
    <script src="js/phaser.min.js"></script>
  </head>
  <body>
    <script>
 var game = new Phaser.Game(480, 320, Phaser.CANVAS, null, {
 preload: preload,
 create: create,
 update: update,
 });
 function preload() {}
 function create() {}
 function update() {}
 </script>
  </body>
</html>
```

Загрузка Phaser
---------------

Дальше мы должны скачать исходный код фреймворка Phaser и использовать его в нашем HTML-документе. Это руководство использует Phaser V2, который не будет работать с текущей версией Phaser V3. Ссылка на скачивание Phaser V2 доступна в разделе Archive.

1. Перейдите на страницу загрузки Phaser.
2. Выберите наиболее удобный для вас вариант загрузки. Я рекомендую *min.js* скачивание, потому что исходный код будет меньше, да и вам не придётся разбираться в нём.
3. Сохраните Phaser внутри `/js` директории, находящейся в том же месте, что и `index.html`
4. Обновите атрибут `src` в первом элементе `<script>`, как это показано выше.
Что мы имеем
------------

На данный момент у нас есть обозначенный `charset`, `<title>` и немного CSS, что убрать значения свойств `margin` и `padding` по умолчанию. Также мы добавили элемент `<script>`, который позволяет использовать Phaser на странице. Во втором `<script>` мы написали код, который позволит отображать игру и управлять ею.

Фреймворк автоматически создаёт элемент `<canvas>`. Мы инициализировали его, создав новый `Phaser.Game` объект и присвоив его переменной. Также мы добавили параметры:

* `width` и `height` устанавливают ширину и высоту `<canvas>` соответственно.
* Метод рендеринга. Здесь есть три опции `AUTO`, `CANVAS` и `WEBGL`. Мы можем установить одно из двух последних значений или `AUTO`, чтобы Phaser сам определил, что использовать. Обычно используется WebGL, но если браузер его не поддерживает, то Canvas 2D.
* `id` элемента `<canvas>` используется для рендеринга, если один `<canvas>` уже есть (мы установили значение `null`, чтобы Phaser создал свой собственный).
* Дальше идут названия трёх ключевых функций Phaser: загрузки (load), старта (start) и обновления (update) игры на каждом кадре; мы выбрали такие же названия, чтобы сохранять чистоту кода.
    + `preload` заботится о предзагрузке ресурсов игры
    + `create` вызывается только один раз, когда всё загружено и готово
    + `update` вызывается на каждом кадре

**Предупреждение:** До конца прохождения всех уроков вы должны использовать `CANVAS`, как метод рендеринга, а не `AUTO`, как это было в нашем коде. Всё это нужно, потому что метод `AUTO` больше не поддерживается в последних версиях браузера.

Сравните свой код
-----------------

Это весь исходный код, который мы написали на этом уроке:

Следующее
---------

Мы создали базовую HTML структуру и узнали немного об инициализации Phaser. Давайте продолжим и узнаем про масштабирование.

* « Предыдущая статья
* Следующая статья »


Масштабирование - Разработка игр

Масштабирование
===============

* « Предыдущая статья
* Следующая статья »

Это **2-й урок** из 16, которые входят в руководство 2D игра на Phaser. Вы можете найти исходный код этого урока на Gamedev-Phaser-Content-Kit/demos/lesson02.html.

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

Масштабирование
---------------

В Phaser есть специальный объект `scale`, которые имеет несколько полезных методов и свойств. Измените вашу функцию `preload()` так, как показано ниже:

```js
function preload() {
  game.scale.scaleMode = Phaser.ScaleManager.SHOW\_ALL;
  game.scale.pageAlignHorizontally = true;
  game.scale.pageAlignVertically = true;
}
```

`scaleMode` имеет несколько опций, которые определяют, как `<canvas>` будет масштабироваться:

* `NO_SCALE` — ничего не масштабировать.
* `EXACT_FIT` — масштабировать с полным заполнением пустого места вертикально и горизонтально, не соблюдая соотношение (aspect ratio).
* `SHOW_ALL` — масштабирует игру, но сохраняет соотношение так, что картинки не будут искажаться, как и при предыдущем значении. Возможно наличие чёрных полос по краям экрана, но мы можем жить с этим.
* `RESIZE` — создаёт `<canvas>` с доступными шириной и высотой так, что вы можете помещать объекты в игру динамически; это расширенный режим (advanced mode).
* `USER_SCALE` — позволяет вам делать динамическое масштабирование, подсчёт размеров, масштаб и соотношение самостоятельно; опять же это расширенный режим.

Две другие строчки кода в функции `preload()` отвечают за вертикальное и горизонтальное выравнивание элемента `<canvas>`, так что он всегда будет находиться по центру независимо от размера экрана.

Изменение цвета фона
--------------------

Мы также можем сделать фон нашего элемента `<canvas>` таким, каким захотим, чтобы он не оставался постоянно чёрным. Объект `stage` имеет свойство `backgroundColor` для этого. Мы можем изменить значение, используя синтаксис CSS для цветов. Добавьте эту строку после трёх, недавно добавленных:

```js
game.stage.backgroundColor = "#eee";
```

Сравните свой код
-----------------

Вы можете сравнить весь код из этого урока со своим и поиграть с ним, чтобы понять, как он работает:

Следующее
---------

Мы научились масштабировать нашу игру, так что давайте перейдём к третьему уроку и узнаем, как загружать ресурсы игры и выводить их.

* « Предыдущая статья
* Следующая статья »


Game over - Разработка игр

Game over
=========

* « Предыдущая статья
* Следующая статья »

Это **8** из 16 уроков руководства разработки игры с помощью Phaser. Исходный код этого урока вы можете найти здесь: Gamedev-Phaser-Content-Kit/demos/lesson08.html.

Чтобы разнообразить игру, давайте добавим возможность проигрыша — если вы не отобьёте мячик и дадите ему упасть на пол, то game over.

Проигрыш
--------

Чтобы добавить возможность проигрыша, давай те отключим определение коллизии с нижней гранью экрана. Добавьте следующую строку кода в функцию `create()`, сразу после кода инициализации всех атрибутов мячика:

```js
game.physics.arcade.checkCollision.down = false;
```

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

```js
ball.checkWorldBounds = true;
ball.events.onOutOfBounds.add(function () {
  alert("Game over!");
  location.reload();
}, this);
```

Мы сделали так, чтобы мячик проверял границы игрового мира (в нашем случае границы `<canvas>`) и, в случае выхода за их пределы (событие `onOutOfBounds`), выполнял функцию, которую мы привязали к этому событию. После закрытия всплывающего окна с сообщением 'Game over!', происходит перезагрузка страницы, чтобы можно было сыграть снова.

Сравните свой код
-----------------

Вы можете проверить код из этого урока и поиграть с ним, чтобы лучше понять, как он работает:

Следующий шаг
-------------

Базовый геймплей готов. Но какой арканоид без разбивания кирпичиков?

* « Предыдущая статья
* Следующая статья »


Обработка коллизий - Разработка игр

Обработка коллизий
==================

* « Предыдущая статья
* Следующая статья »

Это **10** из 16 уроков руководства разработки игры с помощью Phaser. Исходный код этого урока вы можете найти здесь: Gamedev-Phaser-Content-Kit/demos/lesson10.html.

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

Проверяем коллизии Мячик/Кирпич
-------------------------------

Физический движок облегчает очень многие задачи — нам понадобится, всего лишь, несколько простых кусочков кода. Для начала, добавим в функцию `update()` строчку проверки коллизий между мячиком и кирпичами, как показано ниже:

```js
function update() {
  game.physics.arcade.collide(ball, paddle);
  game.physics.arcade.collide(ball, bricks, ballHitBrick);
  paddle.x = game.input.x || game.world.width \* 0.5;
}
```

Теперь будет отслеживаться положение мячика, относительно всех кирпичей из набора `bricks`. Третьим (опциальным) параметром, мы передаём функцию, которая будет выполняться каждый раз, когда будет найдена коллизия — `ballHitBrick`. Давайте создадим эту функцию в самом конце нашего кода, прямо перед `</script>`:

```js
function ballHitBrick(ball, brick) {
  brick.kill();
}
```

Вот и всё! Перезагрузите страницу и вы увидите, что все коллизии обрабатывается, как следует.

Спасибо Phaser за то, что передал нам в функцию эти два параметра — мячик и тот кирпич, с которым у мячика произошла коллизия. А дальше мы просто удаляем кирпич с экрана, вызвав у него функцию `kill()`.

Вы думали, что нам придётся писать много кода для отслеживания коллизий, как мы это делали на чистом JavaScript (en-US)? В этом и прелесть фреймворков — рутину они сделают за нас, а мы, в это время, можем сосредоточиться на действительно интересных вещах.

Сравните свой код
-----------------

Вы можете проверить код из этого урока и поиграть с ним, чтобы лучше понять, как он работает:

Следующий шаг
-------------

Теперь мы можем разбивать кирпичи, а это уже отличное дополнение к нашему геймплею. Будет ещё лучше, если мы сможем считать количество разбитых кирпичей и присуждать за это очки.

* « Предыдущая статья
* Следующая статья »


Победа - Разработка игр

Победа
======

* « Предыдущая статья
* Следующая статья »

Это **12** из 16 уроков руководства разработки игры с помощью Phaser. Исходный код этого урока вы можете найти здесь: Gamedev-Phaser-Content-Kit/demos/lesson12.html.

Победа в нашей игре будет достаточно простой: если ты разрушил все кирпичи, то победил.

Как победить?
-------------

Добавьте следующий код в функцию `ballHitBrick()`:

```js
function ballHitBrick(ball, brick) {
  brick.kill();
  score += 10;
  scoreText.setText("Points: " + score);

  var count_alive = 0;
  for (i = 0; i < bricks.children.length; i++) {
    if (bricks.children[i].alive == true) {
      count_alive++;
    }
  }
  if (count_alive == 0) {
    alert("You won the game, congratulations!");
    location.reload();
  }
}
```

Чтобы перебрать все кирпичи в наборе, необходимо обратиться к полю `bricks.children`. Найдём все неразрешённые кирпичи, проверяя поле `alive` у каждого кирпича и, если все кирпичи разрушены, выведем всплывающее окно с текстом о победе. После закрытия этого окна, страница перезагрузится.

Сравните свой код
-----------------

Вы можете проверить код из этого урока и поиграть с ним, чтобы лучше понять, как он работает:

Следующий шаг
-------------

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

* « Предыдущая статья
* Следующая статья »


Создание кирпичей - Разработка игр

Создание кирпичей
=================

* « Предыдущая статья
* Следующая статья »

Это **9** из 16 уроков руководства разработки игры с помощью Phaser. Исходный код этого урока вы можете найти здесь: Gamedev-Phaser-Content-Kit/demos/lesson09.html.

Создать поле кирпичей немного сложнее, чем просто добавить объект на экран, но всё же, благодаря Phaser, нам будет полегче, по сравнению с чистым JavaScript. Давайте разберёмся, как создать набор кирпичей и нарисовать их всех, используя цикл.

Определяем переменные
---------------------

Сначала, давайте определим необходимые переменные — добавьте следующий код ниже всех наших текущих определений переменных:

```js
var bricks;
var newBrick;
var brickInfo;
```

Переменная `bricks` будет использоваться в качестве набора кирпичей, `newBrick` будет тем самым кирпичом, который мы будем создавать в каждой итерации цикла и добавлять в набор, а в `brickInfo` будет хранить всю необходимую информацию о кирпичах, как таковых.

Добавляем графику для кирпича
-----------------------------

Далее, давайте загрузим изображение кирпича `brick`, при помощи ещё одного вызова функции `load.image()`:

```js
function preload() {
  // ...
  game.load.image("brick", "img/brick.png");
}
```

Не забудьте скачать изображение кирпича с Github в папку `/img`.

Рисуем кирпичи
--------------

Для удобства, давайте вынесем код отрисовки кирпичей в отдельную функцию `initBricks` и вызовем её в конце функции `create()`:

```js
function create() {
  // ...
  initBricks();
}
```

Теперь перейдём непосредственно к самой функции. Добавим функцию `initBricks()` в самый конец нашего кода, прямо перед `</script>`, а в теле этой функции опишем объект `brickInfo`, который нам скоро понадобится:

```js
function initBricks() {
  brickInfo = {
    width: 50,
    height: 20,
    count: {
      row: 3,
      col: 7,
    },
    offset: {
      top: 50,
      left: 60,
    },
    padding: 10,
  };
}
```

Объект `brickInfo` содержит всю необходимую нам информацию о кирпичах: ширина и высота кирпичика, количество рядов и столбцов кирпичей, которые мы хотим отрисовать на игровом поле, отступы от левого и верхнего края экрана (место на <canvas>, откуда мы начнём располагать кирпичи) и зазоры между самими кирпичами.

А теперь, собственно, к кирпичам — инициализируйте пустой набор для хранения кирпичей, путём добавления следующей строчки кода в функцию `initBricks()`:

```js
bricks = game.add.group();
```

Далее переберём в цикле ряды и столбцы — добавьте следующий код со вложенным циклом после предыдущей строки:

```js
for (c = 0; c < brickInfo.count.col; c++) {
  for (r = 0; r < brickInfo.count.row; r++) {
    // create new brick and add it to the group
  }
}
```

Теперь необходимо в каждой итерации создавать кирпич, чтобы получить необходимое число кирпичей, нарисовать их всех на экране и добавить в наш набор `bricks`. Для этого добавим во вложенный цикл немного кода, как показано ниже:

```js
for (c = 0; c < brickInfo.count.col; c++) {
  for (r = 0; r < brickInfo.count.row; r++) {
    var brickX = 0;
    var brickY = 0;
    newBrick = game.add.sprite(brickX, brickY, "brick");
    game.physics.enable(newBrick, Phaser.Physics.ARCADE);
    newBrick.body.immovable = true;
    newBrick.anchor.set(0.5);
    bricks.add(newBrick);
  }
}
```

Вот мы и создали новый кирпич в каждой итерации и отрисовали его на экране. Как мы помним из урока 5, мы используем движок Arcade Physics. К каждому новому кирпичу применяем физику из этого движка и делаем его неподвижным, чтобы мячик его не сбивал, а, также, устанавливаем якорь кирпича в его середину. После этого, добавляем кирпич в набор `bricks`.

Но у нас осталась проблема — все кирпичи мы рисуем в одном и том же месте, в координатах (0,0). Чтобы это исправить, давайте добавим вычисление координат `brickX` и `brickY` в каждой итерации. Обновите строки инициализации этих переменных, как показано ниже:

```js
var brickX = c \* (brickInfo.width + brickInfo.padding) + brickInfo.offset.left;
var brickY = r \* (brickInfo.height + brickInfo.padding) + brickInfo.offset.top;
```

Координата `x` каждого кирпича рассчитывается на основе суммы ширины кирпича `brickInfo.width` и зазора `brickInfo.padding`, умноженной на номер столбца `с`, после этого добавляем отступ от левого края `brickInfo.offset.left`; Расчёт `y` аналогичен, только используются номер ряда r, высота кирпича `brickInfo.height` и отступ от верхнего края `brickInfo.offset.top`. Вот теперь каждый кирпич на своём месте, с учётом всех отступов и зазоров.

Проверяем код функции initBricks()
----------------------------------

Вот итоговый код функции `initBricks()`:

```js
function initBricks() {
  brickInfo = {
    width: 50,
    height: 20,
    count: {
      row: 3,
      col: 7,
    },
    offset: {
      top: 50,
      left: 60,
    },
    padding: 10,
  };
  bricks = game.add.group();
  for (c = 0; c < brickInfo.count.col; c++) {
    for (r = 0; r < brickInfo.count.row; r++) {
      var brickX =
        c \* (brickInfo.width + brickInfo.padding) + brickInfo.offset.left;
      var brickY =
        r \* (brickInfo.height + brickInfo.padding) + brickInfo.offset.top;
      newBrick = game.add.sprite(brickX, brickY, "brick");
      game.physics.enable(newBrick, Phaser.Physics.ARCADE);
      newBrick.body.immovable = true;
      newBrick.anchor.set(0.5);
      bricks.add(newBrick);
    }
  }
}
```

Если вы перезапустите страницу `index.html`, то увидеть кирпичи, нарисованные на расстоянии друг от друга.

Сравните свой код
-----------------

Вы можете проверить код из этого урока и поиграть с ним, чтобы лучше понять, как он работает:

Следующий шаг
-------------

Кажется, что-то не так. Ах да! Мячик же проходит сквозь кирпичи. Добавим обработку коллизий.

* « Предыдущая статья
* Следующая статья »


Загрузка ресурсов и их вывод - Разработка игр

Загрузка ресурсов и их вывод
============================

* « Предыдущая статья
* Следующая статья »

Это 3-й урок из 16 в руководстве 2D игра на Phaser. Весь исходный код из этого урока вы можете найти на Gamedev-Phaser-Content-Kit/demos/lesson03.html.

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

Создание мяча
-------------

Давайте начнём с создания JavaScript переменной для нашего мячика. Добавьте следующий код между строкой инициализации (`var game...`) и функцией `preload()`:

```js
var ball;
```

>
> \*\*Примечание:\*\*В этом уроке мы для удобства будем использовать глобальные переменные, потому что цель урока - научить пользоваться Phaser для создания игр, а не хорошим практикам разработки.
>
>
>

Загрузка спрайта мяча
---------------------

Загрузка и вывод изображений в canvas намного проще с использованием Phaser, чем чистым JavaScript. Чтобы загрузить спрайт, мы будем использовать метод `load.image()` объекта `game`. Добавьте новую строку кода в функцию `preload()`:

```js
function preload() {
  // ...
  game.load.image("ball", "img/ball.png");
}
```

Первым параметром, которому мы хотим присвоить имя картинки, является имя, которое будет использоваться в нашем игровом коде - например, в нашем имени переменной `ball` - поэтому мы должны убедиться, что оно совпадает. Второй параметр - это относительный путь к самой картинке, мы загружаем спрайт для нашего мяча. (Заметьте, что имя файла (asset) не обязано совпадать с именем переменной, которой оно присваивается, однако так проще).

Конечно, чтобы загрузить картинку, она должна находиться в нашей рабочей директории. Скачайте изображение с GitHub и сохраните его в `/img` директории, которая находится там же, где и файл `index.html`.

Теперь, чтобы вывести наш мяч на экран, мы используем другой метод `add.sprite()`. Добавьте следующую строку кода в функцию `create()`:

```js
function create() {
  ball = game.add.sprite(50, 50, "ball");
}
```

Это метод добавит мяч в игру и выведет его на экран. Первые два параметра — это координаты `x` и `y` элемента canvas соответственно, и последний параметр — это имя картинки, которое мы добавили раннее. Вот и всё: загрузите `index.html`, и вы увидите, что картинка уже загружена и выведена в canvas!

**Предупреждение:** Если вы храните ваш JavaScript код отдельно от HTML и используете файл для этого, например, `game.js`, тогда вам нужно расположить директорию `img` и JavaScript файл в одной папке, иначе картинка не загрузится.

Сравните свой код
-----------------

Вы можете проверить код из этого урока и поиграть с ним, чтобы лучше понять, как он работает:

Следующее
---------

Вывод мяча на экран был достаточно прост, теперь попробуем переместить его.

* « Предыдущая статья
* Следующая статья »


Физика - Разработка игр

Физика
======

* « Предыдущая статья
* Следующая статья »

Это **5 урок** из 16, которые входят в руководство 2D игра на Phaser. Вы можете найти исходный код этого урока на Gamedev-Phaser-Content-Kit/demos/lesson05.html.

Для правильного определения столкновений нам необходима физика, и в этом уроке мы покажем, что есть у Phaser на этот счёт, продемонстрировав это на простом примере.

Добавление физики
-----------------

В Phaser есть три разных физических движка: Arcade Physics, P2 и Ninja Physics. Также есть четвёртый Box2D как платный плагин. Для нашей простой игры мы будем использовать Arcade Physics, потому что нам не нужны сложные геометрические вычисления.

Во-первых, инициализируем Arcade Physics в нашей игре. Добавьте метод `physics.startSystem()` в начале функции `create()`. Убедитесь, что следующая строка кода находится в самом начале функции `create():`

```js
game.physics.startSystem(Phaser.Physics.ARCADE);
```

Во-вторых, нам необходимо добавить мяч в физическую систему, потому что объект, отвечающий за физику в Phaser, не включён по умолчанию. Добавьте следующую строку в конце функции `create()`:

```js
game.physics.enable(ball, Phaser.Physics.ARCADE);
```

В-третьих, теперь мы можем установить значение свойства `velocity` нашего мяча через `body`. Добавьте следующую строку снова в конце функции `create()`:

```js
ball.body.velocity.set(150, 150);
```

Удаление предыдущих инструкций при обновлении
---------------------------------------------

Теперь нам надо убрать старый код, который добавлял 1 к координатам x и y в функции update():

```js
function update() {
  ball.x += 1;
  ball.y += 1;
}
```

теперь мы сделали тоже самое, но на физическом движке.

Финальный код
-------------

Весь код должен выглядеть вот так:

```js
var ball;

function preload() {
  game.scale.scaleMode = Phaser.ScaleManager.SHOW\_ALL;
  game.scale.pageAlignHorizontally = true;
  game.scale.pageAlignVertically = true;
  game.stage.backgroundColor = "#eee";
  game.load.image("ball", "img/ball.png");
}

function create() {
  game.physics.startSystem(Phaser.Physics.ARCADE);
  ball = game.add.sprite(50, 50, "ball");
  game.physics.enable(ball, Phaser.Physics.ARCADE);
  ball.body.velocity.set(150, 150);
}

function update() {}
```

Снова перезагрузите index.html. Мячик должен постоянно двигаться в направлении, которое мы задали. На данный момент в физическом движке гравитация (gravity) и трение (friction) имеют нулевое значение. Добавление гравитации заставит мячик падать вниз, пока трение будет пытаться остановить его.

Поиграйте с физикой
-------------------

Вы можете делать гораздо больше вещей с физикой. Например, добавив `ball.body.gravity.y = 100`, вы установите вертикальную гравитацию для мячика. Как результат он будет сначала запущен вверх, но затем начнёт падать, находясь под действием гравитации.

Это лишь верхушка айсберга: есть огромное количество переменных и функции, с помощью которых вы можете взаимодействовать с физическими объектами. Посмотрите официальную документацию, чтобы увидеть огромное количество примеров применения Arcade и P2.

Сравните свой код
-----------------

Вы можете проверить код из этого урока и поиграть с ним, чтобы лучше понять, как он работает:

Следующее
---------

Теперь мы можем посмотреть, как заставить мяч отскакивать от стен.

* « Предыдущая статья
* Следующая статья »


Очки - Разработка игр

Очки
====

* « Предыдущая статья
* Следующая статья »

Это **11** из 16 уроков руководства разработки игры с помощью Phaser. Исходный код этого урока вы можете найти здесь: Gamedev-Phaser-Content-Kit/demos/lesson11.html.

Очки сделают игру более интересной — вы можете пробовать побить собственный рекорд или рекорд друзей. В этой главе мы добавим систему очков в нашу игру.

Мы будем использовать отдельные переменные для хранения количества очков и текста, который Phaser выведет на экран при помощи функции `text()`.

Определим переменные
--------------------

Добавьте две новых переменных после всех наших текущих определений переменных:

```js
// ...
var scoreText;
var score = 0;
```

Выводим очки на экран
---------------------

А сейчас добавим строку кода в самый конец функции `create()`:

```js
scoreText = game.add.text(5, 5, "Points: 0", {
  font: "18px Arial",
  fill: "#0095DD",
});
```

Функция `text()` может принимать четыре параметра:

* Координаты x и y текста.
* Сам текст.
* Шрифт и стиль текста.

Последний параметр выглядит очень похожим на CSS-стиль. В нашем случае, текст будет голубой, размер 18 пикселей, шрифт Arial.

Обновляем очки при разрушении кирпича
-------------------------------------

Мы будем увеличивать количество очков каждый раз, когда мячик разобьёт кирпич и обновлять текст `scoreText`, который отображает на экране текущие очки. Текст обновляется вызовом функции `setText()`. Добавьте эти две строчки кода в функцию `ballHitBrick()`:

```js
function ballHitBrick(ball, brick) {
  brick.kill();
  score += 10;
  scoreText.setText("Points: " + score);
}
```

Вот и всё — обновите страницу `index.html` и проверьте, как очки изменяются, при разрушении кирпича.

Сравните свой код
-----------------

Вы можете проверить код из этого урока и поиграть с ним, чтобы лучше понять, как он работает:

Следующий шаг
-------------

Теперь мы имеем систему очков, но какой смысл в этом, если мы не можем выиграть? Давайте добавим логику выигрыша.

* « Предыдущая статья
* Следующая статья »