Как создать карточную игру Match Up с помощью React
Введение
Реагировать — это библиотека JavaScript, используемая для создания пользовательских интерфейсов. Это интерфейсная библиотека, которую легко и быстро освоить.
В этом уроке мы будем создавать игру Card Match Up с использованием React.
карточная игра
Обзор игры
Игра состоит из 8 пар карт (т.е. 16 карт). Карты расположены случайным образом и рубашкой вниз. Пользователь переворачивает карту, нажав на нее. Если две перевернутые карты совпадают, они исчезнут с нашего игрового поля, в противном случае они будут перевернуты обратно. Игра заканчивается, когда все карты успешно сопоставлены со своими парами.
Предпосылка
- Узел JS (версия 6 и выше)
- NPM (v5.2 и выше)
Да начнется кодирование.
Для начала нам нужно сначала установить пакеты, необходимые для сборки приложения.
Сначала мы устанавливаем создать-реагировать-приложение Пакет НПМ. Этот пакет позволяет нам быстро настроить проект ReactJs с помощью всего одной команды.
В терминале или командной строке введите:
npm i create-react-app
Теперь, когда у нас установлен пакет create-react-app, мы можем настроить наш проект.
npx create-react-app card-match-up
Открой сопоставление карт папку проекта любым текстовым редактором. Я буду использовать VSCode Editor.
настройка проекта сопоставления карт
Запустите приложение с помощью:
npm start
Приложение должно автоматически открываться в вашем браузере на порту 3000. Интерфейс должен быть примерно таким:
Страница создания-реакции-приложения по умолчанию
Нам нужно установить еще один пакет NPM для игры.
npm install react-card-flip --save
ReactCardFlip позволяет нам использовать анимацию переворота карты. Я считаю, что его проще использовать, чем писать собственную анимацию CSS для компонентов карты.
Настройте структуру папок приложений
в src
папку, создайте две папки:
components
папка: в эту папку будут добавлены две папки. Они есть:
а.card
папка: содержит файлы Card и GameOver JSX.
б.header
папка: содержит JSX-файл заголовка.styles
папка: куда мы поместим наш пользовательский файл CSS.
Нам также необходимо удалить эти файлы в src
папка.
- App.css
- index.css
- logo.svg
С созданием папок и удалением некоторых файлов наша структура папок должна выглядеть так:
структура папок игры
Приложение в настоящее время не работает, потому что мы все еще ссылаемся на некоторые файлы, которые мы удалили. Чтобы решить эту проблему, откройте App.js
а также index.js
файлы и удалить строки, где мы импортируем logo.svg, App.css, and index.css
.
Настройте файлы приложения
- в
src > components > card
папка, создатьCard.jsx
а такжеGameOver.jsx
файлы.
Напишите следующий фрагмент кода в созданных вами файлах. Мы рассмотрим их в ближайшее время.
Карта.jsx
import React from 'react';
import ReactCardFlip from "react-card-flip";
const Card = ({ id, isFlipped, handleClick, cardNumber }) => (
<ReactCardFlip isFlipped={isFlipped} flipSpeedBackToFront={1} flipSpeedFrontToBack={1} >
<button id={id} className={`card card-front ${cardNumber !== -1 ? "" : "hide-card"}`} onClick={handleClick} key="front">
</button>
<button id={id} className={`card card-back ${cardNumber !== -1 ? "" : "hide-card"}`} onClick={handleClick} key="back">
{ cardNumber }
</button>
</ReactCardFlip>
);
export default Card;
GameOver.jsx
import React from 'react';
const GameOver = ({ restartGame }) => (
<div className="justify-center">
<h1>Game Over!</h1>
<h3>If you enjoyed playing this game, follow me @iamkenec for more...</h3>
<button className="restart-button" onClick={restartGame}>Restart Game</button>
</div>
);
export default GameOver;
- в
src > components > header
папка, создатьHeader.jsx
файл. Введите приведенный ниже фрагмент кода внутриHeader.jsx
файл.
import React from 'react';
const Header = ({ restartGame }) => (
<div className="grid-header-container">
<div className="justify-left timer"></div>
<div className="justify-center game-status-text"></div>
<div className="justify-end">
<button onClick={restartGame} className="restart-button">Restart Game</button>
</div>
</div>
);
export default Header;
- Заменить содержимое
App.js
вsrc
папку с фрагментом кода ниже.
App.js
import React, { PureComponent } from 'react';
import Header from './components/header/Header';
import Card from './components/card/Card';
import GameOver from './components/card/GameOver';
import './styles/main.css';
class App extends PureComponent {
state = {
isFlipped: Array(16).fill(false),
shuffledCard: App.duplicateCard().sort(() => Math.random() - 0.5),
clickCount: 1,
prevSelectedCard: -1,
prevCardId: -1
};
static duplicateCard = () => {
return [0,1,2,3,4,5,6,7].reduce((preValue, current, index, array) => {
return preValue.concat([current, current])
},[]);
};
handleClick = event => {
event.preventDefault();
const cardId = event.target.id;
const newFlipps = this.state.isFlipped.slice();
this.setState({
prevSelectedCard: this.state.shuffledCard[cardId],
prevCardId: cardId
});
if (newFlipps[cardId] === false) {
newFlipps[cardId] = !newFlipps[cardId];
this.setState(prevState => ({
isFlipped: newFlipps,
clickCount: this.state.clickCount + 1
}));
if (this.state.clickCount === 2) {
this.setState({ clickCount: 1 });
const prevCardId = this.state.prevCardId;
const newCard = this.state.shuffledCard[cardId];
const previousCard = this.state.prevSelectedCard;
this.isCardMatch(previousCard, newCard, prevCardId, cardId);
}
}
};
isCardMatch = (card1, card2, card1Id, card2Id) => {
if (card1 === card2) {
const hideCard = this.state.shuffledCard.slice();
hideCard[card1Id] = -1;
hideCard[card2Id] = -1;
setTimeout(() => {
this.setState(prevState => ({
shuffledCard: hideCard
}))
}, 1000);
} else {
const flipBack = this.state.isFlipped.slice();
flipBack[card1Id] = false;
flipBack[card2Id] = false;
setTimeout(() => {
this.setState(prevState => ({ isFlipped: flipBack }));
}, 1000);
}
};
restartGame = () => {
this.setState({
isFlipped: Array(16).fill(false),
shuffledCard: App.duplicateCard().sort(() => Math.random() - 0.5),
clickCount: 1,
prevSelectedCard: -1,
prevCardId: -1
});
};
isGameOver = () => {
return this.state.isFlipped.every((element, index, array) => element !== false);
};
render() {
return (
<div>
<Header restartGame={this.restartGame} />
{ this.isGameOver() ? <GameOver restartGame={this.restartGame} /> :
<div className="grid-container">
{
this.state.shuffledCard.map((cardNumber, index) =>
<Card
key={index}
id={index}
cardNumber={cardNumber}
isFlipped={this.state.isFlipped[index]}
handleClick={this.handleClick}
/>
)
}
</div>
}
</div>
);
}
}
export default App;
- Наконец, в
src > styles
папка, создатьmain.css
файл. Вставьте эти стили внутрь него.
main.css
body {
margin: 0;
}
.grid-container {
display: grid;
grid-gap: 1px;
grid-template-columns: auto auto auto auto;
padding: 10px 150px 10px 150px;
}
.grid-header-container {
display: grid;
grid-template-columns: auto auto auto;
background-color: #c9d1f5;
padding: 10px;
}
.grid-item {
border: 1px solid rgba(0, 0, 0, 0.8);
}
.justify-left {
text-align: left
}
.justify-end {
text-align: right;
}
.justify-center {
text-align: center;
}
.timer {
color: #5168e9;
font-size: 20px;
font-weight: bold;
}
.restart-button {
width: 15em;
height: 3em;
color: white;
background-color: #5168e9;
border: 0;
}
.game-status-text {
font-family: Verdana, Geneva, Tahoma, sans-serif;
color: rgb(24, 21, 16);
font-weight: bold;
}
.card {
width: 100%;
height: 10em;
background-color: rgb(75, 42, 165);
color: white;
font-size: 15px;
}
.hide-card {
visibility: hidden;
}
.card-front {
background-color: #999999;
box-shadow: 5px 5px 5px rgba(68, 68, 68, 0.6);
}
.card-back {
font-weight: bold;
}
.react-card-front {
position: unset !important;
}
Прежде чем мы перейдем к приведенным выше строкам кода, давайте убедимся, что наше приложение работает правильно. Запустите приложение с npm start
и попробуй доиграть до конца.
Давайте теперь подробно рассмотрим код.
Прохождение кода
App.js
Этот файл содержит логику приложения. Он также содержит три других компонента React, которые Header.jsx
, GameOver.jsx
а также Card.jsx
.
App.js содержит объект внутреннего состояния и пять различных методов.
Строка 18–22 содержит метод дублирования массива номеров карт. Это связано с тем, что у каждого номера карты должен быть дубликат. duplicateCard
метод вернет массив длиной 16, который [0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]. Этот массив рандомизируется, когда он передается объекту состояния. shuffledCard.
метод дубликата карты
static duplicateCard = () => {
return [0,1,2,3,4,5,6,7].reduce((preValue, current, index, array) => {
return preValue.concat([current, current])
},[]);
};
Строка 24 — 49 содержит метод переворачивания карты при нажатии на нее, чтобы показать номер карты. Метод изменяет isFlipped
меняет состояние карты на true и предотвращает реакцию карты, которая уже перевернута, на событие щелчка. Из строка 40 мы проверяем, равно ли количество перевернутых карт двум, чтобы мы могли проверить, совпадают ли эти две карты.
Метод handleClick
handleClick = event => {
event.preventDefault();
const cardId = event.target.id;
const newFlipps = this.state.isFlipped.slice();
this.setState({
prevSelectedCard: this.state.shuffledCard[cardId],
prevCardId: cardId
});
if (newFlipps[cardId] === false) {
newFlipps[cardId] = !newFlipps[cardId];
this.setState(prevState => ({
isFlipped: newFlipps,
clickCount: this.state.clickCount + 1
}));
if (this.state.clickCount === 2) {
this.setState({ clickCount: 1 });
const prevCardId = this.state.prevCardId;
const newCard = this.state.shuffledCard[cardId];
const previousCard = this.state.prevSelectedCard;
this.isCardMatch(previousCard, newCard, prevCardId, cardId);
}
}
};
Строка 51–69 это метод, который проверяет, совпадают ли две перевернутые карты. Этот метод вызывается в строке 46, как показано выше. setTimeout
метод, используемый при установке состояния, заключается в том, что переворот карты не будет резким.
метод isCardMatch
isCardMatch = (card1, card2, card1Id, card2Id) => {
if (card1 === card2) {
const hideCard = this.state.shuffledCard.slice();
hideCard[card1Id] = -1;
hideCard[card2Id] = -1;
setTimeout(() => {
this.setState(prevState => ({
shuffledCard: hideCard
}))
}, 1000);
} else {
const flipBack = this.state.isFlipped.slice();
flipBack[card1Id] = false;
flipBack[card2Id] = false;
setTimeout(() => {
this.setState(prevState => ({ isFlipped: flipBack }));
}, 1000);
}
};
Строка 71–79 это restartGame
метод. Этот метод в основном сбрасывает состояние игры.
Метод перезапуска игры
restartGame = () => {
this.setState({
isFlipped: Array(16).fill(false),
shuffledCard: App.duplicateCard().sort(() => Math.random() - 0.5),
clickCount: 1,
prevSelectedCard: -1,
prevCardId: -1
});
};
Строка 81–83 проверяет, закончилась ли игра. Если игра окончена, GameOver
отображается компонент.
метод isGameOver
isGameOver = () => {
return this.state.isFlipped.every((element, index, array) => element !== false);
};
Строка 85–106 Последний блок кода в App.js
это метод рендеринга. В Линия 88, Header
компонент передан restartGame
реквизит. isGameOver
метод используется для визуализации GameOver
компонент, когда игра окончена, в противном случае Card
компонент визуализируется.
метод визуализации
render() {
return (
<div>
<Header restartGame={this.restartGame} />
{ this.isGameOver() ? <GameOver restartGame={this.restartGame} /> :
<div className="grid-container">
{
this.state.shuffledCard.map((cardNumber, index) =>
<Card
key={index}
id={index}
cardNumber={cardNumber}
isFlipped={this.state.isFlipped[index]}
handleClick={this.handleClick}
/>
)
}
</div>
}
</div>
);
}
}
Card.jsx
, GameOver.jsx
а также Header.jsx
все презентационные компоненты. Они не содержат никакой логики приложения, а содержат реквизиты, переданные им из App.js
родительский компонент.
Ну вот! Наша веселая маленькая игра готова.
Спасибо за чтение. Похлопайте, если вам понравилось создавать карточную игру с помощью React.
Подпишись на меня в Твиттере @ямкенец