From 074785cea106179cb3305637055ab0a009ca74f2 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:42:52 -0500 Subject: initial commit --- .../bounce_off_the_walls/index.html | 109 +++++++++++++++ .../game_over/index.html | 95 ++++++++++++++ .../2d_breakout_game_pure_javascript/index.html | 59 +++++++++ .../paddle_and_keyboard_controls/index.html | 124 +++++++++++++++++ .../track_the_score_and_win/index.html | 100 ++++++++++++++ .../index.html" | 103 +++++++++++++++ .../index.html" | 128 ++++++++++++++++++ .../index.html" | 146 +++++++++++++++++++++ .../index.html" | 119 +++++++++++++++++ .../index.html" | 115 ++++++++++++++++ .../index.html" | 58 ++++++++ 11 files changed, 1156 insertions(+) create mode 100644 files/ru/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_pure_javascript/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.html create mode 100644 files/ru/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.html create 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" create 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" create 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" create 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" create 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" create 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" (limited to 'files/ru/games/tutorials/2d_breakout_game_pure_javascript') diff --git a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.html b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.html new file mode 100644 index 0000000000..1e5796777e --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.html @@ -0,0 +1,109 @@ +--- +title: Отскок от стен +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls +tags: + - Анимация + - Графика + - Игры + - Начинающим + - Обучение + - Примеры + - столкновения +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

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

+ +
+

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

+
+ +

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

+ +

Простое обнаружение столкновений

+ +

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

+ +

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

+ +
var ballRadius = 10;
+ +

Теперь обновите строку, которая рисует шарик, внутри функции drawBall() :

+ +
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
+ +

Отскакивание от верхней и нижней стены

+ +

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

+ +
if(y + dy < 0) {
+    dy = -dy;
+}
+ +

Если значение y положения шара ниже нуля, изменить направление движения по оси y установив его с тем же значением но с другим знаком. Если мяч движется вверх со скоростью 2 пикселя на кадр, теперь он будет двигаться "вверх" со скоростью -2 пикселя, что на самом деле означает движение вниз со скоростью 2 пикселя.

+ +

Приведенный выше код описывает отражение только от верхней границы, так что теперь давайте думать о нижнем крае:

+ +
if(y + dy > canvas.height) {
+    dy = -dy;
+}
+ +

Если положение мяча по оси y больше, чем высота полотна (помните, что мы рассчитываем значения y от верхнего левого, чтобы верхний край начинался с 0, а нижний край — 480 пикселей, высота нашего <canvas>), затем после отскока от нижней кромки обратное движение по оси y.

+ +

Мы можем объединить эти две конструкции в одну, чтобы уменьшить код:

+ +
if(y + dy > canvas.height || y + dy < 0) {
+    dy = -dy;
+}
+ +

Если одно из двух утверждений верно, тогда направление мяча меняется.

+ +

Отскоки влево и вправо

+ +

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

+ +
if(x + dx > canvas.width || x + dx < 0) {
+    dx = -dx;
+}
+
+if(y + dy > canvas.height || y + dy < 0) {
+    dy = -dy;
+}
+ +

На этом этапе вы должны вставить этот блок кода в функцию Draw (), непосредственно перед закрывающей фигурной скобкой.

+ +

Мяч продолжает исчезать в стене!

+ +

Проверьте сейчас свой код, и вы будете впечатлены — теперь мяч, отскакивает от всех четерёх краёв нашего <canvas>!  Однако есть некоторая проблема - когда мяч попадает в любую стену, он немного заходит за границы <canvas> перед отскоком:

+ +

+ +

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

+ +
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
+    dx = -dx;
+}
+if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
+    dy = -dy;
+}
+ +

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

+ +

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

+ +

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

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/redj37dc/","","370")}}

+ +
+

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

+
+ +

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

+ +

Теперь мы добрались до стадии, где наш мяч одновременно двигается и остаётся на игровом поле. В четвертой главе мы рассмотрим реализацию управления — см. Paddle and keyboard controls.

+ +

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

diff --git a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.html b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.html new file mode 100644 index 0000000000..bb944fae5d --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.html @@ -0,0 +1,95 @@ +--- +title: Game over +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Game_over +tags: + - Canvas + - JavaScript + - game over + - Начинающий +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Game_over +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

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

+ +
+

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

+
+ +

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

+ +

Реализация окончания игры

+ +

Давайте попытаемся реализовать "Конец Игры" в нашей игре. Вот часть кода от третьего урока, где мы заставили шар отталкиваться от стен:

+ +
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
+    dx = -dx;
+}
+
+if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
+    dy = -dy;
+}
+ +

Вместо того, чтобы позволить шару отталкиваться от всех четырех стен, давайте позволим отталкиваться только от трех стен — левую, верхнюю и правую. Удар об нижнюю стенку закончит игру. Мы отредактируем второй блок if, таким образом, что if else вызовит "Конец Игры" , когда шар столкнется  с нижней стенкой холста. Сохраните документ, взгляните на выводящееся сообщение перезагрузите игру путем презагрузки страницы.

+ +

Во-первых, измените код, где вы изначально вызывали setInterval()

+ + + +
setInterval(draw, 10);
+
+ +

на следующий:

+ +
var interval = setInterval(draw, 10);
+
+ + + +

Затем замените второй оператор if следующим:

+ +
if(y + dy < ballRadius) {
+    dy = -dy;
+} else if(y + dy > canvas.height-ballRadius) {
+    alert("GAME OVER");
+    document.location.reload();
+    clearInterval(interval); // Needed for Chrome to end game
+}
+ + + +

Отбить шар

+ +

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

+ +
if(y + dy < ballRadius) {
+    dy = -dy;
+} else if(y + dy > canvas.height-ballRadius) {
+    if(x > paddleX && x < paddleX + paddleWidth) {
+        dy = -dy;
+    }
+    else {
+        alert("GAME OVER");
+        document.location.reload();
+    }
+}
+ +

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

+ +

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

+ +

Вот рабочий код для Вас, чтобы сравнить Ваш с:

+ +

{{JSFiddleEmbed("https://jsfiddle.net/raymondjplante/L61c9y50/","","395")}}

+ +
+

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

+
+ +

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

+ +

Все идет хорошо и наша игра начинает чувствовать себя намного более достойно. Вы уже можете проиграть! Но все еще не хватает чего-то. Перейдем к шестой главе — Build the brick field — и создадим некоторые кирпичи для шара, чтобы их уничтожить.

+ +

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

diff --git a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/index.html b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/index.html new file mode 100644 index 0000000000..2a30bbadb5 --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/index.html @@ -0,0 +1,59 @@ +--- +title: 2D игра на чистом JavaScript +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript +tags: + - 2D + - Canvas + - JavaScript + - TopicStub + - Игры + - Начинающий + - Руководство +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

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

+ +

В этом пошаговом руководстве мы создадим простую игру MDN Breakout, написанную на чистом JavaScript и отрендеренную на HTML5 {{htmlelement("canvas")}}.

+ +

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

+ +

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

+ +

Gameplay screen from the game MDN Breakout where you can use your paddle to bounce the ball and destroy the brick field, with keeping the score and lives.

+ +

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

+ +

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

+ +
    +
  1. Создание Canvas и рисование на нем
  2. +
  3. Движение мяча
  4. +
  5. Реакция при столкновении со стеной
  6. +
  7. Управление
  8. +
  9. Конец игры
  10. +
  11. Построение поля кирпичей
  12. +
  13. Реакция при столкновении
  14. +
  15. Счет и выигрыш
  16. +
  17. Контроль мышью
  18. +
  19. Заключение
  20. +
+ +

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

+ +
+

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

+
+ +
+

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

+
+ +

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

+ +

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

+ +

{{Next("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it")}} 

diff --git a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.html b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.html new file mode 100644 index 0000000000..ad4caeefa1 --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.html @@ -0,0 +1,124 @@ +--- +title: Ракетка и управление клавиатурой +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

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

+ +
+

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

+ +

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

+
+ +

Определение ракетки, чтобы ударить по мячу

+ +

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

+ +
var paddleHeight = 10;
+var paddleWidth = 75;
+var paddleX = (canvas.width-paddleWidth)/2;
+ +

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

+ +
function drawPaddle() {
+    ctx.beginPath();
+    ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
+    ctx.fillStyle = "#0095DD";
+    ctx.fill();
+    ctx.closePath();
+}
+ +

Позволяем пользователю управлять ракеткой

+ +

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

+ + + +

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

+ +
var rightPressed = false;
+var leftPressed = false;
+ +

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

+ +
document.addEventListener("keydown", keyDownHandler, false);
+document.addEventListener("keyup", keyUpHandler, false);
+ +

Когда keydown событие вызывается любой клавишей клавиатуры (нажатием клавиши), функция keyDownHandler() будет выполняться. Та же картина верна для второго обработчика: keyup событие запустит функцию keyUpHandler () (когда будет отпущена). Добавьте следующий блок в ваш код ниже addEventListener():

+ +
function keyDownHandler(e) {
+    if(e.keyCode == 39) {
+        rightPressed = true;
+    }
+    else if(e.keyCode == 37) {
+        leftPressed = true;
+    }
+}
+
+function keyUpHandler(e) {
+    if(e.keyCode == 39) {
+        rightPressed = false;
+    }
+    else if(e.keyCode == 37) {
+        leftPressed = false;
+    }
+}
+ +

Когда мы нажимаем клавишу, эта информация хранится в переменной. Соответствующая переменная в каждом конкретном случае устанавливается в true. Когда клавиша отпущена, переменная устанавливается обратно в false.

+ +

Обе функции принимают параметр, представленный переменной e. Из нее вы можете получить полезную информацию: key содержит информацию о нажатой клавише. Например, код 37 — это клавиша стрелка влево и 39 — стрелка вправо. Если стрелка влево нажата, то переменная leftPressed имеет значение true, когда кнопка отпущена, то переменная leftPressed имеет значение false. Та же схема со стрелкой вправо и переменной rightPressed.

+ +

Логика перемещения ракетки

+ +

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

+ +
if(rightPressed) {
+    paddleX += 7;
+}
+else if(leftPressed) {
+    paddleX -= 7;
+}
+ +

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

+ +
if(rightPressed && paddleX < canvas.width-paddleWidth) {
+    paddleX += 7;
+}
+else if(leftPressed && paddleX > 0) {
+    paddleX -= 7;
+}
+ +

Позиция paddleX будет двигаться от 0 на левой стороне холста и canvas.width-paddleWidth на правой стороне. Это будет работать именно так, как нам нужно.

+ +

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

+ +

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

+ +
drawPaddle();
+
+ +

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

+ +

Вот работающий код для вас, чтобы сравнить со своим:

+ +

{{JSFiddleEmbed("https://jsfiddle.net/end3r/tgn3zscj/","","320")}}

+ +
+

Упражнение: Сделайте скорость движения ракетки быстрее или медленнее, или измените ее размер.

+
+ +

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

+ +

Теперь у нас есть что-то похожее на игру. Беда только в том, что пока вы можете лишь бесконечно бить мяч ракеткой. Это все изменится в пятой главе, Game over, когда мы начнем добавлять конечное состояние для нашей игры.

+ +

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

diff --git a/files/ru/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.html b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.html new file mode 100644 index 0000000000..f9993a8b31 --- /dev/null +++ b/files/ru/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.html @@ -0,0 +1,100 @@ +--- +title: Счет и выигрыш +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win +tags: + - JavaScript + - Игры + - Начинающий + - Учебник + - счет +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win +--- +
{{GamesSidebar}}
+ +
{{IncludeSubnav("/en-US/docs/Games")}}
+ +

{{PreviousNext("Games/Tutorials/2D_Breakout_game_pure_JavaScript/Обнаружение_столкновений", "Games/Tutorials/2D_Breakout_game_pure_JavaScript/Управление_мышью")}}

+ +
+

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

+
+ +

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

+ +

Подсчет очков

+ +

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

+ +
var score = 0;
+ +

Вам также нужна функция drawScore() для создания и обновления отображения оценки. Добавьте после функции collisionDetection() следующий код:

+ +
function drawScore() {
+    ctx.font = "16px Arial";
+    ctx.fillStyle = "#0095DD";
+    ctx.fillText("Score: "+score, 8, 20);
+}
+ +

Рисование текста на канве аналогично рисованию фигур. Определение шрифта выглядит точно так же, как и в CSS - вы можете установить размер и тип шрифта в {{domxref("CanvasRenderingContext2D.font","font()")}} методе. Затем используйте {{domxref("CanvasRenderingContext2D.fillStyle()","fillStyle()")}} для установки цвета шрифта и  {{domxref("CanvasRenderingContext2D.fillText","fillText()")}} для установки фактического текста, который будет помещен на канву, и где он будет размещен. Первым параметром является сам текст - приведенный выше код показывает текущее количество точек, а два последних параметра - это координаты, в которых текст будет помещен на канву.

+ +

Чтобы начислять баллы каждый раз при ударе кирпича, добавьте строку в функцию 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;
+                    score++;
+                }
+            }
+        }
+    }
+}
+ +

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

+ +
drawScore();
+ +

Отображение сообщения о победе, когда все кирпичи были уничтожены

+ +

В конце концов, это главная цель игры, поэтому вы должны отобразить сообщение о победе, если все доступные кирпичи уничтожены. Добавьте следующий код в свою функцию 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;
+                    score++;
+                    if(score == brickRowCount*brickColumnCount) {
+                        alert("YOU WIN, CONGRATULATIONS!");
+                        document.location.reload();
+                    }
+                }
+            }
+        }
+    }
+}
+ +

Благодаря этому, игроки могут выиграть игру, когда они уничтожают все кирпичи, что очень важно, когда дело доходит до игр. Функция document.location.reload() перезагружает страницу и снова запускает игру после нажатия кнопки оповещения.

+ +

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

+ +

Вот работающий код для вас, чтобы сравнить со своим:

+ +

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

+ +
+

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

+
+ +

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

+ +

На данный момент игра выглядит довольно хорошо. В следующем уроке Вы расширите привлекательность игры, добавив Mouse controls.

+ +

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

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" new file mode 100644 index 0000000000..d8f40896e1 --- /dev/null +++ "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" @@ -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/\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" new file mode 100644 index 0000000000..576f17e7cc --- /dev/null +++ "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" @@ -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/\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" new file mode 100644 index 0000000000..f6d26cfc52 --- /dev/null +++ "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" @@ -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/\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" new file mode 100644 index 0000000000..91c7ea5405 --- /dev/null +++ "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" @@ -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/\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" new file mode 100644 index 0000000000..84f23b0e2a --- /dev/null +++ "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" @@ -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/\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" new file mode 100644 index 0000000000..b3ab4efaca --- /dev/null +++ "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" @@ -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")}}

-- cgit v1.2.3-54-g00ecf