From c058fa0fb22dc40ef0225b21a97578cddd0aaffa Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 14:51:05 +0100 Subject: unslug ru: move --- files/ru/games/anatomy/index.html | 337 +++++++++++++++++++++ files/ru/games/introduction/index.html | 121 ++++++++ files/ru/games/tools/asm.js/index.html | 30 ++ files/ru/games/tools/index.html | 33 ++ .../bounce_off_the_walls/index.html | 42 +++ .../build_the_brick_field/index.html | 156 ++++++++++ .../collision_detection/index.html | 52 ++++ .../2d_breakout_game_phaser/extra_lives/index.html | 117 +++++++ .../2d_breakout_game_phaser/game_over/index.html | 46 +++ .../tutorials/2d_breakout_game_phaser/index.html | 64 ++++ .../initialize_the_framework/index.html | 95 ++++++ .../index.html | 73 +++++ .../move_the_ball/index.html | 48 +++ .../2d_breakout_game_phaser/physics/index.html | 98 ++++++ .../player_paddle_and_controls/index.html | 116 +++++++ .../2d_breakout_game_phaser/scaling/index.html | 64 ++++ .../2d_breakout_game_phaser/the_score/index.html | 69 +++++ .../win_the_game/index.html | 54 ++++ .../build_the_brick_field/index.html | 119 ++++++++ .../collision_detection/index.html | 128 ++++++++ .../create_the_canvas_and_draw_on_it/index.html | 115 +++++++ .../finishing_up/index.html | 103 +++++++ .../mouse_controls/index.html | 58 ++++ .../move_the_ball/index.html | 146 +++++++++ .../index.html" | 103 ------- .../index.html" | 128 -------- .../index.html" | 146 --------- .../index.html" | 119 -------- .../index.html" | 115 ------- .../index.html" | 58 ---- .../bounce_off_the_walls/index.html" | 42 --- .../game_over/index.html" | 46 --- .../index.html" | 64 ---- .../initialize_the_framework/index.html" | 95 ------ .../index.html" | 73 ----- .../move_the_ball/index.html" | 48 --- .../physics/index.html" | 98 ------ .../scaling/index.html" | 64 ---- .../index.html" | 117 ------- .../index.html" | 52 ---- .../\320\276\321\207\320\272\320\270/index.html" | 69 ----- .../index.html" | 116 ------- .../index.html" | 54 ---- .../index.html" | 156 ---------- .../index.html" | 337 --------------------- .../\320\262\320\262\320\276\320\264/index.html" | 121 -------- .../asm.js/index.html" | 30 -- .../index.html" | 33 -- 48 files changed, 2284 insertions(+), 2284 deletions(-) create mode 100644 files/ru/games/anatomy/index.html create mode 100644 files/ru/games/introduction/index.html create mode 100644 files/ru/games/tools/asm.js/index.html create mode 100644 files/ru/games/tools/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_phaser/collision_detection/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_phaser/extra_lives/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_phaser/game_over/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_phaser/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_phaser/physics/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_phaser/scaling/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_phaser/the_score/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_phaser/win_the_game/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_pure_javascript/finishing_up/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_pure_javascript/mouse_controls/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.html delete mode 100644 "files/ru/games/tutorials/2d_breakout_game_pure_javascript/\320\267\320\260\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265/index.html" delete mode 100644 "files/ru/games/tutorials/2d_breakout_game_pure_javascript/\320\276\320\261\320\275\320\260\321\200\321\203\320\266\320\265\320\275\320\270\320\265_\321\201\321\202\320\276\320\273\320\272\320\275\320\276\320\262\320\265\320\275\320\270\320\271/index.html" delete mode 100644 "files/ru/games/tutorials/2d_breakout_game_pure_javascript/\320\277\320\265\321\200\320\265\320\274\320\265\321\201\321\202\320\270\321\202\321\214_\320\274\321\217\321\207/index.html" delete mode 100644 "files/ru/games/tutorials/2d_breakout_game_pure_javascript/\321\201\320\276\320\267\320\264\320\260\320\265\320\274_\320\267\320\276\320\275\321\203_\320\272\320\270\321\200\320\277\320\270\321\207\320\265\320\271/index.html" delete mode 100644 "files/ru/games/tutorials/2d_breakout_game_pure_javascript/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_canvas_\320\270_\321\200\320\270\321\201\320\276\320\262\320\260\320\275\320\270\320\265_\320\275\320\260_\320\275\321\221\320\274/index.html" delete mode 100644 "files/ru/games/tutorials/2d_breakout_game_pure_javascript/\321\203\320\277\321\200\320\260\320\262\320\273\320\265\320\275\320\270\320\265_\320\274\321\213\321\210\321\214\321\216/index.html" delete mode 100644 "files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/bounce_off_the_walls/index.html" delete mode 100644 "files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/game_over/index.html" delete mode 100644 "files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/index.html" delete mode 100644 "files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/initialize_the_framework/index.html" delete mode 100644 "files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/load_the_assets_and_print_them_on_screen/index.html" delete mode 100644 "files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/move_the_ball/index.html" delete mode 100644 "files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/physics/index.html" delete mode 100644 "files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/scaling/index.html" delete mode 100644 "files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\266\320\270\320\267\320\275\320\270/index.html" delete mode 100644 "files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\276\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260_\320\272\320\276\320\273\320\273\320\270\320\267\320\270\320\271/index.html" delete mode 100644 "files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\276\321\207\320\272\320\270/index.html" delete mode 100644 "files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\277\320\273\320\260\321\202\321\204\320\276\321\200\320\274\320\260_\320\270_\321\203\320\277\321\200\320\260\320\262\320\273\320\265\320\275\320\270\320\265/index.html" delete mode 100644 "files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\277\320\276\320\261\320\265\320\264\320\260/index.html" delete mode 100644 "files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_\320\272\320\270\321\200\320\277\320\270\321\207\320\265\320\271/index.html" delete mode 100644 "files/ru/games/\320\260\320\275\320\260\321\202\320\276\320\274\320\270\321\217/index.html" delete mode 100644 "files/ru/games/\320\262\320\262\320\276\320\264/index.html" delete mode 100644 "files/ru/games/\320\270\320\275\321\201\321\202\321\200\321\203\320\274\320\265\320\275\321\202\321\213/asm.js/index.html" delete mode 100644 "files/ru/games/\320\270\320\275\321\201\321\202\321\200\321\203\320\274\320\265\320\275\321\202\321\213/index.html" (limited to 'files/ru/games') diff --git a/files/ru/games/anatomy/index.html b/files/ru/games/anatomy/index.html new file mode 100644 index 0000000000..0396fc4159 --- /dev/null +++ b/files/ru/games/anatomy/index.html @@ -0,0 +1,337 @@ +--- +title: Анатомия видеоигры +slug: Games/Анатомия +translation_of: Games/Anatomy +--- +
{{GamesSidebar}}
+ +

{{IncludeSubnav("/en-US/docs/Games")}}

+ +
+

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

+
+ +

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

+ +

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

+ +

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

+ +

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

+ +

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

+ +

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

+ +

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

+ +

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

+ +

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

+ +

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

+ +
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() загрязняет {{ domxref("window") }} объект (в нем хранятся все глобальные переменные) и код не оставляет нам возможность остановить цикл, если только вся вкладка не будет закрыта или обновлена. Для решения первой проблемы, если нужно, чтобы основной цикл просто выполнялся и вам не нужен легкий (прямой) доступ к нему, вы можете поместить его внутрь самовызывающейся Function Expression (IIFE).

+ +
/*
+* Начинаем с точки с запятой в случае, если какая-либо строка кода выше данного примера
+* полагается на автоматическую вставку точки с запятой (ASI). Браузер может случайно решить,
+* что весь этот код начинается с предыдущей строки. Первая точка с запятой отмечает начало
+* новой строки, если предыдущая не была пустой или завершенной.
+*/
+
+;(function () {
+  function main() {
+    window.requestAnimationFrame( main );
+
+    // Содержание вашего основного цикла
+  }
+
+  main(); // Вызов цикла
+})();
+ +

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

+ +
+

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

+
+ +

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

+ +
/*
+* Начинаем с точки с запятой в случае, если какая-либо строка кода выше данного примера
+* полагается на автоматическую вставку точки с запятой (ASI). Браузер может случайно решить,
+* что весь этот код начинается с предыдущей строки. Первая точка с запятой отмечает начало
+* новой строки, если предыдущая не была пустой или завершенной.
+*
+* Давайте также предположим, что MyGame уже определена.
+*/
+
+;(function () {
+  function main() {
+    MyGame.stopMain = window.requestAnimationFrame( main );
+
+    // Содержание вашего основного цикла
+  }
+
+  main(); // Вызов цикла
+})();
+ +

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

+ +
window.cancelAnimationFrame( MyGame.stopMain );
+ +

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

+ +

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

+ +

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

+ +

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

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

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

+ +

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

+ +
+

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

+
+ + + +

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

+ +
var tNow = window.performance.now();
+
+ +

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

+ +
/*
+* Начинаем с точки с запятой в случае, если какая-либо строка кода выше данного примера
+* полагается на автоматическую вставку точки с запятой (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.

+ +
+

Note: 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.

+ +
/*
+* 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:

+ + + +

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:

+ + + +

Each of these methods have similar tradeoffs:

+ + + +

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).

+ +
+

Note: This example, specifically, is in need of technical review.

+
+ +
/*
+* 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:

+ + + +

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.

diff --git a/files/ru/games/introduction/index.html b/files/ru/games/introduction/index.html new file mode 100644 index 0000000000..65d1aed2c0 --- /dev/null +++ b/files/ru/games/introduction/index.html @@ -0,0 +1,121 @@ +--- +title: Ввод в разработку Web-игр +slug: Games/Ввод +tags: + - Firefox OS + - Игры + - уроки +translation_of: Games/Introduction +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs/Games")}}
+ +

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

+ +

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

+ +

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

+ +

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

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

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

+ +

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

+ +

1. Охват паутины огромен, она повсюду. Игры, построенные на HTML5, работают на смартфонах, планшетах, ПК и смарт-телевизорах.

+ +

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

+ +

3. У вас есть контроль, где это имеет значение: Платежи. Вы не должны отдавать 30% своих доходов кому-то другому только потому, что ваша игра в их экосистеме. Вместо этого, взимать плату, что вы хотите, и использовать любую услугу обработки платежей вам нравится.

+ +

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

+ +

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

+ +

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

+ +

7. Ваши игроки могут играть в вашу игру в любом месте, в любое время. Поскольку Web распространен повсеместно, ваши клиенты могут проверить статус своей игры на своих телефонах, планшетах, домашних ноутбуках, рабочих столах или на чем-либо еще.

+ +

Web-технологии для разработчиков игр

+ +

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

+ +
+
+
Full Screen API
+
Этот простой API позволяет вашей игре использовать весь экран, тем самым погружая игрока в действие.
+
Gamepad API
+
Если вы хотите, чтобы ваши пользователи могли использовать геймпады и прочие игровые контроллеры для работы с игрой, вам потребуется этот API
+
HTML и CSS
+
Эти технологии помогут вам создать и разместить UI вашей игры, а HTML-элемент {{HTMLElement("canvas")}} это один из способов создать 2D-графику
+
HTML audio
+
Элемент {{HTMLElement ("audio")}} позволяет легко воспроизводить простые звуковые эффекты и музыку. Если ваше потребности выше, ознакомьтесь с Web Audio API для полной мощности обработки звука!
+
IndexedDB
+
Мощный API для хранения пользовательских данных на собственном компьютере или устройстве. Отличный способ локально сохранить состояние игры и другую информацию, без необходимости подгружать ее каждый раз при необходимости. Также полезно дял того, чтобы сделать ваш проект играбельным, даже если пользователь не подключен к Интернету (например, когда он оказался в самолете на несколько часов).
+
JavaScript
+
JavaScript, язык программирования, используемый в Интернете, быстро развивается в современных браузерах и становится ещё быстрее. Используйте его возможности для написания кода своей игры или используйте такие технологии, как Emscripten или Asm.js, чтобы с легкотью переносить существующие игры.
+
Pointer Lock API
+
API Pointer Lock позволяет блокировать мышь или другое указывающее устройство в интерфейсе вашей игры. Вместо абсолютного позиционирования курсора вы получаете координаты дельты, которые дают вам более точные измерения того, что делает пользователь, и предотвращают случайную отправку ввода где-то еще, тем самым упуская важные пользовательские действия.
+
+
SVG (масштабируемая векторная графика)
+
Позволяет создавать векторную графику, которая плавно масштабируется независимо от размера или разрешения дисплея пользователя.
+
Typed Arrays
+
Типизированные массивы JavaScript дают вам доступ к необработанным двоичным данным из кода, что позволяет вам манипулировать текстурами GL, игровыми данными или чем-то еще, даже если код не в формате JavaScript.
+
Web Audio API
+
Этот API необходим для управления воспроизведением, синтезом звука и манипулированием аудио из кода JavaScript. Позволяет создавать потрясающие звуковые эффекты, а также воспроизводить и манипулировать музыкой в ​​режиме реального времени.
+
WebGL
+
Позволяет создавать высокопроизводительную аппаратно-ускоренную 3D (и 2D) графику из веб-контента. Это веб-реализация OpenGL ES 2.0.
+
WebRTC
+
API WebRTC (Real-Time Communications) дает вам возможность управлять аудио- и видеоданными, включая телеконференции и передачу данных из других приложений между двумя пользователями. Хотите, чтобы ваши игроки могли общаться друг с другом, взрывая монстров? Это API для вас!
+
WebSockets
+
+

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

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

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

+
+
+
diff --git a/files/ru/games/tools/asm.js/index.html b/files/ru/games/tools/asm.js/index.html new file mode 100644 index 0000000000..3f9b2afde0 --- /dev/null +++ b/files/ru/games/tools/asm.js/index.html @@ -0,0 +1,30 @@ +--- +title: asm.js +slug: Games/Инструменты/asm.js +tags: + - JavaScript + - WebAssembly + - asm.js +translation_of: Games/Tools/asm.js +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/en-US/docs/Games")}}
+ +
+

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 также зависит от браузера и от оборудования.

diff --git a/files/ru/games/tools/index.html b/files/ru/games/tools/index.html new file mode 100644 index 0000000000..8981085874 --- /dev/null +++ b/files/ru/games/tools/index.html @@ -0,0 +1,33 @@ +--- +title: Инструменты для разработки игр +slug: Games/Инструменты +translation_of: Games/Tools +--- +
{{GamesSidebar}}
{{IncludeSubnav("/en-US/docs/Games")}}
+ +
+

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

+
+ +
+
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 года)
  • +
+
+
diff --git a/files/ru/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.html b/files/ru/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.html new file mode 100644 index 0000000000..aedabaaf25 --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.html @@ -0,0 +1,42 @@ +--- +title: Отскакивания +slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Bounce_off_the_walls +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Bounce_off_the_walls +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs/")}}
+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Physics", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Платформа_и_управление")}}

+ +
+

Это 6 урок из 16 Руководства разработки игры с помощью Phaser. Вы можете найти исходный код того как должен выглядеть код после завершения урока здесь: Gamedev-Phaser-Content-Kit/demos/lesson06.html.

+
+ +

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

+ +

Отскакивание от границ представления

+ +

Самый простой способ заставить мячик от стен это сообщить фреймворку что мы хотим рассматривать границы элемента {{htmlelement("canvas")}} как стены и не позволять мячу проходить через них. В Phaser это может быть просто реализовано с помощью свойства collideWorldsBound. Добавьте этот код сразу после существующего вызова метода game.physics.enable():

+ +
ball.body.collideWorldBounds = true;
+
+ +

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

+ +
ball.body.bounce.set(1);
+
+ +

Попробуйте перезагрузить index.html опять — теперь мяч отскакивает от стен и движется внутри холста canvas.

+ +

Сравните ваш код

+ +

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

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/dcw36opz/","","400")}}

+ +

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

+ +

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

+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Physics", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Платформа_и_управление")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.html b/files/ru/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.html new file mode 100644 index 0000000000..ffdd6c1d6d --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.html @@ -0,0 +1,156 @@ +--- +title: Создание кирпичей +slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Создание_кирпичей +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Build_the_brick_field +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs/Games")}}
+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Game_over", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Обработка_коллизий")}}

+ +
+

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

+
+ +

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

+ +

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

+ +

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

+ +
var bricks;
+var newBrick;
+var brickInfo;
+
+ +

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

+ +

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

+ +

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

+ +
function preload() {
+    // ...
+    game.load.image('brick', 'img/brick.png');
+}
+
+ +

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

+ +

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

+ +

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

+ +
function create(){
+    // ...
+    initBricks();
+}
+
+ +

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

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

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

+ +

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

+ +
bricks = game.add.group();
+
+ +

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

+ +
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. Для этого добавим во вложенный цикл немного кода, как показано ниже:

+ +
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 в каждой итерации. Обновите строки инициализации этих переменных, как показано ниже:

+ +
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():

+ +
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, то увидете кирпичи, нарисованные на расстоянии друг от друга.

+ +

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

+ +

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

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/cck2b9e8/","","400")}}

+ +

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

+ +

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

+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Game_over", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Обработка_коллизий")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_phaser/collision_detection/index.html b/files/ru/games/tutorials/2d_breakout_game_phaser/collision_detection/index.html new file mode 100644 index 0000000000..e3fb27724b --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_phaser/collision_detection/index.html @@ -0,0 +1,52 @@ +--- +title: Обработка коллизий +slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Обработка_коллизий +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Collision_detection +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs")}}
+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Создание_кирпичей", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Очки")}}

+ +
+

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

+
+ +

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

+ +

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

+ +

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

+ +
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>:

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

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

+ +

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

+ +

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

+ +

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

+ +

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

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/wwneakwf/","","400")}}

+ +

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

+ +

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

+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Создание_кирпичей", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Очки")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_phaser/extra_lives/index.html b/files/ru/games/tutorials/2d_breakout_game_phaser/extra_lives/index.html new file mode 100644 index 0000000000..b6bb403469 --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_phaser/extra_lives/index.html @@ -0,0 +1,117 @@ +--- +title: Жизни +slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Жизни +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Extra_lives +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs")}}
+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Победа", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Анимация")}}

+ +
+

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

+
+ +

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

+ +

Новый переменные

+ +

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

+ +
var lives = 3;
+var livesText;
+var lifeLostText;
+
+ +

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

+ +

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

+ +

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

+ +
livesText = game.add.text(game.world.width-5, 5, 'Lives: '+lives, { font: '18px Arial', fill: '#0095DD' });
+livesText.anchor.set(1,0);
+lifeLostText = game.add.text(game.world.width*0.5, game.world.height*0.5, 'Life lost, click to continue', { font: '18px Arial', fill: '#0095DD' });
+lifeLostText.anchor.set(0.5);
+lifeLostText.visible = false;
+
+ +

Объекты livesText иlifeLostText очень похожи на scoreText — они определяют положение на экране, текст надписи и стилизацию шрифта. Чтобы всё выглядило должным образом, надпись с жизнями мы закрепляем в правом верхнем углу, а надпись о потере жизни, мы выводим в центре экрана. И всё это при помощи функции anchor.set().

+ +

Надпись lifeLostText появится только при потере жизни, поэтому её видимость мы выставляем в false.

+ +

Чистим код, стилизирующий надписи

+ +

Как вы могли заметить, мы используем одинаковые стили для всех надписей: scoreText, livesText и lifeLostText. Однако, налицо копирование кода и если мы, когда-либо, захотим изменить размер шрифта или цвет, то нам придётся делать это в нескольких местах. Чтобы избежать этого, мы вынесем стиль в отдельную переменную. Напишите следующую строку сразу после всех наших текущих опеределений переменных:

+ +
var textStyle = { font: '18px Arial', fill: '#0095DD' };
+
+ +

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

+ +
scoreText = game.add.text(5, 5, 'Points: 0', textStyle);
+livesText = game.add.text(game.world.width-5, 5, 'Lives: '+lives, textStyle);
+livesText.anchor.set(1,0);
+lifeLostText = game.add.text(game.world.width*0.5, game.world.height*0.5, 'Life lost, click to continue', textStyle);
+lifeLostText.anchor.set(0.5);
+lifeLostText.visible = false;
+
+ +

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

+ +

Код обработки жизни

+ +

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

+ +
ball.events.onOutOfBounds.add(function(){
+    alert('Game over!');
+    location.reload();
+}, this);
+
+ +

Мы объявим новую функцию ballLeaveScreen; Удалим предыдущий обработчик (зачёркнутый код сверху) и заменим его следующей линией:

+ +
ball.events.onOutOfBounds.add(ballLeaveScreen, this);
+
+ +

Мы будем уменьшать количество жизней каждый раз, когда шар выйдет за пределы окна Canvas. Добавьте функцию ballLeaveScreen() в конец кода:

+ +
function ballLeaveScreen() {
+    lives--;
+    if(lives) {
+        livesText.setText('Lives: '+lives);
+        lifeLostText.visible = true;
+        ball.reset(game.world.width*0.5, game.world.height-25);
+        paddle.reset(game.world.width*0.5, game.world.height-5);
+        game.input.onDown.addOnce(function(){
+            lifeLostText.visible = false;
+            ball.body.velocity.set(150, -150);
+        }, this);
+    }
+    else {
+        alert('You lost, game over!');
+        location.reload();
+    }
+}
+
+ +

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

+ +

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

+ +

События

+ +

Скорее всего вы заметили вызов методов add() и addOnce() в двух блоках кода выше и хотите знать, чем они отличаются. Разница в том, что метод add()  и привязанная к нему функция выполняется каждый раз, когда выполняется событие, тогда как метод  addOnce() полезен, когда вы хотите, чтобы связанная с ним функция выполнилась единожды и не повторялась снова. В нашем случае при каждом событии outOfBounds будет выполняться ballLeaveScreen, но когда мяч покидает экран, сообщение с экрана удалится единожды.

+ +

Проверь свой код

+ +

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

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/yk1c5n0b/","","400")}}

+ +

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

+ +

Жизни делают игру более казуальной — даже если вы проиграете единожды, у вас будут еще 2 жизни и вы сможете продолжить игру. Теперь мы можем поработать над внешним видом игры, сделать ее более красивой, добавив анимацию и эффекты .

+ +

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Win_the_game", "Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_phaser/game_over/index.html b/files/ru/games/tutorials/2d_breakout_game_phaser/game_over/index.html new file mode 100644 index 0000000000..a617f8969d --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_phaser/game_over/index.html @@ -0,0 +1,46 @@ +--- +title: Game over +slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Game_over +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Game_over +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs/Games")}}
+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Платформа_и_управление", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Создание_кирпичей")}}

+ +
+

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

+
+ +

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

+ +

Проигрыш

+ +

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

+ +
game.physics.arcade.checkCollision.down = false;
+
+ +

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

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

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

+ +

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

+ +

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

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/436bckb7/","","400")}}

+ +

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

+ +

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

+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Платформа_и_управление", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Создание_кирпичей")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_phaser/index.html b/files/ru/games/tutorials/2d_breakout_game_phaser/index.html new file mode 100644 index 0000000000..05a0439cc7 --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_phaser/index.html @@ -0,0 +1,64 @@ +--- +title: 2D игра на Phaser +slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser +tags: + - 2D + - Canvas + - JavaScript + - Phaser + - Игры + - Начинающий + - Руководство + - туториал +translation_of: Games/Tutorials/2D_breakout_game_Phaser +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs/")}}
+ +

{{Next("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Initialize_the_framework")}}

+ +

В этом пошаговом руководстве мы создадим простую мобильную игру 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.

+ +

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

+ +

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

+ +
    +
  1. Инициализация фреймворка
  2. +
  3. Масштабирование
  4. +
  5. Загрузка ресурсов и их вывод
  6. +
  7. Движение мяча
  8. +
  9. Физика
  10. +
  11. Отскакивание от стен
  12. +
  13. Управление
  14. +
  15. Конец игры
  16. +
  17. Создание поля блоков
  18. +
  19. Определение столкновения
  20. +
  21. Счёт
  22. +
  23. Победа в игре
  24. +
  25. Добавление жизней
  26. +
  27. Анимация
  28. +
  29. Кнопки
  30. +
  31. Создание случайных событий
  32. +
+ +

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

+ +

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

+ +
+

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

+
+ +

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

+ +

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

+ +

{{Next("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Initialize_the_framework")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.html b/files/ru/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.html new file mode 100644 index 0000000000..bf1fac5bfc --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.html @@ -0,0 +1,95 @@ +--- +title: Инициализация фреймворка +slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Initialize_the_framework +tags: + - 2D + - Canvas + - HTML + - JavaScript + - Phaser + - Игры + - Руководство +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Initialize_the_framework +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("ru/docs/")}}
+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Scaling")}}

+ +
+

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

+
+ +

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

+ +

HTML-код игры

+ +

Структура HTML-документа достаточно простая. Игра будет отображаться в элементе {{htmlelement("canvas")}}, который будет сгенерирован фреймворком. Используя свой любимый редактор, создайте новый HTML-документ, сохраните его как index.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. +
  3. Выберите наиболее удобный для вас вариант загрузки. Я рекоммендую min.js скачивание, потому что исходный код будет меньше, да и вам не придётся разбираться в нём.
  4. +
  5. Сохраните Phaser внутри /js директории, находящейся в том же месте, что и index.html
  6. +
  7. Обновите аттрибут src в первом элементе {{htmlelement("script")}}, как это показано выше.
  8. +
+ +

Что мы имеем

+ +

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

+ +

Фреймворк автоматически создаёт элемент {{htmlelement("canvas")}}. Мы инициализировали его, создав новый Phaser.Game объект и присвоив его переменной. Также мы добавили параметры:

+ + + +
+

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

+
+ +

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

+ +

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

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/h6cwzv2b/","","400")}}

+ +

Следующее

+ +

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

+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Scaling")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.html b/files/ru/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.html new file mode 100644 index 0000000000..57274a84c0 --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.html @@ -0,0 +1,73 @@ +--- +title: Загрузка ресурсов и их вывод +slug: >- + Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Load_the_assets_and_print_them_on_screen +tags: + - 2D + - Canvas + - JavaScript + - Phaser +translation_of: >- + Games/Tutorials/2D_breakout_game_Phaser/Load_the_assets_and_print_them_on_screen +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs/Games")}}
+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Scaling", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Move_the_ball")}}

+ +
+

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

+
+ +

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

+ +

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

+ +

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

+ +
var ball;
+
+ +
+

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

+
+ +

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

+ +

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

+ +
function preload() {
+    // ...
+    game.load.image('ball', 'img/ball.png');
+}
+
+ +

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

+ +

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

+ +

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

+ +
function create() {
+    ball = game.add.sprite(50, 50, 'ball');
+}
+
+ +

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

+ +
+

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

+
+ +

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

+ +

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

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/98xrv9x5/","","400")}}

+ +

Следующее

+ +

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

+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Scaling", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Move_the_ball")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.html b/files/ru/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.html new file mode 100644 index 0000000000..deed4a9494 --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.html @@ -0,0 +1,48 @@ +--- +title: Движение мяча +slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Move_the_ball +tags: + - 2D + - Beginner + - Canvas + - JavaScript + - Phaser +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Move_the_ball +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs/")}}
+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Load_the_assets_and_print_them_on_screen", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Physics")}}

+ +
+

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

+
+ +

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

+ +

Обновление позиции мяча на каждом кадре

+ +

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

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

Код выше добавляет 1 к свойствам x и y, которые отвечают за координаты мяча в canvas на каждом кадре. Перезагрузив index.html, вы должны увидеть, как наш мячик движется. 

+ +

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

+ +

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

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/g1cfp0vv/","","400")}}

+ +

Следующее

+ +

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

+ +

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

+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Load_the_assets_and_print_them_on_screen", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Physics")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_phaser/physics/index.html b/files/ru/games/tutorials/2d_breakout_game_phaser/physics/index.html new file mode 100644 index 0000000000..20acffa239 --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_phaser/physics/index.html @@ -0,0 +1,98 @@ +--- +title: Физика +slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Physics +tags: + - 2D + - Beginner + - Canvas + - JavaScript + - Phaser +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Physics +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs")}}
+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Move_the_ball", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Bounce_off_the_walls")}}

+ +
+

Это 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():

+ +
game.physics.startSystem(Phaser.Physics.ARCADE);
+
+ +

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

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

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

+ +
ball.body.velocity.set(150, 150);
+
+ +

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

+ +

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

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

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

+ +

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

+ +

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

+ +
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.

+ +

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

+ +

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

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/bjto9nj8/","","400")}}

+ +

Следующее

+ +

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

+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Move_the_ball", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Bounce_off_the_walls")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.html b/files/ru/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.html new file mode 100644 index 0000000000..46713cdddb --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.html @@ -0,0 +1,116 @@ +--- +title: Платформа и управление +slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Платформа_и_управление +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Player_paddle_and_controls +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs/")}}
+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Bounce_off_the_walls", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Game_over")}}

+ +
+

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

+
+ +

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

+ +

Рисуем платформу

+ +

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

+ +

Создаем платформу

+ +

Сначала, добавим переменную paddle, сразу после переменной ball:

+ +
var paddle;
+
+ +

После этого, в функции preload, загрузим изображение paddle при помощи ещё одного вызова функции load.image():

+ +
function preload() {
+    // ...
+    game.load.image('ball', 'img/ball.png');
+    game.load.image('paddle', 'img/paddle.png');
+}
+
+ +

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

+ +

Чуть не забыли, на этом этапе нам надо скачать изображение платформы с Github в папку /img.

+ +

Рисуем платформу с физикой

+ +

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

+ +
paddle = game.add.sprite(game.world.width*0.5, game.world.height-5, 'paddle');
+
+ +

Мы можем использовать world.width и world.height для позиционирования платформы в том месте, где мы хотим: game.world.width*0.5 расположит платформу прямо по середине экрана. В данном случае, нам повезло, что наш игровой мир совпадает с <canvas>, однако, в других играх мир может быть гараздо больше экрана. 

+ +

Как вы могли заметить, перезагрузив, на данном этапе, страницу index.html, платформа находится не совсем по середине экрана. Почему? Всё дело в том, что, по умолчанию, точка, из которой начинается позиционирование объекта (якорь), находится в левом верхнем углу. Но мы можем это изменить и переместить якорь в середину платформы по ширине и в самый низ повысоте, чтобы проще было позиционировать платформу, относительно нижней грани экрана. Добавьте следующую строку кода:

+ +
paddle.anchor.set(0.5,1);
+
+ +

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

+ +
game.physics.enable(paddle, Phaser.Physics.ARCADE);
+
+ +

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

+ +
function update() {
+    game.physics.arcade.collide(ball, paddle);
+}
+
+ +

В качестве аргументов, мы передаём два объекта, между которыми проверяются коллизии — в нашем случае, мячик и платформа. Вроде, сработало, но не совсем так, как мы ожидали — когда мячик сталкивается с платформой, последняя падает за пределы экрана! А мы, всего лишь, хотим, чтобы мячик отскакивал от платформы, а платформа, при этом, оставалась на месте. Мы можем использовать свойство immovable, для того, чтобы платформа не двигалась, когда мячик бьётся об неё. Для этого добавьте следующую строку кода в конец функции create():

+ +
paddle.body.immovable = true;
+
+ +

Вот! Теперь всё работает, как надо.

+ +

Управляем платформой

+ +

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

+ +
function update() {
+    game.physics.arcade.collide(ball, paddle);
+    paddle.x = game.input.x;
+}
+
+ +

Теперь, каждый кадр координата x платформы будет соответствовать координате x курсора. Однако, при старте игры, положение нашей платформы не по центру экрана, из-за того, что положение курсора не определено. Чтобы это исправить, давайте добавим платформе координату x по умолчанию, на случаей, если положение курсора не определено. Обновите предыдущую строку кода:

+ +
paddle.x = game.input.x || game.world.width*0.5;
+
+ +

Если вы этого ещё не сделали, то обновите страницу index.html и попробуйте то, что у нас получилось!

+ +

Расположение мячика

+ +

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

+ +
ball = game.add.sprite(game.world.width*0.5, game.world.height-25, 'ball');
+ball.anchor.set(0.5);
+ +

Скорость оставим такую же, но изменим направление по оси y, изменив второй параметр со 150 на -150, и теперь мяч будет двигаться вверх. Найдите строку ball.body.velocity.set( ... ) и измените её, как показано ниже:

+ +
ball.body.velocity.set(150, -150);
+
+ +

Теперь мячик появляется по середине платформы и двигается вверх.

+ +

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

+ +

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

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/ogqza0ye/","","400")}}

+ +

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

+ +

Мы можем управлять платформой и сделали так, чтобы мячик отскакивал от неё. Но какой от этого толк, если мячик отскакивает и от нижней грани экрана? В следующей главе мы добавим логику проигрыша и экран "Game over".

+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Bounce_off_the_walls", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Game_over")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_phaser/scaling/index.html b/files/ru/games/tutorials/2d_breakout_game_phaser/scaling/index.html new file mode 100644 index 0000000000..395e9f52de --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_phaser/scaling/index.html @@ -0,0 +1,64 @@ +--- +title: Масштабирование +slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Scaling +tags: + - 2D + - Canvas + - JavaScript + - Phaser + - Начинающий +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Scaling +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs/Games")}}
+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Initialize_the_framework", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Load_the_assets_and_print_them_on_screen")}}

+ +
+

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

+
+ +

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

+ +

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

+ +

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

+ +
function preload() {
+    game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
+    game.scale.pageAlignHorizontally = true;
+    game.scale.pageAlignVertically = true;
+}
+
+ +

scaleMode имеет несколько опций, которые определяют, как {{htmlelement("canvas")}} будет масштабироваться:

+ + + +

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

+ +

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

+ +

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

+ +
game.stage.backgroundColor = '#eee';
+
+ +

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

+ +

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

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/6a64vecL/","","400")}}

+ +

Следующее

+ +

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

+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Initialize_the_framework", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Load_the_assets_and_print_them_on_screen")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_phaser/the_score/index.html b/files/ru/games/tutorials/2d_breakout_game_phaser/the_score/index.html new file mode 100644 index 0000000000..9f4b18ace1 --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_phaser/the_score/index.html @@ -0,0 +1,69 @@ +--- +title: Очки +slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Очки +translation_of: Games/Tutorials/2D_breakout_game_Phaser/The_score +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs/")}}
+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Обработка_коллизий", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Победа")}}

+ +
+

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

+
+ +

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

+ +

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

+ +

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

+ +

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

+ +
// ...
+var scoreText;
+var score = 0;
+
+ +

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

+ +

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

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

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

+ + + +

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

+ +

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

+ +

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

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

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

+ +

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

+ +

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

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/n8o6rhrf/","","400")}}

+ +

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

+ +

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

+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Обработка_коллизий", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Победа")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_phaser/win_the_game/index.html b/files/ru/games/tutorials/2d_breakout_game_phaser/win_the_game/index.html new file mode 100644 index 0000000000..21ff763bbf --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_phaser/win_the_game/index.html @@ -0,0 +1,54 @@ +--- +title: Победа +slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Победа +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Win_the_game +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs/Games")}}
+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Очки", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Жизни")}}

+ +
+

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

+
+ +

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

+ +

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

+ +

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

+ +
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 у каждого кирпича и, если все кирпичи разрушены, выведем всплывающее окно с текстом о победе. После закрытия этого окна, страница перезагрузится.

+ +

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

+ +

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

+ + + +

{{JSFiddleEmbed("https://jsfiddle.net/u8waa4Lx/1/","","400")}}

+ +

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

+ +

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

+ +

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Очки", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Жизни")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.html b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.html new file mode 100644 index 0000000000..91c7ea5405 --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.html @@ -0,0 +1,119 @@ +--- +title: Создаем зону кирпичей +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Создаем_зону_кирпичей +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Build_the_brick_field +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

{{PreviousNext("Games/Tutorials/2D_Breakout_game_pure_JavaScript/Game_over", "Games/Tutorials/2D_Breakout_game_pure_JavaScript/Collision_detection")}}

+ +
+

Это 6 шаг из 10 в Gamedev Canvas tutorial. Вы можете найти исходный код, как он будет выглядеть после завершения этого урока, тут - Gamedev-Canvas-workshop/lesson6.html.

+
+ +

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

+ +

Настройка переменных кирпича

+ +

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

+ +
var brickRowCount = 3;
+var brickColumnCount = 5;
+var brickWidth = 75;
+var brickHeight = 20;
+var brickPadding = 10;
+var brickOffsetTop = 30;
+var brickOffsetLeft = 30;
+ + + +

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

+ +

Мы будем держать все наши кирпичи в двумерном массиве. Он будет содержать кирпичные столбцы (c), которые, в свою очередь, будут содержать кирпичные ряды (r), которые, в свою очередь, будут содержать объект, содержащий положение x и yчтобы рисовать каждый кирпич на экране. Добавьте следующие значения ниже ваших переменных:

+ + + +
var bricks = [];
+for(var c=0; c<brickColumnCount; c++) {
+    bricks[c] = [];
+    for(var r=0; r<brickRowCount; r++) {
+        bricks[c][r] = { x: 0, y: 0 };
+    }
+}
+ +

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

+ +

Механизм отрисовки кирпичей

+ +

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

+ +
function drawBricks() {
+    for(var c=0; c<brickColumnCount; c++) {
+        for(var r=0; r<brickRowCount; r++) {
+            bricks[c][r].x = 0;
+            bricks[c][r].y = 0;
+            ctx.beginPath();
+            ctx.rect(0, 0, brickWidth, brickHeight);
+            ctx.fillStyle = "#0095DD";
+            ctx.fill();
+            ctx.closePath();
+        }
+    }
+}
+ +

Опять же, мы зацикливаем строки и столбцы, чтобы установить положение x и yкаждого кирпича, и мы также brickWidth кирпич на кирпичной brickWidth Canvas -brickWidth - с каждой итерацией цикла. Проблема в том, что мы рисуем их все в одном месте, в координатах (0,0) . Нам нужно включить некоторые вычисления, которые будут определять положение x и y каждого кирпича для каждой итерации цикла:

+ +
var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
+var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
+ + + +

Каждая позиция brickX разрабатывается как brickWidth + brickPadding , умноженная на номер столбца, c , плюс brickOffsetLeft ; логика для brickY идентична, за исключением того, что она использует значения для номера строки, rbrickHeight и brickOffsetTop . Теперь каждый отдельный кирпич может быть помещен в правильное место и столбец места, с отступом между каждым кирпичом, нарисованным на смещение от левого и верхнего краев холста.

+ +

Окончательная версия функции drawBricks() после назначения brickX и brickY в качестве координат вместо (0,0) каждый раз будет выглядеть следующим образом: добавьте это в свой код ниже функции drawPaddle() :

+ + + +
    for(var c=0; c<brickColumnCount; c++) {
+        for(var r=0; r<brickRowCount; r++) {
+            var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
+            var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
+            bricks[c][r].x = brickX;
+            bricks[c][r].y = brickY;
+            ctx.beginPath();
+            ctx.rect(brickX, brickY, brickWidth, brickHeight);
+            ctx.fillStyle = "#0095DD";
+            ctx.fill();
+            ctx.closePath();
+        }
+    }
+}
+ +

Сама отрисовка кирпичей

+ +

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

+ +
drawBricks();
+
+ +

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

+ + + +

На этом этапе игра снова стала интереснее:

+ + + +

{{JSFiddleEmbed("https://jsfiddle.net/yumetodo/t1zqmzLp/","","395")}}

+ +
+

Упражнение: попробуйте изменить количество кирпичей в строке или столбце или их позиции.

+
+ +

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

+ +

Итак, теперь у нас есть кирпичи! Но мяч вообще не взаимодействует с ними - мы изменим это, поскольку мы переходим в седьмую главу: Collision detection.

+ +

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.html b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.html new file mode 100644 index 0000000000..576f17e7cc --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.html @@ -0,0 +1,128 @@ +--- +title: Обнаружение столкновений +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Обнаружение_столкновений +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Collision_detection +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

{{PreviousNext("Games/Tutorials/2D_Breakout_game_pure_JavaScript/Создаем_зону_кирпичей", "Games/Tutorials/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win")}}

+ +
+

Это 7 шаг из 10 в Gamedev Canvas tutorial. Вы можете найти исходный код, как он будет выглядеть после завершения этого урока, тут Gamedev-Canvas-workshop/lesson7.html.

+ +

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

+
+ +

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

+ +

Функция обнаружения столкновения

+ +

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

+ +
function collisionDetection() {
+    for(var c=0; c<brickColumnCount; c++) {
+        for(var r=0; r<brickRowCount; r++) {
+            var b = bricks[c][r];
+            // calculations
+        }
+    }
+}
+ +

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

+ + + +

Давайте напишем это в коде:

+ +
function collisionDetection() {
+    for(var c=0; c<brickColumnCount; c++) {
+        for(var r=0; r<brickRowCount; r++) {
+            var b = bricks[c][r];
+            if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
+                dy = -dy;
+            }
+        }
+    }
+}
+ +

Добавьте вышеприведенный блок к вашему коду под keyUpHandler() функцией .

+ +

Удаление кирпичей после их попадания

+ +

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

+ +
var bricks = [];
+for(var c=0; c<brickColumnCount; c++) {
+    bricks[c] = [];
+    for(var r=0; r<brickRowCount; r++) {
+        bricks[c][r] = { x: 0, y: 0, status: 1 };
+    }
+}
+ +

Теперь мы будем проверять значение свойства status каждого кирпича в функции drawBricks() перед его рисованием - если status равен 1 , нарисуем его, а если равен 0 , то значит в него попал мяч и он не должен больше отрисовываться. Отредактируйте drawBricks() следующим образом:

+ +
function drawBricks() {
+    for(var c=0; c<brickColumnCount; c++) {
+        for(var r=0; r<brickRowCount; r++) {
+            if(bricks[c][r].status == 1) {
+                var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
+                var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
+                bricks[c][r].x = brickX;
+                bricks[c][r].y = brickY;
+                ctx.beginPath();
+                ctx.rect(brickX, brickY, brickWidth, brickHeight);
+                ctx.fillStyle = "#0095DD";
+                ctx.fill();
+                ctx.closePath();
+            }
+        }
+    }
+}
+ +

Отслеживание и обновление состояния в функции обнаружения столкновений

+ +

Теперь нам нужно задействовать свойство status кирпича в функции collisionDetection() : если кирпич активен (его статус равен 1 ), мы проверяем, было ли столкновение; если да, мы устанавливаем статус данного кирпича равным 0, чтобы он не был нарисован на экране. Отредактируйте функцию collisionDetection(), как показано ниже:

+ +
function collisionDetection() {
+    for(var c=0; c<brickColumnCount; c++) {
+        for(var r=0; r<brickRowCount; r++) {
+            var b = bricks[c][r];
+            if(b.status == 1) {
+                if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
+                    dy = -dy;
+                    b.status = 0;
+                }
+            }
+        }
+    }
+}
+ +

Активация нашего обнаружения столкновений

+ +

Последнее, что нужно сделать, это добавить вызов функции collisionDetection() в нашу основную функцию draw() . Добавьте следующую строку в функцию draw() , чуть ниже drawPaddle() :

+ +
collisionDetection();
+
+ +

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

+ +

Обнаружение столкновения шара теперь выполняется на каждом кадре и для каждого кирпича. Теперь мы можем ломать кирпичи! : -

+ +

{{JSFiddleEmbed("https://jsfiddle.net/yumetodo/mkwtxgc3/3/","","395")}}

+ +
+

Упражнение : измените цвет шара, когда он ударит по кирпичу.

+
+ +

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

+ +

Мы уверенно движемся вперёд! Поехали! В восьмой главе мы будем учиться отслеживать счет и выигрывать .

+ +

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.html b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.html new file mode 100644 index 0000000000..84f23b0e2a --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.html @@ -0,0 +1,115 @@ +--- +title: Создание Canvas и рисование на нём +slug: >- + Games/Tutorials/2D_Breakout_game_pure_JavaScript/Создание_Canvas_и_рисование_на_нём +tags: + - JavaScript + - Игры + - разработка игр + - создание игр +translation_of: >- + Games/Tutorials/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/ru/docs/Games")}}
+ +

{{PreviousNext("Games/Tutorials/2D_Breakout_game_pure_JavaScript", "Games/Tutorials/2D_Breakout_game_pure_JavaScript/Переместить_мяч")}}

+ +
+

Это 1й шаг из 10 Gamedev Canvas tutorial. Вы можете найти исходный код для этого урока по ссылке Gamedev-Canvas-workshop/lesson1.html.

+
+ +

Прежде чем мы сможем начать писать функциональные возможности игры, нам необходимо создать базовую структуру для рендеринга игры внутри. Это можно сделать с помощью HTML и элемента {{htmlelement ("canvas")}}.

+ +

HTML игры

+ +

Структура HTML документа довольно проста, так как игра будет полностью визуализироваться в {{htmlelement("canvas")}} элементе. Используя Ваш любимый текстовый редактор, создайте новый HTML документ, сохраните его как index.html в любом удобном месте, и скопируйте в него этот код:

+ +
<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8" />
+    <title>Gamedev Canvas Workshop</title>
+    <style>
+    	* { padding: 0; margin: 0; }
+    	canvas { background: #eee; display: block; margin: 0 auto; }
+    </style>
+</head>
+<body>
+
+<canvas id="myCanvas" width="480" height="320"></canvas>
+
+<script>
+	// JavaScript код будем писать здесь
+</script>
+
+</body>
+</html>
+
+ +

Мы определили charset, {{htmlelement("title")}} и некий базовый CSS в заголовке. Тело документа содержит элементы {{htmlelement("canvas")}} и {{htmlelement("script")}} — мы будем визуализировать игру внутри первого и писать JavaScript код, который управляет игрой, во втором. Элемент {{htmlelement("canvas")}} имеет id равный myCanvas, который позволяет однозначно отыскать элемент. Так же этот элемент имеет ширину 480 пикселей и высоту 320 пикселей. Весь JavaScript код мы будем писать между открывающим тегом <script> и закрывающим тегом </script>.

+ +

Основы Canvas

+ +

Чтобы иметь возможность визуализировать игру в {{htmlelement("canvas")}} элементе, сначала мы должны сослаться на этот элемент в коде JavaScript. Добавьте следующий код после открывающего тега <script>.

+ +
var canvas = document.getElementById("myCanvas");
+var ctx = canvas.getContext("2d");
+ +

Таким образом, мы храним ссылку на {{htmlelement("canvas")}} элемент в переменной canvas. Далее мы создаём переменную ctx для хранения 2D визуализации контекста — метод, который используется для отрисовки в Canvas.

+ +

Давайте рассмотрим пример отрисовки красного квадрата на canvas. Добавьте этот код ниже предыдущего кода на JavaScript и загрузите index.html в браузере, чтобы посмотреть результат.

+ +
ctx.beginPath();
+ctx.rect(20, 40, 50, 50);
+ctx.fillStyle = "#FF0000";
+ctx.fill();
+ctx.closePath();
+ +

Все инструкции располагаются между методами {{domxref("CanvasRenderingContext2D.beginPath()","beginPath()")}} и {{domxref("CanvasRenderingContext2D.closePath()","closePath()")}}. Мы определяем прямоугольник, используя  {{domxref("CanvasRenderingContext2D.rect()","rect()")}}: первые два параметра определяют координаты верхнего левого угла прямоугольника на canvas, в то время, как два других параметра определяют ширину и высоту прямоугольника. В нашем случае прямоугольник нарисован на расстоянии 20 пикселей слева и 40 пикселей сверху, 50 пикселей в ширину и 50 пикселей в высоту, что делает его квадратом. Свойство {{domxref("CanvasRenderingContext2D.fillStyle","fillStyle")}} хранит цвет, который будет использован методом {{domxref("CanvasRenderingContext2D.fill()","fill()")}} для отрисовки нашего квадрата.

+ +

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

+ +
ctx.beginPath();
+ctx.arc(240, 160, 20, 0, Math.PI*2, false);
+ctx.fillStyle = "green";
+ctx.fill();
+ctx.closePath();
+ +

Как видите, мы снова используем методы {{domxref("CanvasRenderingContext2D.beginPath()","beginPath()")}} и {{domxref("CanvasRenderingContext2D.closePath()","closePath()")}}. Между ними наиболее важная часть кода - метод {{domxref("CanvasRenderingContext2D.arc()","arc()")}}. Он принимает шесть параметров:

+ + + +

Свойство {{domxref("CanvasRenderingContext2D.fillStyle","fillStyle")}} выглядит не так, как прежде. Это потому что, как и в CSS, цвет может быть задан в шестнадцатиричном формате, названием цвета, функцией rgba() , или же любым другим методом для цвета.

+ +

Вместо {{domxref("CanvasRenderingContext2D.fill()","fill()")}} и заполнения фигур цветом, можно использовать {{domxref("CanvasRenderingContext2D.stroke()","stroke()")}}, чтобы окрасить только внешнюю обводку фигуры. Попробуйте добавить этот код к Вашему коду JavaScript:

+ +
ctx.beginPath();
+ctx.rect(160, 10, 100, 40);
+ctx.strokeStyle = "rgba(0, 0, 255, 0.5)";
+ctx.stroke();
+ctx.closePath();
+ +

Код выше отрисовывает пустой прямоугольник с синей обводкой. Благодаря функции альфа-канала rgba() , голубой цвет полупрозрачный.

+ +

Сравните Ваш код

+ +

Здесь полный исходный код для первого урока, посмотреть онлайн можно на JSFiddle:

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/x62h15e2/","","395")}}

+ +
+

Упражнение: попробуйте изменить цвет и размер созданных фигур.

+
+ +

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

+ +

Сейчас мы создали базовый HTML и немного узнали о canvas, давайте на следующем шаге изучим, как Двигать мяч в нашей игре.

+ +

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/finishing_up/index.html b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/finishing_up/index.html new file mode 100644 index 0000000000..d8f40896e1 --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/finishing_up/index.html @@ -0,0 +1,103 @@ +--- +title: Заключение +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Заключение +tags: + - Игры + - Канва + - Начинающий + - жизни +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Finishing_up +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

{{Previous("Games/Tutorials/2D_Breakout_game_pure_JavaScript/Управление_мышью")}}

+ +
+

Это 10-й и заключительный шаг в Gamedev Canvas tutorial. Вы можете найти исходный код, как он должен выглядеть, после завершения этого урока в Gamedev-Canvas-workshop/lesson10.html.

+
+ +

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

+ +

Предоставление игроку нескольких жизней

+ +

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

+ +
var lives = 3;
+ +

Отрисовка счетчика жизни выглядит почти так же, как и счетчика баллов - добавьте в код следующую функцию под функцией drawScore() :

+ +
function drawLives() {
+    ctx.font = "16px Arial";
+    ctx.fillStyle = "#0095DD";
+    ctx.fillText("Lives: "+lives, canvas.width-65, 20);
+}
+ +

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

+ +
alert("GAME OVER");
+document.location.reload();
+clearInterval(interval); // Needed for Chrome to end game
+ +

Давайте добавим немного более сложную логику к ней, как показано ниже:

+ +
lives--;
+if(!lives) {
+    alert("GAME OVER");
+    document.location.reload();
+}
+else {
+    x = canvas.width/2;
+    y = canvas.height-30;
+    dx = 2;
+    dy = -2;
+    paddleX = (canvas.width-paddleWidth)/2;
+}
+ +

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

+ +

Визуализация дисплея жизней

+ +

Теперь вам нужно добавить вызов drawLives() внутри функции draw() и добавить его под вызовом drawScore().

+ +
drawLives();
+
+ +

Улучшение рендеринга с requestAnimationFrame()

+ +

Теперь давайте работать над чем-то, что не связано с игровой механикой, но с тем, как она рендерится. {{domxref("window.requestAnimationFrame", "requestAnimationFrame")}} поможет браузеру рендерить игру лучше, чем фиксированная частота кадров, которую в настоящее время мы реализовали, используя {{domxref("windowTimers.setInterval()", "setInterval()")}}. Замените следующую строку:

+ +
setInterval(draw, 10);
+ +

на:

+ +
draw();
+ +

и удалите каждый экземпляр:

+ +
clearInterval(interval); // Needed for Chrome to end game
+ +

Затем в самом низу функции draw() (непосредственно перед закрывающей фигурной скобкой) добавьте следующую строку, которая заставляет функцию draw() вызывать себя снова и снова:

+ +
requestAnimationFrame(draw);
+ +

Функция draw() теперь выполняется снова и снова в цикле requestAnimationFrame(), но вместо фиксированной частоты кадров в 10 миллисекунд, мы возвращаем управление частотой кадров обратно в браузер. Соответственно он будет синхронизировать частоту кадров и отображать фигуры только при необходимости. Это обеспечивает более эффективный и плавный цикл анимации, чем более старый метод setInterval().

+ +

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

+ +

Вот и все-финальная версия игры готова!

+ +

{{JSFiddleEmbed("https://jsfiddle.net/yumetodo/3becw9fy/1/","","395")}}

+ +
+

Упражнение: измените количество жизней и угол отскока мяча от биты.

+
+ +

Игра закончена - на данный момент!

+ +

Вы закончили все уроки — поздравляем! К этому моменту вы должны знать основы манипулирования canvas и логику простых 2D-игр. Сейчас самое время изучить некоторые фреймворки и продолжить разработку игр. Вы можете проверить аналог этой серии, 2D breakout game using Phaser или Cyber Orb built in Phaser учебник. Вы также можете просмотреть раздел Games section on MDN для вдохновения и  увеличения знаний.

+ +

Вы также можете вернуться на this tutorial series' index page учебника. Получайте удовольствие от написания кода!

+ +

{{Previous("Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/mouse_controls/index.html b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/mouse_controls/index.html new file mode 100644 index 0000000000..b3ab4efaca --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/mouse_controls/index.html @@ -0,0 +1,58 @@ +--- +title: Управление мышью +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Управление_мышью +tags: + - Игры + - Начинающий + - канвас + - мышь +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Mouse_controls +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

{{PreviousNext("Games/Tutorials/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win", "Games/Tutorials/2D_Breakout_game_pure_JavaScript/Заключение")}}

+ +
+

Это 9-й шаг из 10 в Gamedev Canvas tutorial. Вы можете найти исходный код к этому уроку в Gamedev-Canvas-workshop/lesson9.html.

+
+ +

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

+ +

Отслеживание движений мыши

+ +

Отслеживание движений мыши еще проще, чем прослушивание нажатий клавиш. Все, что нам нужно, это следить за событиями {{event("mousemove")}}. Добавьте следующую строку в том же месте, как и для других событий, чуть ниже keyup event:

+ +
document.addEventListener("mousemove", mouseMoveHandler, false);
+ +

Привязка движения ракетки к движению мыши

+ +

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

+ +
function mouseMoveHandler(e) {
+    var relativeX = e.clientX - canvas.offsetLeft;
+    if(relativeX > 0 && relativeX < canvas.width) {
+        paddleX = relativeX - paddleWidth/2;
+    }
+}
+ +

В этой функции мы сначала разрабатываем значение relativeX, которое равно горизонтальному положению мыши в окне браузера (e.clientX) минус расстояние между левым краем canvas и левым краем окна браузера (canvas.offsetLeft) - фактически это равно расстоянию между левым краем canvas и указателем мыши. Если относительный указатель позиции X больше нуля и меньше, чем ширина Canvas, указатель находится в пределах границы Canvas, и paddleX установки (крепится на левый край ракетки) - устанавливается на relativeX значение минус половина ширины ракетки, так что движение будет по отношению к середине ракетки.

+ +

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

+ +

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

+ +

Это последнее состояние кода для сравнения:

+ +

{{JSFiddleEmbed("https://jsfiddle.net/yumetodo/1L9ep9r2/1/","","395")}}

+ +
+

Упражнение: отрегулируйте границы движения ракетки так, что вся ракетка будет видна на обоих краях Canvas, а не только на его половину.

+
+ +

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

+ +

Теперь у нас есть полная игра, мы закончим нашу серию уроков с еще несколькими небольшими хитростями — Finishing up.

+ +

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Finishing_up")}}

diff --git a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.html b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.html new file mode 100644 index 0000000000..f6d26cfc52 --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.html @@ -0,0 +1,146 @@ +--- +title: Переместить мяч +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Переместить_мяч +tags: + - 2D + - Canvas + - Игры + - Обучение + - Цикл + - передвижение + - пишем игру на javascript +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Move_the_ball +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

{{PreviousNext("Games/Tutorials/2D_Breakout_game_pure_JavaScript/Создание_Canvas_и_рисование_на_нём", "Games/Tutorials/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls")}}

+ +
+

Это 2й шаг из 10 Gamedev Canvas tutorial. Вы можете найти исходный код для данного урока по ссылке Gamedev-Canvas-workshop/lesson2.html.

+
+ +

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

+ +

Определяем цикл рисования

+ +

Чтобы canvas постоянно обновлялся, необходимо определить функцию отрисовки, которая будет циклически запускаться с разными параметрами, чтобы изменять позицию элемента. Функцию можно циклически запускать с помощью JavaScript временной функции, такой как {{domxref("WindowTimers.setInterval()", "setInterval()")}} или {{domxref("window.requestAnimationFrame()", "requestAnimationFrame()")}}.

+ +

Удалите весь JavaScript код, который сейчас хранился в Вашем HTML файле, за исключением первых двух строк, и добавьте следующий код после них. Функция draw() будет исполняться внутри функции setInterval каждые 10 мс:

+ +
function draw() {
+    // код отрисовки
+}
+setInterval(draw, 10);
+ +

Благодаря бесконечности функции setInterval функция draw() будет выполняться каждые 10 мс бесконечно или же пока мы не остановим её. Теперь давайте нарисуем мяч - добавьте в свой код функцию draw():

+ +
ctx.beginPath();
+ctx.arc(50, 50, 10, 0, Math.PI*2);
+ctx.fillStyle = "#0095DD";
+ctx.fill();
+ctx.closePath();
+
+ +

Попробуйте сейчас Ваш обновлённый код - каждый раз мяч будет перерисовываться.

+ +

Перемещение

+ +

Вы не можете определить, перерисовывается ли мяч в конкретный момент, так как его позиция не меняется. Давайте исправим это. Прежде всего, в позиции (50,50) определим стартовую точку в нижней центральной части Canvas в переменной x и y, и потом используем их для определения текущего положения мяча.

+ +

Для начала добавьте следующие две строки до функции draw(), чтобы определить переменные x и y:

+ +
var x = canvas.width/2;
+var y = canvas.height-30;
+
+ +

Далее обновите функцию draw(), чтобы использовать переменные x и y в методе {{domxref("CanvasRenderingContext2D.arc()","arc()")}}, как показано на подсвеченной линии:

+ +
function draw() {
+    ctx.beginPath();
+    ctx.arc(x, y, 10, 0, Math.PI*2);
+    ctx.fillStyle = "#0095DD";
+    ctx.fill();
+    ctx.closePath();
+}
+
+ +

Теперь важная часть: мы хотим добавлять небольшое значение к переменным x и y после каждой итерации, чтобы заставить мяч двигаться. Давайте определим эти небольшие значения в переменных dx и dy и установим их 2 и -2 соответственно. Добавьте следующий код после определения переменных x и y:

+ +
var dx = 2;
+var dy = -2;
+
+ +

И последнее, необходимо обновить переменные x и y на значение dx и dy каждую итерацию, чтобы мяч отрисовывался каждый раз на новой позиции. Добавьте ещё две строки кода в функции draw():

+ +
function draw() {
+    ctx.beginPath();
+    ctx.arc(x, y, 10, 0, Math.PI*2);
+    ctx.fillStyle = "#0095DD";
+    ctx.fill();
+    ctx.closePath();
+    x += dx;
+    y += dy;
+}
+ +

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

+ +

+ +

Очищение объекта после каждого кадра

+ +

Мяч оставляет след, потому что мы рисуем круг на каждой итерации без удаления предыдущей отрисованной фигуры. Не переживайте, потому что существует метод для очистки canvas элемента: {{domxref("CanvasRenderingContext2D.clearRect()","clearRect()")}}. Этот метод принимает четыре параметра: x и y координаты верхнего левого угла прямоугольника, x и y координаты нижнего правого угла прямоугольника. Вся площадь, покрытая прямоугольником, будет очищена от любого содержимого, которое когда-либо было там отрисовано.

+ +

Добавьте следующую подсвеченную строку в функцию draw():

+ +
function draw() {
+    ctx.clearRect(0, 0, canvas.width, canvas.height);
+    ctx.beginPath();
+    ctx.arc(x, y, 10, 0, Math.PI*2);
+    ctx.fillStyle = "#0095DD";
+    ctx.fill();
+    ctx.closePath();
+    x += dx;
+    y += dy;
+}
+
+ +

Сохраните Ваш код и попробуйте снова, и на этот раз Вы увидите, что мяч перемещается без следов. Каждые 10 мс canvas очищается, голубой круг (наш мяч) отрисовывается на заданной позиции, переменные x и y каждую итерацию обновляются.

+ +

Рефакторинг

+ +

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

+ +

Замените существующую функцию draw() следующими двумя функциями:

+ +
function drawBall() {
+    ctx.beginPath();
+    ctx.arc(x, y, 10, 0, Math.PI*2);
+    ctx.fillStyle = "#0095DD";
+    ctx.fill();
+    ctx.closePath();
+}
+
+function draw() {
+    ctx.clearRect(0, 0, canvas.width, canvas.height);
+    drawBall();
+    x += dx;
+    y += dy;
+}
+ +

Сравните Ваш код

+ +

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

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/3x5foxb1/","","395")}}

+ +
+

Упражнение: попробуйте изменить скорость перемещения мяча, или направление перемещения.

+
+ +

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

+ +

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

+ +

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls")}}

diff --git "a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\320\267\320\260\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265/index.html" "b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\320\267\320\260\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265/index.html" deleted file mode 100644 index d8f40896e1..0000000000 --- "a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\320\267\320\260\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265/index.html" +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: Заключение -slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Заключение -tags: - - Игры - - Канва - - Начинающий - - жизни -translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Finishing_up ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/en-US/docs/Games")}}
- -

{{Previous("Games/Tutorials/2D_Breakout_game_pure_JavaScript/Управление_мышью")}}

- -
-

Это 10-й и заключительный шаг в Gamedev Canvas tutorial. Вы можете найти исходный код, как он должен выглядеть, после завершения этого урока в Gamedev-Canvas-workshop/lesson10.html.

-
- -

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

- -

Предоставление игроку нескольких жизней

- -

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

- -
var lives = 3;
- -

Отрисовка счетчика жизни выглядит почти так же, как и счетчика баллов - добавьте в код следующую функцию под функцией drawScore() :

- -
function drawLives() {
-    ctx.font = "16px Arial";
-    ctx.fillStyle = "#0095DD";
-    ctx.fillText("Lives: "+lives, canvas.width-65, 20);
-}
- -

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

- -
alert("GAME OVER");
-document.location.reload();
-clearInterval(interval); // Needed for Chrome to end game
- -

Давайте добавим немного более сложную логику к ней, как показано ниже:

- -
lives--;
-if(!lives) {
-    alert("GAME OVER");
-    document.location.reload();
-}
-else {
-    x = canvas.width/2;
-    y = canvas.height-30;
-    dx = 2;
-    dy = -2;
-    paddleX = (canvas.width-paddleWidth)/2;
-}
- -

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

- -

Визуализация дисплея жизней

- -

Теперь вам нужно добавить вызов drawLives() внутри функции draw() и добавить его под вызовом drawScore().

- -
drawLives();
-
- -

Улучшение рендеринга с requestAnimationFrame()

- -

Теперь давайте работать над чем-то, что не связано с игровой механикой, но с тем, как она рендерится. {{domxref("window.requestAnimationFrame", "requestAnimationFrame")}} поможет браузеру рендерить игру лучше, чем фиксированная частота кадров, которую в настоящее время мы реализовали, используя {{domxref("windowTimers.setInterval()", "setInterval()")}}. Замените следующую строку:

- -
setInterval(draw, 10);
- -

на:

- -
draw();
- -

и удалите каждый экземпляр:

- -
clearInterval(interval); // Needed for Chrome to end game
- -

Затем в самом низу функции draw() (непосредственно перед закрывающей фигурной скобкой) добавьте следующую строку, которая заставляет функцию draw() вызывать себя снова и снова:

- -
requestAnimationFrame(draw);
- -

Функция draw() теперь выполняется снова и снова в цикле requestAnimationFrame(), но вместо фиксированной частоты кадров в 10 миллисекунд, мы возвращаем управление частотой кадров обратно в браузер. Соответственно он будет синхронизировать частоту кадров и отображать фигуры только при необходимости. Это обеспечивает более эффективный и плавный цикл анимации, чем более старый метод setInterval().

- -

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

- -

Вот и все-финальная версия игры готова!

- -

{{JSFiddleEmbed("https://jsfiddle.net/yumetodo/3becw9fy/1/","","395")}}

- -
-

Упражнение: измените количество жизней и угол отскока мяча от биты.

-
- -

Игра закончена - на данный момент!

- -

Вы закончили все уроки — поздравляем! К этому моменту вы должны знать основы манипулирования canvas и логику простых 2D-игр. Сейчас самое время изучить некоторые фреймворки и продолжить разработку игр. Вы можете проверить аналог этой серии, 2D breakout game using Phaser или Cyber Orb built in Phaser учебник. Вы также можете просмотреть раздел Games section on MDN для вдохновения и  увеличения знаний.

- -

Вы также можете вернуться на this tutorial series' index page учебника. Получайте удовольствие от написания кода!

- -

{{Previous("Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}}

diff --git "a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\320\276\320\261\320\275\320\260\321\200\321\203\320\266\320\265\320\275\320\270\320\265_\321\201\321\202\320\276\320\273\320\272\320\275\320\276\320\262\320\265\320\275\320\270\320\271/index.html" "b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\320\276\320\261\320\275\320\260\321\200\321\203\320\266\320\265\320\275\320\270\320\265_\321\201\321\202\320\276\320\273\320\272\320\275\320\276\320\262\320\265\320\275\320\270\320\271/index.html" deleted file mode 100644 index 576f17e7cc..0000000000 --- "a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\320\276\320\261\320\275\320\260\321\200\321\203\320\266\320\265\320\275\320\270\320\265_\321\201\321\202\320\276\320\273\320\272\320\275\320\276\320\262\320\265\320\275\320\270\320\271/index.html" +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: Обнаружение столкновений -slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Обнаружение_столкновений -translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Collision_detection ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/en-US/docs/Games")}}
- -

{{PreviousNext("Games/Tutorials/2D_Breakout_game_pure_JavaScript/Создаем_зону_кирпичей", "Games/Tutorials/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win")}}

- -
-

Это 7 шаг из 10 в Gamedev Canvas tutorial. Вы можете найти исходный код, как он будет выглядеть после завершения этого урока, тут Gamedev-Canvas-workshop/lesson7.html.

- -

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

-
- -

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

- -

Функция обнаружения столкновения

- -

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

- -
function collisionDetection() {
-    for(var c=0; c<brickColumnCount; c++) {
-        for(var r=0; r<brickRowCount; r++) {
-            var b = bricks[c][r];
-            // calculations
-        }
-    }
-}
- -

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

- - - -

Давайте напишем это в коде:

- -
function collisionDetection() {
-    for(var c=0; c<brickColumnCount; c++) {
-        for(var r=0; r<brickRowCount; r++) {
-            var b = bricks[c][r];
-            if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
-                dy = -dy;
-            }
-        }
-    }
-}
- -

Добавьте вышеприведенный блок к вашему коду под keyUpHandler() функцией .

- -

Удаление кирпичей после их попадания

- -

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

- -
var bricks = [];
-for(var c=0; c<brickColumnCount; c++) {
-    bricks[c] = [];
-    for(var r=0; r<brickRowCount; r++) {
-        bricks[c][r] = { x: 0, y: 0, status: 1 };
-    }
-}
- -

Теперь мы будем проверять значение свойства status каждого кирпича в функции drawBricks() перед его рисованием - если status равен 1 , нарисуем его, а если равен 0 , то значит в него попал мяч и он не должен больше отрисовываться. Отредактируйте drawBricks() следующим образом:

- -
function drawBricks() {
-    for(var c=0; c<brickColumnCount; c++) {
-        for(var r=0; r<brickRowCount; r++) {
-            if(bricks[c][r].status == 1) {
-                var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
-                var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
-                bricks[c][r].x = brickX;
-                bricks[c][r].y = brickY;
-                ctx.beginPath();
-                ctx.rect(brickX, brickY, brickWidth, brickHeight);
-                ctx.fillStyle = "#0095DD";
-                ctx.fill();
-                ctx.closePath();
-            }
-        }
-    }
-}
- -

Отслеживание и обновление состояния в функции обнаружения столкновений

- -

Теперь нам нужно задействовать свойство status кирпича в функции collisionDetection() : если кирпич активен (его статус равен 1 ), мы проверяем, было ли столкновение; если да, мы устанавливаем статус данного кирпича равным 0, чтобы он не был нарисован на экране. Отредактируйте функцию collisionDetection(), как показано ниже:

- -
function collisionDetection() {
-    for(var c=0; c<brickColumnCount; c++) {
-        for(var r=0; r<brickRowCount; r++) {
-            var b = bricks[c][r];
-            if(b.status == 1) {
-                if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
-                    dy = -dy;
-                    b.status = 0;
-                }
-            }
-        }
-    }
-}
- -

Активация нашего обнаружения столкновений

- -

Последнее, что нужно сделать, это добавить вызов функции collisionDetection() в нашу основную функцию draw() . Добавьте следующую строку в функцию draw() , чуть ниже drawPaddle() :

- -
collisionDetection();
-
- -

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

- -

Обнаружение столкновения шара теперь выполняется на каждом кадре и для каждого кирпича. Теперь мы можем ломать кирпичи! : -

- -

{{JSFiddleEmbed("https://jsfiddle.net/yumetodo/mkwtxgc3/3/","","395")}}

- -
-

Упражнение : измените цвет шара, когда он ударит по кирпичу.

-
- -

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

- -

Мы уверенно движемся вперёд! Поехали! В восьмой главе мы будем учиться отслеживать счет и выигрывать .

- -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win")}}

diff --git "a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\320\277\320\265\321\200\320\265\320\274\320\265\321\201\321\202\320\270\321\202\321\214_\320\274\321\217\321\207/index.html" "b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\320\277\320\265\321\200\320\265\320\274\320\265\321\201\321\202\320\270\321\202\321\214_\320\274\321\217\321\207/index.html" deleted file mode 100644 index f6d26cfc52..0000000000 --- "a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\320\277\320\265\321\200\320\265\320\274\320\265\321\201\321\202\320\270\321\202\321\214_\320\274\321\217\321\207/index.html" +++ /dev/null @@ -1,146 +0,0 @@ ---- -title: Переместить мяч -slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Переместить_мяч -tags: - - 2D - - Canvas - - Игры - - Обучение - - Цикл - - передвижение - - пишем игру на javascript -translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Move_the_ball ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/en-US/docs/Games")}}
- -

{{PreviousNext("Games/Tutorials/2D_Breakout_game_pure_JavaScript/Создание_Canvas_и_рисование_на_нём", "Games/Tutorials/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls")}}

- -
-

Это 2й шаг из 10 Gamedev Canvas tutorial. Вы можете найти исходный код для данного урока по ссылке Gamedev-Canvas-workshop/lesson2.html.

-
- -

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

- -

Определяем цикл рисования

- -

Чтобы canvas постоянно обновлялся, необходимо определить функцию отрисовки, которая будет циклически запускаться с разными параметрами, чтобы изменять позицию элемента. Функцию можно циклически запускать с помощью JavaScript временной функции, такой как {{domxref("WindowTimers.setInterval()", "setInterval()")}} или {{domxref("window.requestAnimationFrame()", "requestAnimationFrame()")}}.

- -

Удалите весь JavaScript код, который сейчас хранился в Вашем HTML файле, за исключением первых двух строк, и добавьте следующий код после них. Функция draw() будет исполняться внутри функции setInterval каждые 10 мс:

- -
function draw() {
-    // код отрисовки
-}
-setInterval(draw, 10);
- -

Благодаря бесконечности функции setInterval функция draw() будет выполняться каждые 10 мс бесконечно или же пока мы не остановим её. Теперь давайте нарисуем мяч - добавьте в свой код функцию draw():

- -
ctx.beginPath();
-ctx.arc(50, 50, 10, 0, Math.PI*2);
-ctx.fillStyle = "#0095DD";
-ctx.fill();
-ctx.closePath();
-
- -

Попробуйте сейчас Ваш обновлённый код - каждый раз мяч будет перерисовываться.

- -

Перемещение

- -

Вы не можете определить, перерисовывается ли мяч в конкретный момент, так как его позиция не меняется. Давайте исправим это. Прежде всего, в позиции (50,50) определим стартовую точку в нижней центральной части Canvas в переменной x и y, и потом используем их для определения текущего положения мяча.

- -

Для начала добавьте следующие две строки до функции draw(), чтобы определить переменные x и y:

- -
var x = canvas.width/2;
-var y = canvas.height-30;
-
- -

Далее обновите функцию draw(), чтобы использовать переменные x и y в методе {{domxref("CanvasRenderingContext2D.arc()","arc()")}}, как показано на подсвеченной линии:

- -
function draw() {
-    ctx.beginPath();
-    ctx.arc(x, y, 10, 0, Math.PI*2);
-    ctx.fillStyle = "#0095DD";
-    ctx.fill();
-    ctx.closePath();
-}
-
- -

Теперь важная часть: мы хотим добавлять небольшое значение к переменным x и y после каждой итерации, чтобы заставить мяч двигаться. Давайте определим эти небольшие значения в переменных dx и dy и установим их 2 и -2 соответственно. Добавьте следующий код после определения переменных x и y:

- -
var dx = 2;
-var dy = -2;
-
- -

И последнее, необходимо обновить переменные x и y на значение dx и dy каждую итерацию, чтобы мяч отрисовывался каждый раз на новой позиции. Добавьте ещё две строки кода в функции draw():

- -
function draw() {
-    ctx.beginPath();
-    ctx.arc(x, y, 10, 0, Math.PI*2);
-    ctx.fillStyle = "#0095DD";
-    ctx.fill();
-    ctx.closePath();
-    x += dx;
-    y += dy;
-}
- -

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

- -

- -

Очищение объекта после каждого кадра

- -

Мяч оставляет след, потому что мы рисуем круг на каждой итерации без удаления предыдущей отрисованной фигуры. Не переживайте, потому что существует метод для очистки canvas элемента: {{domxref("CanvasRenderingContext2D.clearRect()","clearRect()")}}. Этот метод принимает четыре параметра: x и y координаты верхнего левого угла прямоугольника, x и y координаты нижнего правого угла прямоугольника. Вся площадь, покрытая прямоугольником, будет очищена от любого содержимого, которое когда-либо было там отрисовано.

- -

Добавьте следующую подсвеченную строку в функцию draw():

- -
function draw() {
-    ctx.clearRect(0, 0, canvas.width, canvas.height);
-    ctx.beginPath();
-    ctx.arc(x, y, 10, 0, Math.PI*2);
-    ctx.fillStyle = "#0095DD";
-    ctx.fill();
-    ctx.closePath();
-    x += dx;
-    y += dy;
-}
-
- -

Сохраните Ваш код и попробуйте снова, и на этот раз Вы увидите, что мяч перемещается без следов. Каждые 10 мс canvas очищается, голубой круг (наш мяч) отрисовывается на заданной позиции, переменные x и y каждую итерацию обновляются.

- -

Рефакторинг

- -

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

- -

Замените существующую функцию draw() следующими двумя функциями:

- -
function drawBall() {
-    ctx.beginPath();
-    ctx.arc(x, y, 10, 0, Math.PI*2);
-    ctx.fillStyle = "#0095DD";
-    ctx.fill();
-    ctx.closePath();
-}
-
-function draw() {
-    ctx.clearRect(0, 0, canvas.width, canvas.height);
-    drawBall();
-    x += dx;
-    y += dy;
-}
- -

Сравните Ваш код

- -

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

- -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/3x5foxb1/","","395")}}

- -
-

Упражнение: попробуйте изменить скорость перемещения мяча, или направление перемещения.

-
- -

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

- -

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

- -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls")}}

diff --git "a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\321\201\320\276\320\267\320\264\320\260\320\265\320\274_\320\267\320\276\320\275\321\203_\320\272\320\270\321\200\320\277\320\270\321\207\320\265\320\271/index.html" "b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\321\201\320\276\320\267\320\264\320\260\320\265\320\274_\320\267\320\276\320\275\321\203_\320\272\320\270\321\200\320\277\320\270\321\207\320\265\320\271/index.html" deleted file mode 100644 index 91c7ea5405..0000000000 --- "a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\321\201\320\276\320\267\320\264\320\260\320\265\320\274_\320\267\320\276\320\275\321\203_\320\272\320\270\321\200\320\277\320\270\321\207\320\265\320\271/index.html" +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: Создаем зону кирпичей -slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Создаем_зону_кирпичей -translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Build_the_brick_field ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/en-US/docs/Games")}}
- -

{{PreviousNext("Games/Tutorials/2D_Breakout_game_pure_JavaScript/Game_over", "Games/Tutorials/2D_Breakout_game_pure_JavaScript/Collision_detection")}}

- -
-

Это 6 шаг из 10 в Gamedev Canvas tutorial. Вы можете найти исходный код, как он будет выглядеть после завершения этого урока, тут - Gamedev-Canvas-workshop/lesson6.html.

-
- -

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

- -

Настройка переменных кирпича

- -

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

- -
var brickRowCount = 3;
-var brickColumnCount = 5;
-var brickWidth = 75;
-var brickHeight = 20;
-var brickPadding = 10;
-var brickOffsetTop = 30;
-var brickOffsetLeft = 30;
- - - -

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

- -

Мы будем держать все наши кирпичи в двумерном массиве. Он будет содержать кирпичные столбцы (c), которые, в свою очередь, будут содержать кирпичные ряды (r), которые, в свою очередь, будут содержать объект, содержащий положение x и yчтобы рисовать каждый кирпич на экране. Добавьте следующие значения ниже ваших переменных:

- - - -
var bricks = [];
-for(var c=0; c<brickColumnCount; c++) {
-    bricks[c] = [];
-    for(var r=0; r<brickRowCount; r++) {
-        bricks[c][r] = { x: 0, y: 0 };
-    }
-}
- -

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

- -

Механизм отрисовки кирпичей

- -

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

- -
function drawBricks() {
-    for(var c=0; c<brickColumnCount; c++) {
-        for(var r=0; r<brickRowCount; r++) {
-            bricks[c][r].x = 0;
-            bricks[c][r].y = 0;
-            ctx.beginPath();
-            ctx.rect(0, 0, brickWidth, brickHeight);
-            ctx.fillStyle = "#0095DD";
-            ctx.fill();
-            ctx.closePath();
-        }
-    }
-}
- -

Опять же, мы зацикливаем строки и столбцы, чтобы установить положение x и yкаждого кирпича, и мы также brickWidth кирпич на кирпичной brickWidth Canvas -brickWidth - с каждой итерацией цикла. Проблема в том, что мы рисуем их все в одном месте, в координатах (0,0) . Нам нужно включить некоторые вычисления, которые будут определять положение x и y каждого кирпича для каждой итерации цикла:

- -
var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
-var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
- - - -

Каждая позиция brickX разрабатывается как brickWidth + brickPadding , умноженная на номер столбца, c , плюс brickOffsetLeft ; логика для brickY идентична, за исключением того, что она использует значения для номера строки, rbrickHeight и brickOffsetTop . Теперь каждый отдельный кирпич может быть помещен в правильное место и столбец места, с отступом между каждым кирпичом, нарисованным на смещение от левого и верхнего краев холста.

- -

Окончательная версия функции drawBricks() после назначения brickX и brickY в качестве координат вместо (0,0) каждый раз будет выглядеть следующим образом: добавьте это в свой код ниже функции drawPaddle() :

- - - -
    for(var c=0; c<brickColumnCount; c++) {
-        for(var r=0; r<brickRowCount; r++) {
-            var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
-            var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
-            bricks[c][r].x = brickX;
-            bricks[c][r].y = brickY;
-            ctx.beginPath();
-            ctx.rect(brickX, brickY, brickWidth, brickHeight);
-            ctx.fillStyle = "#0095DD";
-            ctx.fill();
-            ctx.closePath();
-        }
-    }
-}
- -

Сама отрисовка кирпичей

- -

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

- -
drawBricks();
-
- -

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

- - - -

На этом этапе игра снова стала интереснее:

- - - -

{{JSFiddleEmbed("https://jsfiddle.net/yumetodo/t1zqmzLp/","","395")}}

- -
-

Упражнение: попробуйте изменить количество кирпичей в строке или столбце или их позиции.

-
- -

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

- -

Итак, теперь у нас есть кирпичи! Но мяч вообще не взаимодействует с ними - мы изменим это, поскольку мы переходим в седьмую главу: Collision detection.

- -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection")}}

diff --git "a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_canvas_\320\270_\321\200\320\270\321\201\320\276\320\262\320\260\320\275\320\270\320\265_\320\275\320\260_\320\275\321\221\320\274/index.html" "b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_canvas_\320\270_\321\200\320\270\321\201\320\276\320\262\320\260\320\275\320\270\320\265_\320\275\320\260_\320\275\321\221\320\274/index.html" deleted file mode 100644 index 84f23b0e2a..0000000000 --- "a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_canvas_\320\270_\321\200\320\270\321\201\320\276\320\262\320\260\320\275\320\270\320\265_\320\275\320\260_\320\275\321\221\320\274/index.html" +++ /dev/null @@ -1,115 +0,0 @@ ---- -title: Создание Canvas и рисование на нём -slug: >- - Games/Tutorials/2D_Breakout_game_pure_JavaScript/Создание_Canvas_и_рисование_на_нём -tags: - - JavaScript - - Игры - - разработка игр - - создание игр -translation_of: >- - Games/Tutorials/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs/Games")}}
- -

{{PreviousNext("Games/Tutorials/2D_Breakout_game_pure_JavaScript", "Games/Tutorials/2D_Breakout_game_pure_JavaScript/Переместить_мяч")}}

- -
-

Это 1й шаг из 10 Gamedev Canvas tutorial. Вы можете найти исходный код для этого урока по ссылке Gamedev-Canvas-workshop/lesson1.html.

-
- -

Прежде чем мы сможем начать писать функциональные возможности игры, нам необходимо создать базовую структуру для рендеринга игры внутри. Это можно сделать с помощью HTML и элемента {{htmlelement ("canvas")}}.

- -

HTML игры

- -

Структура HTML документа довольно проста, так как игра будет полностью визуализироваться в {{htmlelement("canvas")}} элементе. Используя Ваш любимый текстовый редактор, создайте новый HTML документ, сохраните его как index.html в любом удобном месте, и скопируйте в него этот код:

- -
<!DOCTYPE html>
-<html>
-<head>
-    <meta charset="utf-8" />
-    <title>Gamedev Canvas Workshop</title>
-    <style>
-    	* { padding: 0; margin: 0; }
-    	canvas { background: #eee; display: block; margin: 0 auto; }
-    </style>
-</head>
-<body>
-
-<canvas id="myCanvas" width="480" height="320"></canvas>
-
-<script>
-	// JavaScript код будем писать здесь
-</script>
-
-</body>
-</html>
-
- -

Мы определили charset, {{htmlelement("title")}} и некий базовый CSS в заголовке. Тело документа содержит элементы {{htmlelement("canvas")}} и {{htmlelement("script")}} — мы будем визуализировать игру внутри первого и писать JavaScript код, который управляет игрой, во втором. Элемент {{htmlelement("canvas")}} имеет id равный myCanvas, который позволяет однозначно отыскать элемент. Так же этот элемент имеет ширину 480 пикселей и высоту 320 пикселей. Весь JavaScript код мы будем писать между открывающим тегом <script> и закрывающим тегом </script>.

- -

Основы Canvas

- -

Чтобы иметь возможность визуализировать игру в {{htmlelement("canvas")}} элементе, сначала мы должны сослаться на этот элемент в коде JavaScript. Добавьте следующий код после открывающего тега <script>.

- -
var canvas = document.getElementById("myCanvas");
-var ctx = canvas.getContext("2d");
- -

Таким образом, мы храним ссылку на {{htmlelement("canvas")}} элемент в переменной canvas. Далее мы создаём переменную ctx для хранения 2D визуализации контекста — метод, который используется для отрисовки в Canvas.

- -

Давайте рассмотрим пример отрисовки красного квадрата на canvas. Добавьте этот код ниже предыдущего кода на JavaScript и загрузите index.html в браузере, чтобы посмотреть результат.

- -
ctx.beginPath();
-ctx.rect(20, 40, 50, 50);
-ctx.fillStyle = "#FF0000";
-ctx.fill();
-ctx.closePath();
- -

Все инструкции располагаются между методами {{domxref("CanvasRenderingContext2D.beginPath()","beginPath()")}} и {{domxref("CanvasRenderingContext2D.closePath()","closePath()")}}. Мы определяем прямоугольник, используя  {{domxref("CanvasRenderingContext2D.rect()","rect()")}}: первые два параметра определяют координаты верхнего левого угла прямоугольника на canvas, в то время, как два других параметра определяют ширину и высоту прямоугольника. В нашем случае прямоугольник нарисован на расстоянии 20 пикселей слева и 40 пикселей сверху, 50 пикселей в ширину и 50 пикселей в высоту, что делает его квадратом. Свойство {{domxref("CanvasRenderingContext2D.fillStyle","fillStyle")}} хранит цвет, который будет использован методом {{domxref("CanvasRenderingContext2D.fill()","fill()")}} для отрисовки нашего квадрата.

- -

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

- -
ctx.beginPath();
-ctx.arc(240, 160, 20, 0, Math.PI*2, false);
-ctx.fillStyle = "green";
-ctx.fill();
-ctx.closePath();
- -

Как видите, мы снова используем методы {{domxref("CanvasRenderingContext2D.beginPath()","beginPath()")}} и {{domxref("CanvasRenderingContext2D.closePath()","closePath()")}}. Между ними наиболее важная часть кода - метод {{domxref("CanvasRenderingContext2D.arc()","arc()")}}. Он принимает шесть параметров:

- - - -

Свойство {{domxref("CanvasRenderingContext2D.fillStyle","fillStyle")}} выглядит не так, как прежде. Это потому что, как и в CSS, цвет может быть задан в шестнадцатиричном формате, названием цвета, функцией rgba() , или же любым другим методом для цвета.

- -

Вместо {{domxref("CanvasRenderingContext2D.fill()","fill()")}} и заполнения фигур цветом, можно использовать {{domxref("CanvasRenderingContext2D.stroke()","stroke()")}}, чтобы окрасить только внешнюю обводку фигуры. Попробуйте добавить этот код к Вашему коду JavaScript:

- -
ctx.beginPath();
-ctx.rect(160, 10, 100, 40);
-ctx.strokeStyle = "rgba(0, 0, 255, 0.5)";
-ctx.stroke();
-ctx.closePath();
- -

Код выше отрисовывает пустой прямоугольник с синей обводкой. Благодаря функции альфа-канала rgba() , голубой цвет полупрозрачный.

- -

Сравните Ваш код

- -

Здесь полный исходный код для первого урока, посмотреть онлайн можно на JSFiddle:

- -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/x62h15e2/","","395")}}

- -
-

Упражнение: попробуйте изменить цвет и размер созданных фигур.

-
- -

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

- -

Сейчас мы создали базовый HTML и немного узнали о canvas, давайте на следующем шаге изучим, как Двигать мяч в нашей игре.

- -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball")}}

diff --git "a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\321\203\320\277\321\200\320\260\320\262\320\273\320\265\320\275\320\270\320\265_\320\274\321\213\321\210\321\214\321\216/index.html" "b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\321\203\320\277\321\200\320\260\320\262\320\273\320\265\320\275\320\270\320\265_\320\274\321\213\321\210\321\214\321\216/index.html" deleted file mode 100644 index b3ab4efaca..0000000000 --- "a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/\321\203\320\277\321\200\320\260\320\262\320\273\320\265\320\275\320\270\320\265_\320\274\321\213\321\210\321\214\321\216/index.html" +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Управление мышью -slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Управление_мышью -tags: - - Игры - - Начинающий - - канвас - - мышь -translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Mouse_controls ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/en-US/docs/Games")}}
- -

{{PreviousNext("Games/Tutorials/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win", "Games/Tutorials/2D_Breakout_game_pure_JavaScript/Заключение")}}

- -
-

Это 9-й шаг из 10 в Gamedev Canvas tutorial. Вы можете найти исходный код к этому уроку в Gamedev-Canvas-workshop/lesson9.html.

-
- -

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

- -

Отслеживание движений мыши

- -

Отслеживание движений мыши еще проще, чем прослушивание нажатий клавиш. Все, что нам нужно, это следить за событиями {{event("mousemove")}}. Добавьте следующую строку в том же месте, как и для других событий, чуть ниже keyup event:

- -
document.addEventListener("mousemove", mouseMoveHandler, false);
- -

Привязка движения ракетки к движению мыши

- -

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

- -
function mouseMoveHandler(e) {
-    var relativeX = e.clientX - canvas.offsetLeft;
-    if(relativeX > 0 && relativeX < canvas.width) {
-        paddleX = relativeX - paddleWidth/2;
-    }
-}
- -

В этой функции мы сначала разрабатываем значение relativeX, которое равно горизонтальному положению мыши в окне браузера (e.clientX) минус расстояние между левым краем canvas и левым краем окна браузера (canvas.offsetLeft) - фактически это равно расстоянию между левым краем canvas и указателем мыши. Если относительный указатель позиции X больше нуля и меньше, чем ширина Canvas, указатель находится в пределах границы Canvas, и paddleX установки (крепится на левый край ракетки) - устанавливается на relativeX значение минус половина ширины ракетки, так что движение будет по отношению к середине ракетки.

- -

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

- -

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

- -

Это последнее состояние кода для сравнения:

- -

{{JSFiddleEmbed("https://jsfiddle.net/yumetodo/1L9ep9r2/1/","","395")}}

- -
-

Упражнение: отрегулируйте границы движения ракетки так, что вся ракетка будет видна на обоих краях Canvas, а не только на его половину.

-
- -

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

- -

Теперь у нас есть полная игра, мы закончим нашу серию уроков с еще несколькими небольшими хитростями — Finishing up.

- -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Finishing_up")}}

diff --git "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/bounce_off_the_walls/index.html" "b/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/bounce_off_the_walls/index.html" deleted file mode 100644 index aedabaaf25..0000000000 --- "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/bounce_off_the_walls/index.html" +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Отскакивания -slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Bounce_off_the_walls -translation_of: Games/Tutorials/2D_breakout_game_Phaser/Bounce_off_the_walls ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs/")}}
- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Physics", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Платформа_и_управление")}}

- -
-

Это 6 урок из 16 Руководства разработки игры с помощью Phaser. Вы можете найти исходный код того как должен выглядеть код после завершения урока здесь: Gamedev-Phaser-Content-Kit/demos/lesson06.html.

-
- -

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

- -

Отскакивание от границ представления

- -

Самый простой способ заставить мячик от стен это сообщить фреймворку что мы хотим рассматривать границы элемента {{htmlelement("canvas")}} как стены и не позволять мячу проходить через них. В Phaser это может быть просто реализовано с помощью свойства collideWorldsBound. Добавьте этот код сразу после существующего вызова метода game.physics.enable():

- -
ball.body.collideWorldBounds = true;
-
- -

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

- -
ball.body.bounce.set(1);
-
- -

Попробуйте перезагрузить index.html опять — теперь мяч отскакивает от стен и движется внутри холста canvas.

- -

Сравните ваш код

- -

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

- -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/dcw36opz/","","400")}}

- -

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

- -

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

- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Physics", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Платформа_и_управление")}}

diff --git "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/game_over/index.html" "b/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/game_over/index.html" deleted file mode 100644 index a617f8969d..0000000000 --- "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/game_over/index.html" +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Game over -slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Game_over -translation_of: Games/Tutorials/2D_breakout_game_Phaser/Game_over ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs/Games")}}
- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Платформа_и_управление", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Создание_кирпичей")}}

- -
-

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

-
- -

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

- -

Проигрыш

- -

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

- -
game.physics.arcade.checkCollision.down = false;
-
- -

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

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

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

- -

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

- -

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

- -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/436bckb7/","","400")}}

- -

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

- -

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

- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Платформа_и_управление", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Создание_кирпичей")}}

diff --git "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/index.html" "b/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/index.html" deleted file mode 100644 index 05a0439cc7..0000000000 --- "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/index.html" +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: 2D игра на Phaser -slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser -tags: - - 2D - - Canvas - - JavaScript - - Phaser - - Игры - - Начинающий - - Руководство - - туториал -translation_of: Games/Tutorials/2D_breakout_game_Phaser ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs/")}}
- -

{{Next("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Initialize_the_framework")}}

- -

В этом пошаговом руководстве мы создадим простую мобильную игру 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.

- -

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

- -

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

- -
    -
  1. Инициализация фреймворка
  2. -
  3. Масштабирование
  4. -
  5. Загрузка ресурсов и их вывод
  6. -
  7. Движение мяча
  8. -
  9. Физика
  10. -
  11. Отскакивание от стен
  12. -
  13. Управление
  14. -
  15. Конец игры
  16. -
  17. Создание поля блоков
  18. -
  19. Определение столкновения
  20. -
  21. Счёт
  22. -
  23. Победа в игре
  24. -
  25. Добавление жизней
  26. -
  27. Анимация
  28. -
  29. Кнопки
  30. -
  31. Создание случайных событий
  32. -
- -

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

- -

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

- -
-

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

-
- -

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

- -

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

- -

{{Next("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Initialize_the_framework")}}

diff --git "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/initialize_the_framework/index.html" "b/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/initialize_the_framework/index.html" deleted file mode 100644 index bf1fac5bfc..0000000000 --- "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/initialize_the_framework/index.html" +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Инициализация фреймворка -slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Initialize_the_framework -tags: - - 2D - - Canvas - - HTML - - JavaScript - - Phaser - - Игры - - Руководство -translation_of: Games/Tutorials/2D_breakout_game_Phaser/Initialize_the_framework ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("ru/docs/")}}
- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Scaling")}}

- -
-

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

-
- -

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

- -

HTML-код игры

- -

Структура HTML-документа достаточно простая. Игра будет отображаться в элементе {{htmlelement("canvas")}}, который будет сгенерирован фреймворком. Используя свой любимый редактор, создайте новый HTML-документ, сохраните его как index.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. -
  3. Выберите наиболее удобный для вас вариант загрузки. Я рекоммендую min.js скачивание, потому что исходный код будет меньше, да и вам не придётся разбираться в нём.
  4. -
  5. Сохраните Phaser внутри /js директории, находящейся в том же месте, что и index.html
  6. -
  7. Обновите аттрибут src в первом элементе {{htmlelement("script")}}, как это показано выше.
  8. -
- -

Что мы имеем

- -

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

- -

Фреймворк автоматически создаёт элемент {{htmlelement("canvas")}}. Мы инициализировали его, создав новый Phaser.Game объект и присвоив его переменной. Также мы добавили параметры:

- - - -
-

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

-
- -

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

- -

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

- -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/h6cwzv2b/","","400")}}

- -

Следующее

- -

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

- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Scaling")}}

diff --git "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/load_the_assets_and_print_them_on_screen/index.html" "b/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/load_the_assets_and_print_them_on_screen/index.html" deleted file mode 100644 index 57274a84c0..0000000000 --- "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/load_the_assets_and_print_them_on_screen/index.html" +++ /dev/null @@ -1,73 +0,0 @@ ---- -title: Загрузка ресурсов и их вывод -slug: >- - Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Load_the_assets_and_print_them_on_screen -tags: - - 2D - - Canvas - - JavaScript - - Phaser -translation_of: >- - Games/Tutorials/2D_breakout_game_Phaser/Load_the_assets_and_print_them_on_screen ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs/Games")}}
- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Scaling", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Move_the_ball")}}

- -
-

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

-
- -

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

- -

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

- -

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

- -
var ball;
-
- -
-

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

-
- -

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

- -

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

- -
function preload() {
-    // ...
-    game.load.image('ball', 'img/ball.png');
-}
-
- -

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

- -

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

- -

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

- -
function create() {
-    ball = game.add.sprite(50, 50, 'ball');
-}
-
- -

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

- -
-

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

-
- -

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

- -

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

- -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/98xrv9x5/","","400")}}

- -

Следующее

- -

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

- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Scaling", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Move_the_ball")}}

diff --git "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/move_the_ball/index.html" "b/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/move_the_ball/index.html" deleted file mode 100644 index deed4a9494..0000000000 --- "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/move_the_ball/index.html" +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: Движение мяча -slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Move_the_ball -tags: - - 2D - - Beginner - - Canvas - - JavaScript - - Phaser -translation_of: Games/Tutorials/2D_breakout_game_Phaser/Move_the_ball ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs/")}}
- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Load_the_assets_and_print_them_on_screen", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Physics")}}

- -
-

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

-
- -

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

- -

Обновление позиции мяча на каждом кадре

- -

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

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

Код выше добавляет 1 к свойствам x и y, которые отвечают за координаты мяча в canvas на каждом кадре. Перезагрузив index.html, вы должны увидеть, как наш мячик движется. 

- -

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

- -

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

- -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/g1cfp0vv/","","400")}}

- -

Следующее

- -

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

- -

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

- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Load_the_assets_and_print_them_on_screen", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Physics")}}

diff --git "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/physics/index.html" "b/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/physics/index.html" deleted file mode 100644 index 20acffa239..0000000000 --- "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/physics/index.html" +++ /dev/null @@ -1,98 +0,0 @@ ---- -title: Физика -slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Physics -tags: - - 2D - - Beginner - - Canvas - - JavaScript - - Phaser -translation_of: Games/Tutorials/2D_breakout_game_Phaser/Physics ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs")}}
- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Move_the_ball", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Bounce_off_the_walls")}}

- -
-

Это 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():

- -
game.physics.startSystem(Phaser.Physics.ARCADE);
-
- -

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

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

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

- -
ball.body.velocity.set(150, 150);
-
- -

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

- -

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

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

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

- -

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

- -

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

- -
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.

- -

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

- -

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

- -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/bjto9nj8/","","400")}}

- -

Следующее

- -

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

- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Move_the_ball", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Bounce_off_the_walls")}}

diff --git "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/scaling/index.html" "b/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/scaling/index.html" deleted file mode 100644 index 395e9f52de..0000000000 --- "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/scaling/index.html" +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: Масштабирование -slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Scaling -tags: - - 2D - - Canvas - - JavaScript - - Phaser - - Начинающий -translation_of: Games/Tutorials/2D_breakout_game_Phaser/Scaling ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs/Games")}}
- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Initialize_the_framework", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Load_the_assets_and_print_them_on_screen")}}

- -
-

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

-
- -

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

- -

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

- -

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

- -
function preload() {
-    game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
-    game.scale.pageAlignHorizontally = true;
-    game.scale.pageAlignVertically = true;
-}
-
- -

scaleMode имеет несколько опций, которые определяют, как {{htmlelement("canvas")}} будет масштабироваться:

- - - -

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

- -

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

- -

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

- -
game.stage.backgroundColor = '#eee';
-
- -

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

- -

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

- -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/6a64vecL/","","400")}}

- -

Следующее

- -

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

- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Initialize_the_framework", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Load_the_assets_and_print_them_on_screen")}}

diff --git "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\266\320\270\320\267\320\275\320\270/index.html" "b/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\266\320\270\320\267\320\275\320\270/index.html" deleted file mode 100644 index b6bb403469..0000000000 --- "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\266\320\270\320\267\320\275\320\270/index.html" +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: Жизни -slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Жизни -translation_of: Games/Tutorials/2D_breakout_game_Phaser/Extra_lives ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs")}}
- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Победа", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Анимация")}}

- -
-

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

-
- -

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

- -

Новый переменные

- -

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

- -
var lives = 3;
-var livesText;
-var lifeLostText;
-
- -

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

- -

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

- -

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

- -
livesText = game.add.text(game.world.width-5, 5, 'Lives: '+lives, { font: '18px Arial', fill: '#0095DD' });
-livesText.anchor.set(1,0);
-lifeLostText = game.add.text(game.world.width*0.5, game.world.height*0.5, 'Life lost, click to continue', { font: '18px Arial', fill: '#0095DD' });
-lifeLostText.anchor.set(0.5);
-lifeLostText.visible = false;
-
- -

Объекты livesText иlifeLostText очень похожи на scoreText — они определяют положение на экране, текст надписи и стилизацию шрифта. Чтобы всё выглядило должным образом, надпись с жизнями мы закрепляем в правом верхнем углу, а надпись о потере жизни, мы выводим в центре экрана. И всё это при помощи функции anchor.set().

- -

Надпись lifeLostText появится только при потере жизни, поэтому её видимость мы выставляем в false.

- -

Чистим код, стилизирующий надписи

- -

Как вы могли заметить, мы используем одинаковые стили для всех надписей: scoreText, livesText и lifeLostText. Однако, налицо копирование кода и если мы, когда-либо, захотим изменить размер шрифта или цвет, то нам придётся делать это в нескольких местах. Чтобы избежать этого, мы вынесем стиль в отдельную переменную. Напишите следующую строку сразу после всех наших текущих опеределений переменных:

- -
var textStyle = { font: '18px Arial', fill: '#0095DD' };
-
- -

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

- -
scoreText = game.add.text(5, 5, 'Points: 0', textStyle);
-livesText = game.add.text(game.world.width-5, 5, 'Lives: '+lives, textStyle);
-livesText.anchor.set(1,0);
-lifeLostText = game.add.text(game.world.width*0.5, game.world.height*0.5, 'Life lost, click to continue', textStyle);
-lifeLostText.anchor.set(0.5);
-lifeLostText.visible = false;
-
- -

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

- -

Код обработки жизни

- -

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

- -
ball.events.onOutOfBounds.add(function(){
-    alert('Game over!');
-    location.reload();
-}, this);
-
- -

Мы объявим новую функцию ballLeaveScreen; Удалим предыдущий обработчик (зачёркнутый код сверху) и заменим его следующей линией:

- -
ball.events.onOutOfBounds.add(ballLeaveScreen, this);
-
- -

Мы будем уменьшать количество жизней каждый раз, когда шар выйдет за пределы окна Canvas. Добавьте функцию ballLeaveScreen() в конец кода:

- -
function ballLeaveScreen() {
-    lives--;
-    if(lives) {
-        livesText.setText('Lives: '+lives);
-        lifeLostText.visible = true;
-        ball.reset(game.world.width*0.5, game.world.height-25);
-        paddle.reset(game.world.width*0.5, game.world.height-5);
-        game.input.onDown.addOnce(function(){
-            lifeLostText.visible = false;
-            ball.body.velocity.set(150, -150);
-        }, this);
-    }
-    else {
-        alert('You lost, game over!');
-        location.reload();
-    }
-}
-
- -

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

- -

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

- -

События

- -

Скорее всего вы заметили вызов методов add() и addOnce() в двух блоках кода выше и хотите знать, чем они отличаются. Разница в том, что метод add()  и привязанная к нему функция выполняется каждый раз, когда выполняется событие, тогда как метод  addOnce() полезен, когда вы хотите, чтобы связанная с ним функция выполнилась единожды и не повторялась снова. В нашем случае при каждом событии outOfBounds будет выполняться ballLeaveScreen, но когда мяч покидает экран, сообщение с экрана удалится единожды.

- -

Проверь свой код

- -

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

- -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/yk1c5n0b/","","400")}}

- -

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

- -

Жизни делают игру более казуальной — даже если вы проиграете единожды, у вас будут еще 2 жизни и вы сможете продолжить игру. Теперь мы можем поработать над внешним видом игры, сделать ее более красивой, добавив анимацию и эффекты .

- -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Win_the_game", "Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens")}}

diff --git "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\276\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260_\320\272\320\276\320\273\320\273\320\270\320\267\320\270\320\271/index.html" "b/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\276\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260_\320\272\320\276\320\273\320\273\320\270\320\267\320\270\320\271/index.html" deleted file mode 100644 index e3fb27724b..0000000000 --- "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\276\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260_\320\272\320\276\320\273\320\273\320\270\320\267\320\270\320\271/index.html" +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: Обработка коллизий -slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Обработка_коллизий -translation_of: Games/Tutorials/2D_breakout_game_Phaser/Collision_detection ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs")}}
- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Создание_кирпичей", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Очки")}}

- -
-

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

-
- -

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

- -

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

- -

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

- -
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>:

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

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

- -

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

- -

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

- -

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

- -

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

- -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/wwneakwf/","","400")}}

- -

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

- -

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

- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Создание_кирпичей", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Очки")}}

diff --git "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\276\321\207\320\272\320\270/index.html" "b/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\276\321\207\320\272\320\270/index.html" deleted file mode 100644 index 9f4b18ace1..0000000000 --- "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\276\321\207\320\272\320\270/index.html" +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: Очки -slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Очки -translation_of: Games/Tutorials/2D_breakout_game_Phaser/The_score ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs/")}}
- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Обработка_коллизий", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Победа")}}

- -
-

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

-
- -

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

- -

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

- -

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

- -

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

- -
// ...
-var scoreText;
-var score = 0;
-
- -

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

- -

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

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

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

- - - -

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

- -

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

- -

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

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

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

- -

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

- -

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

- -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/n8o6rhrf/","","400")}}

- -

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

- -

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

- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Обработка_коллизий", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Победа")}}

diff --git "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\277\320\273\320\260\321\202\321\204\320\276\321\200\320\274\320\260_\320\270_\321\203\320\277\321\200\320\260\320\262\320\273\320\265\320\275\320\270\320\265/index.html" "b/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\277\320\273\320\260\321\202\321\204\320\276\321\200\320\274\320\260_\320\270_\321\203\320\277\321\200\320\260\320\262\320\273\320\265\320\275\320\270\320\265/index.html" deleted file mode 100644 index 46713cdddb..0000000000 --- "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\277\320\273\320\260\321\202\321\204\320\276\321\200\320\274\320\260_\320\270_\321\203\320\277\321\200\320\260\320\262\320\273\320\265\320\275\320\270\320\265/index.html" +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: Платформа и управление -slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Платформа_и_управление -translation_of: Games/Tutorials/2D_breakout_game_Phaser/Player_paddle_and_controls ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs/")}}
- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Bounce_off_the_walls", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Game_over")}}

- -
-

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

-
- -

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

- -

Рисуем платформу

- -

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

- -

Создаем платформу

- -

Сначала, добавим переменную paddle, сразу после переменной ball:

- -
var paddle;
-
- -

После этого, в функции preload, загрузим изображение paddle при помощи ещё одного вызова функции load.image():

- -
function preload() {
-    // ...
-    game.load.image('ball', 'img/ball.png');
-    game.load.image('paddle', 'img/paddle.png');
-}
-
- -

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

- -

Чуть не забыли, на этом этапе нам надо скачать изображение платформы с Github в папку /img.

- -

Рисуем платформу с физикой

- -

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

- -
paddle = game.add.sprite(game.world.width*0.5, game.world.height-5, 'paddle');
-
- -

Мы можем использовать world.width и world.height для позиционирования платформы в том месте, где мы хотим: game.world.width*0.5 расположит платформу прямо по середине экрана. В данном случае, нам повезло, что наш игровой мир совпадает с <canvas>, однако, в других играх мир может быть гараздо больше экрана. 

- -

Как вы могли заметить, перезагрузив, на данном этапе, страницу index.html, платформа находится не совсем по середине экрана. Почему? Всё дело в том, что, по умолчанию, точка, из которой начинается позиционирование объекта (якорь), находится в левом верхнем углу. Но мы можем это изменить и переместить якорь в середину платформы по ширине и в самый низ повысоте, чтобы проще было позиционировать платформу, относительно нижней грани экрана. Добавьте следующую строку кода:

- -
paddle.anchor.set(0.5,1);
-
- -

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

- -
game.physics.enable(paddle, Phaser.Physics.ARCADE);
-
- -

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

- -
function update() {
-    game.physics.arcade.collide(ball, paddle);
-}
-
- -

В качестве аргументов, мы передаём два объекта, между которыми проверяются коллизии — в нашем случае, мячик и платформа. Вроде, сработало, но не совсем так, как мы ожидали — когда мячик сталкивается с платформой, последняя падает за пределы экрана! А мы, всего лишь, хотим, чтобы мячик отскакивал от платформы, а платформа, при этом, оставалась на месте. Мы можем использовать свойство immovable, для того, чтобы платформа не двигалась, когда мячик бьётся об неё. Для этого добавьте следующую строку кода в конец функции create():

- -
paddle.body.immovable = true;
-
- -

Вот! Теперь всё работает, как надо.

- -

Управляем платформой

- -

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

- -
function update() {
-    game.physics.arcade.collide(ball, paddle);
-    paddle.x = game.input.x;
-}
-
- -

Теперь, каждый кадр координата x платформы будет соответствовать координате x курсора. Однако, при старте игры, положение нашей платформы не по центру экрана, из-за того, что положение курсора не определено. Чтобы это исправить, давайте добавим платформе координату x по умолчанию, на случаей, если положение курсора не определено. Обновите предыдущую строку кода:

- -
paddle.x = game.input.x || game.world.width*0.5;
-
- -

Если вы этого ещё не сделали, то обновите страницу index.html и попробуйте то, что у нас получилось!

- -

Расположение мячика

- -

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

- -
ball = game.add.sprite(game.world.width*0.5, game.world.height-25, 'ball');
-ball.anchor.set(0.5);
- -

Скорость оставим такую же, но изменим направление по оси y, изменив второй параметр со 150 на -150, и теперь мяч будет двигаться вверх. Найдите строку ball.body.velocity.set( ... ) и измените её, как показано ниже:

- -
ball.body.velocity.set(150, -150);
-
- -

Теперь мячик появляется по середине платформы и двигается вверх.

- -

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

- -

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

- -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/ogqza0ye/","","400")}}

- -

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

- -

Мы можем управлять платформой и сделали так, чтобы мячик отскакивал от неё. Но какой от этого толк, если мячик отскакивает и от нижней грани экрана? В следующей главе мы добавим логику проигрыша и экран "Game over".

- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Bounce_off_the_walls", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Game_over")}}

diff --git "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\277\320\276\320\261\320\265\320\264\320\260/index.html" "b/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\277\320\276\320\261\320\265\320\264\320\260/index.html" deleted file mode 100644 index 21ff763bbf..0000000000 --- "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\320\277\320\276\320\261\320\265\320\264\320\260/index.html" +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Победа -slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Победа -translation_of: Games/Tutorials/2D_breakout_game_Phaser/Win_the_game ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs/Games")}}
- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Очки", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Жизни")}}

- -
-

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

-
- -

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

- -

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

- -

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

- -
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 у каждого кирпича и, если все кирпичи разрушены, выведем всплывающее окно с текстом о победе. После закрытия этого окна, страница перезагрузится.

- -

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

- -

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

- - - -

{{JSFiddleEmbed("https://jsfiddle.net/u8waa4Lx/1/","","400")}}

- -

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

- -

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

- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Очки", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Жизни")}}

diff --git "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_\320\272\320\270\321\200\320\277\320\270\321\207\320\265\320\271/index.html" "b/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_\320\272\320\270\321\200\320\277\320\270\321\207\320\265\320\271/index.html" deleted file mode 100644 index ffdd6c1d6d..0000000000 --- "a/files/ru/games/tutorials/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_2d_breakout_\320\270\320\263\321\200\321\213_\320\275\320\260_phaser/\321\201\320\276\320\267\320\264\320\260\320\275\320\270\320\265_\320\272\320\270\321\200\320\277\320\270\321\207\320\265\320\271/index.html" +++ /dev/null @@ -1,156 +0,0 @@ ---- -title: Создание кирпичей -slug: Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Создание_кирпичей -translation_of: Games/Tutorials/2D_breakout_game_Phaser/Build_the_brick_field ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs/Games")}}
- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Game_over", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Обработка_коллизий")}}

- -
-

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

-
- -

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

- -

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

- -

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

- -
var bricks;
-var newBrick;
-var brickInfo;
-
- -

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

- -

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

- -

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

- -
function preload() {
-    // ...
-    game.load.image('brick', 'img/brick.png');
-}
-
- -

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

- -

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

- -

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

- -
function create(){
-    // ...
-    initBricks();
-}
-
- -

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

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

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

- -

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

- -
bricks = game.add.group();
-
- -

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

- -
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. Для этого добавим во вложенный цикл немного кода, как показано ниже:

- -
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 в каждой итерации. Обновите строки инициализации этих переменных, как показано ниже:

- -
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():

- -
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, то увидете кирпичи, нарисованные на расстоянии друг от друга.

- -

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

- -

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

- -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/cck2b9e8/","","400")}}

- -

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

- -

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

- -

{{PreviousNext("Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Game_over", "Games/Tutorials/Создание_2D_Breakout_игры_на_Phaser/Обработка_коллизий")}}

diff --git "a/files/ru/games/\320\260\320\275\320\260\321\202\320\276\320\274\320\270\321\217/index.html" "b/files/ru/games/\320\260\320\275\320\260\321\202\320\276\320\274\320\270\321\217/index.html" deleted file mode 100644 index 0396fc4159..0000000000 --- "a/files/ru/games/\320\260\320\275\320\260\321\202\320\276\320\274\320\270\321\217/index.html" +++ /dev/null @@ -1,337 +0,0 @@ ---- -title: Анатомия видеоигры -slug: Games/Анатомия -translation_of: Games/Anatomy ---- -
{{GamesSidebar}}
- -

{{IncludeSubnav("/en-US/docs/Games")}}

- -
-

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

-
- -

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

- -

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

- -

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

- -

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

- -

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

- -

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

- -

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

- -

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

- -

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

- -

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

- -
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() загрязняет {{ domxref("window") }} объект (в нем хранятся все глобальные переменные) и код не оставляет нам возможность остановить цикл, если только вся вкладка не будет закрыта или обновлена. Для решения первой проблемы, если нужно, чтобы основной цикл просто выполнялся и вам не нужен легкий (прямой) доступ к нему, вы можете поместить его внутрь самовызывающейся Function Expression (IIFE).

- -
/*
-* Начинаем с точки с запятой в случае, если какая-либо строка кода выше данного примера
-* полагается на автоматическую вставку точки с запятой (ASI). Браузер может случайно решить,
-* что весь этот код начинается с предыдущей строки. Первая точка с запятой отмечает начало
-* новой строки, если предыдущая не была пустой или завершенной.
-*/
-
-;(function () {
-  function main() {
-    window.requestAnimationFrame( main );
-
-    // Содержание вашего основного цикла
-  }
-
-  main(); // Вызов цикла
-})();
- -

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

- -
-

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

-
- -

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

- -
/*
-* Начинаем с точки с запятой в случае, если какая-либо строка кода выше данного примера
-* полагается на автоматическую вставку точки с запятой (ASI). Браузер может случайно решить,
-* что весь этот код начинается с предыдущей строки. Первая точка с запятой отмечает начало
-* новой строки, если предыдущая не была пустой или завершенной.
-*
-* Давайте также предположим, что MyGame уже определена.
-*/
-
-;(function () {
-  function main() {
-    MyGame.stopMain = window.requestAnimationFrame( main );
-
-    // Содержание вашего основного цикла
-  }
-
-  main(); // Вызов цикла
-})();
- -

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

- -
window.cancelAnimationFrame( MyGame.stopMain );
- -

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

- -

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

- -

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

- -

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

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

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

- -

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

- -
-

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

-
- - - -

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

- -
var tNow = window.performance.now();
-
- -

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

- -
/*
-* Начинаем с точки с запятой в случае, если какая-либо строка кода выше данного примера
-* полагается на автоматическую вставку точки с запятой (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.

- -
-

Note: 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.

- -
/*
-* 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:

- - - -

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:

- - - -

Each of these methods have similar tradeoffs:

- - - -

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).

- -
-

Note: This example, specifically, is in need of technical review.

-
- -
/*
-* 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:

- - - -

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.

diff --git "a/files/ru/games/\320\262\320\262\320\276\320\264/index.html" "b/files/ru/games/\320\262\320\262\320\276\320\264/index.html" deleted file mode 100644 index 65d1aed2c0..0000000000 --- "a/files/ru/games/\320\262\320\262\320\276\320\264/index.html" +++ /dev/null @@ -1,121 +0,0 @@ ---- -title: Ввод в разработку Web-игр -slug: Games/Ввод -tags: - - Firefox OS - - Игры - - уроки -translation_of: Games/Introduction ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/ru/docs/Games")}}
- -

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

- -

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

- -

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

- -

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

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

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

- -

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

- -

1. Охват паутины огромен, она повсюду. Игры, построенные на HTML5, работают на смартфонах, планшетах, ПК и смарт-телевизорах.

- -

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

- -

3. У вас есть контроль, где это имеет значение: Платежи. Вы не должны отдавать 30% своих доходов кому-то другому только потому, что ваша игра в их экосистеме. Вместо этого, взимать плату, что вы хотите, и использовать любую услугу обработки платежей вам нравится.

- -

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

- -

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

- -

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

- -

7. Ваши игроки могут играть в вашу игру в любом месте, в любое время. Поскольку Web распространен повсеместно, ваши клиенты могут проверить статус своей игры на своих телефонах, планшетах, домашних ноутбуках, рабочих столах или на чем-либо еще.

- -

Web-технологии для разработчиков игр

- -

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

- -
-
-
Full Screen API
-
Этот простой API позволяет вашей игре использовать весь экран, тем самым погружая игрока в действие.
-
Gamepad API
-
Если вы хотите, чтобы ваши пользователи могли использовать геймпады и прочие игровые контроллеры для работы с игрой, вам потребуется этот API
-
HTML и CSS
-
Эти технологии помогут вам создать и разместить UI вашей игры, а HTML-элемент {{HTMLElement("canvas")}} это один из способов создать 2D-графику
-
HTML audio
-
Элемент {{HTMLElement ("audio")}} позволяет легко воспроизводить простые звуковые эффекты и музыку. Если ваше потребности выше, ознакомьтесь с Web Audio API для полной мощности обработки звука!
-
IndexedDB
-
Мощный API для хранения пользовательских данных на собственном компьютере или устройстве. Отличный способ локально сохранить состояние игры и другую информацию, без необходимости подгружать ее каждый раз при необходимости. Также полезно дял того, чтобы сделать ваш проект играбельным, даже если пользователь не подключен к Интернету (например, когда он оказался в самолете на несколько часов).
-
JavaScript
-
JavaScript, язык программирования, используемый в Интернете, быстро развивается в современных браузерах и становится ещё быстрее. Используйте его возможности для написания кода своей игры или используйте такие технологии, как Emscripten или Asm.js, чтобы с легкотью переносить существующие игры.
-
Pointer Lock API
-
API Pointer Lock позволяет блокировать мышь или другое указывающее устройство в интерфейсе вашей игры. Вместо абсолютного позиционирования курсора вы получаете координаты дельты, которые дают вам более точные измерения того, что делает пользователь, и предотвращают случайную отправку ввода где-то еще, тем самым упуская важные пользовательские действия.
-
-
SVG (масштабируемая векторная графика)
-
Позволяет создавать векторную графику, которая плавно масштабируется независимо от размера или разрешения дисплея пользователя.
-
Typed Arrays
-
Типизированные массивы JavaScript дают вам доступ к необработанным двоичным данным из кода, что позволяет вам манипулировать текстурами GL, игровыми данными или чем-то еще, даже если код не в формате JavaScript.
-
Web Audio API
-
Этот API необходим для управления воспроизведением, синтезом звука и манипулированием аудио из кода JavaScript. Позволяет создавать потрясающие звуковые эффекты, а также воспроизводить и манипулировать музыкой в ​​режиме реального времени.
-
WebGL
-
Позволяет создавать высокопроизводительную аппаратно-ускоренную 3D (и 2D) графику из веб-контента. Это веб-реализация OpenGL ES 2.0.
-
WebRTC
-
API WebRTC (Real-Time Communications) дает вам возможность управлять аудио- и видеоданными, включая телеконференции и передачу данных из других приложений между двумя пользователями. Хотите, чтобы ваши игроки могли общаться друг с другом, взрывая монстров? Это API для вас!
-
WebSockets
-
-

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

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

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

-
-
-
diff --git "a/files/ru/games/\320\270\320\275\321\201\321\202\321\200\321\203\320\274\320\265\320\275\321\202\321\213/asm.js/index.html" "b/files/ru/games/\320\270\320\275\321\201\321\202\321\200\321\203\320\274\320\265\320\275\321\202\321\213/asm.js/index.html" deleted file mode 100644 index 3f9b2afde0..0000000000 --- "a/files/ru/games/\320\270\320\275\321\201\321\202\321\200\321\203\320\274\320\265\320\275\321\202\321\213/asm.js/index.html" +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: asm.js -slug: Games/Инструменты/asm.js -tags: - - JavaScript - - WebAssembly - - asm.js -translation_of: Games/Tools/asm.js ---- -
{{GamesSidebar}}
- -
{{IncludeSubnav("/en-US/docs/Games")}}
- -
-

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 также зависит от браузера и от оборудования.

diff --git "a/files/ru/games/\320\270\320\275\321\201\321\202\321\200\321\203\320\274\320\265\320\275\321\202\321\213/index.html" "b/files/ru/games/\320\270\320\275\321\201\321\202\321\200\321\203\320\274\320\265\320\275\321\202\321\213/index.html" deleted file mode 100644 index 8981085874..0000000000 --- "a/files/ru/games/\320\270\320\275\321\201\321\202\321\200\321\203\320\274\320\265\320\275\321\202\321\213/index.html" +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Инструменты для разработки игр -slug: Games/Инструменты -translation_of: Games/Tools ---- -
{{GamesSidebar}}
{{IncludeSubnav("/en-US/docs/Games")}}
- -
-

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

-
- -
-
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 года)
  • -
-
-
-- cgit v1.2.3-54-g00ecf