Игра на память в Vanilla JavaScript

1656551050 igra na pamyat v vanilla javascript

Марина Феррейра

1*ikkvZ9ToN2kCtpUSP6702w

Изучите JS, CSS и HTML, создав игру на память за 30 минут!

В этом руководстве описаны некоторые основные понятия HTML5, CSS3 и JavaScript. Мы обсудим атрибуты данных, позиционирование, перспективу, переходы, flexbox, обработку событий, тайм-ауты и тернарные файлы. От вас не ожидается, что у вас будет много предыдущих знаний в программировании. Если вы знаете, для чего нужны HTML, CSS и JS, этого предостаточно!

Структура файла

Начнем создавать файлы в терминале:

? mkdir memory-game ? cd memory-game ? touch index.html styles.css scripts.js ? mkdir img  

HTML

The initial template linking both css и js файлы.

The game has 12 cards. Each card consists of a container div назван .memory-cardкоторый содержит два img элементов. Первый символизирует карту front-face а второй его back-face.

0*LXwjdEFd1dhLuME-

You can download the assets for this project at: Memory Game Repo.

The set of cards will be wrapped in a section контейнерный элемент. Конечный результат:

CSS

We will use a simple but yet very useful reset, applied to all items:

The box-sizing: border-box свойство включает значение заполнения и пределы в общую ширину и высоту элемента, поэтому мы можем пропустить математику.

By setting display: flex to the body и margin: auto к .memory-game контейнера, он будет отцентрирован как по вертикали, так и по горизонтали.

.memory-game также будет a flex-container. По умолчанию элементы настроены для уменьшения ширины, чтобы вместить контейнер. Установив flex-wrap на wrap, flex-items обмотать по нескольким линиям, согласно их размеру.

Each card width и height вычисляется с помощью функции CSS calc(). Сделаем три ряда, по четыре карты по постановке width к 25% и height к 33.333% минус 10px от margin.

To position .memory-card дети, добавим position: relative поэтому мы можем разместить детей абсолютно, по этому поводу.

The property position: absolute установлено на оба front-face и back-faceудалить элементы из исходного положения и положит их друг на друга.

The template should be looking like this:

0*XCqaVtrSiWnr7Ucp

Let’s also add a click effect. The :active псевдокласс будет запускаться каждый раз, когда элемент будет щелкнут. Он применит переход .2s к своему размеру:

0*NediqPWKuwU_g0i8

Flip Card

To flip the card when clicked, a class flip прилагается к элементу. Для этого выберем все memory-card элементы с document.querySelectorAll. Затем проведите их с помощью forEach и подключите прослушивающий события. Каждый раз, когда нажимают карту flipCard функция будет запущена. The this переменная представляет карточку, которая была нажата. Функция получает доступ к элементу classList и переключает flip класс:

In the CSS the flip класс возвращает карту на 180 градусов:

To produce the 3D flip effect, we will add the perspective property to .memory-game. Это свойство определяет, насколько далеко в z плоскости объекта от пользователя. Чем ниже значение, тем больше эффект перспективы. Для тонкого эффекта применяем 1000px:

To the .memory-card элементы добавим transform-style: preserve-3dчтобы расположить их в трехмерном пространстве, созданном в родительском пространстве, вместо того, чтобы выравнивать его до z = 0 плоскость (в стиле трансформации).

Now, a transition has to be applied to the transform свойство создавать эффект движения:

So, we got the card to 3D flip, yay! But why isn’t the card face showing up? Right now, both .front-face и .back-face сложены друг на друга, поскольку они абсолютно расположены. Каждый элемент имеет a back faceчто является его зеркальным отражением front face. Свойство backface-visibility по умолчанию имеет значение visibleпоэтому, когда мы переворачиваем карточку, мы получаем заднюю грань значка JS.

0*k2MPONGEHyHGYvyl

To reveal the image underneath it, let’s apply backface-visibility: hidden к .front-face и .back-face.

If we refresh the page and flip a card, it’s gone!

0*YCMzdW-z0yruzOPf

Since we’ve hidden both images back face, there is nothing in the other side. So now we have to turn the .front-face 180 градусов:

And now, there’s the desired flip effect!

0*QQAnvvQeYs7iFSAo

Match card

Now that we have flipping cards, let’s handle the matching logic.

When we click the first card, it needs to wait until another card is flipped. The variables hasFlippedCard и flippedCard будет управлять состоянием оборота. Если карта не перевернута, hasFlippedCard установлено на true и flippedCard установлен на карту, на которую была нажата. Давайте также переключим toggle метод к add:

So now, when the user clicks the second card, we will fall into the else block in our condition. We will check to see if it’s a match. In order to do that, let’s identify each card.

Whenever we feel like adding extra information to HTML elements, we can make use of data attributes. By using the following syntax: data-*где, * Может быть хоть каким словом, этот атрибут будет вставлен в свойство набора данных элемента. Итак, добавим а data-framework к каждой карточке:

So now we can check for a match by accessing both cards dataset. Let’s extract the matching logic to its own method checkForMatch() а также набор hasFlippedCard вернуться к фальшивому. В случае совпадения, disableCards() вызывается, а прослушиватели событий на обеих карточках отсоединяются, чтобы предотвратить дальнейшее пролистывание. иначе unflipCards() вернет обе карты обратно через тайм-аут 1500 мс, что удаляет .flip класс:

Putting all together:

A more elegant way of writing the matching condition is to use a ternary operator. It’s composed by three blocks. The first block is the condition to be evaluated. The second block is executed if the condition returns true, otherwise the executed block is the third:

Lock Board

So now that we have the matching logic covered, we need to lock the board. We lock the board to avoid two sets of cards being turned at the same time, otherwise the flipping will fail.

0*z1gY24eYgqu2cjvw

Let’s declare a lockBoard переменный. Когда игрок щелкнет вторую карту, lockBoard будет установлен на true и состояние if (lockBoard) return; будет предотвращать перелистывание карт до того, как карты будут скрыты или совпадают:

Same Card Click

The is still the case where the player can click twice on the same card. The matching condition would evaluate to true, removing the event listener from that card.

0*WuPO5Ra7nRNJkZIO

To prevent that, let’s check if the current clicked card is equal to the firstCard и вернуть, если положительный.

The firstCard и secondCard переменные нужно сбрасывать после каждого раунда, поэтому давайте вытащим это к новому методу resetBoard(). Разместим hasFlippedCard = false; и lockBoard = false там тоже. Назначение деструктуризации es6 [var1, var2] = ['value1', 'value2']позволяет нам сохранять очень короткий код:

The new method will be called both from disableCards() и unflipCards():

Shuffling

Our game looks pretty good, but there is no fun if the cards are not shuffled, so let’s take care of that now.

When display: flex декларируется на контейнере, flex-items расположены по такой иерархии: группа и источник заказ. Каждая группа определяется свойством order, содержащим положительное или отрицательное целое число. По умолчанию каждый flex-item имеет свой order свойство установлено на 0, что означает, что все они принадлежат одной группе и будут размещены в порядке источника. Если существует более одной группы, элементы вначале размещаются по возрастанию группового порядка.

There is 12 cards in the game, so we will iterate through them, generate a random number between 0 and 12 and assign it to the flex-item order собственность:

In order to invoke the shuffle давайте сделаем ее выражением вызываемой немедленно функции (IIFE), что означает, что она будет выполняться сразу после объявления. Скрипты должны выглядеть так:

And that’s all folks!

You can also find a video explanation at ? Code Sketch Channel.

References

Originally published at marina-ferreira.github.io.

Добавить комментарий

Ваш адрес email не будет опубликован.