Как создать карточную игру 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 папку, создайте две папки:

  1. components папка: в эту папку будут добавлены две папки. Они есть:
    а. cardпапка: содержит файлы Card и GameOver JSX.
    б. header папка: содержит JSX-файл заголовка.
  2. stylesпапка: куда мы поместим наш пользовательский файл CSS.

Нам также необходимо удалить эти файлы в srcпапка.

  1. App.css
  2. index.css
  3. logo.svg

С созданием папок и удалением некоторых файлов наша структура папок должна выглядеть так:


структура папок игры

Приложение в настоящее время не работает, потому что мы все еще ссылаемся на некоторые файлы, которые мы удалили. Чтобы решить эту проблему, откройте App.js а также index.jsфайлы и удалить строки, где мы импортируем logo.svg, App.css, and index.css.

Настройте файлы приложения

  1. в 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;
  1. в 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;
  1. Заменить содержимое 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;
  1. Наконец, в 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.

Подпишись на меня в Твиттере @ямкенец

Похожие записи

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *