15 Puzzle Game使用ReactJS

15 Puzzle Game使用ReactJS

在本文中,我们将使用ReactJS创建15 Puzzle Game。15 puzzle game基本上是一款基于图块的游戏,其中有16个图块,其中1个图块是空的,其余的图块以1到15的随机顺序填充数字。用户必须按照数字顺序排列所有图块,规则是他们只能移动直接邻接空图块的图块。

在这个项目中,我们基本上使用了React函数组件和使用了React hooks,比如useState, useEffect等。玩家可以将图块从其位置拖动到相邻的空位置。通过使用JSX实现拖动和获胜的逻辑。

让我们看看我们的最终项目将是什么样子:

15 Puzzle Game使用ReactJS

使用的技术/先决条件:

  • ReactJs
  • Tailwind CSS
  • JSX
  • 在React中使用功能组件
  • React Hooks

方法: 容器是有状态的React组件(基于class)。组件是无状态的React组件(基于函数)。在这个项目中,我使用了组件(基于函数),为了使它们有状态,我在React中使用了hooks,如useState、useEffect等。

项目结构

15 Puzzle Game使用ReactJS

步骤

1. 使用以下命令设置React项目

npx create-react-app <name of project>

2. 使用以下步骤导航到项目文件夹

cd <name_of_project>

3. 创建一个名为“ components ”的文件夹来存储组件,以及一个名为“ utils ”的文件夹,我们将在其中创建随机生成数字数组的实用函数。在“components”文件夹中添加4个文件,分别是“Game.js”、“Puzzle.js”、“Tile.js”、“Timer.js”,并在“utils”文件夹中创建一个名为“shuffleFunction.js”的文件。

4. 要在项目中添加 tailwindcss,请在“index.html”中添加以下脚本标签。

<script src="https://cdn.tailwindcss.com"></script>

在不同的文件中编写以下代码(文件名在每个代码块的第一行中提到)。

示例:

  • index.html : 自动创建的文件,在这里我们需要导入tailwindcss标签。
  • index.js : 自动创建的文件,React用于最终渲染。
  • App.js : 此文件导入Game组件并导出它。
  • Game.js : 此文件包含游戏的整体逻辑和所有所需的组件。
  • Puzzle.js : 此文件包含拼图游戏的组件。
  • Tile.js : 此文件包含两个组件,分别是“EmptyTile”和“FilledTile”,用于在Puzzle.js中渲染拼图块。
  • Timer.js : 此文件包含计时器的逻辑并渲染时间。
  • shuffleFunction.js : 此文件包含将数组从1到16洗牌的逻辑,其中第16个位置为空字符串,并返回洗牌后的数组。

JavaScript

// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
 
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Javascript

// App.js
import Game from "./components/Game";
 
export default function App() {
  return <Game />
}

Javascript

// Game.js
import { useEffect, useState } from "react";
import shuffleArray from "../utils/shuffleFunction";
import Puzzle from "./Puzzle";
import Timer from "./Timer";
 
export default function Game() {
  const [shuffledArray, setShuffledArray] = useState(shuffleArray());
  const [moves, setMoves] = useState(0);
  const [time, setTime] = useState(0);
  const [timerActive, setTimerActive] = useState(false);
  const [win, setWin] = useState(false);
 
  useEffect(() => {
    if (moves === 1) setTimerActive(true);
    let won = true;
    for (let i = 0; i < shuffledArray.length - 1; i++) {
      const value = shuffledArray[i];
      if (i == value - 1) continue;
      else {
        won = false;
        break;
      }
    }
    if (won) {
      setWin(true);
      setTimerActive(false);
    }
    return;
  }, [moves]);
 
  const newGame = () => {
    setMoves(0);
    setTimerActive(false);
    setTime(0);
    setShuffledArray(shuffleArray());
    setWin(false);
  };
 
  const dragStart = (e) => e.dataTransfer.setData("tile", e.target.id);
 
  const dragOver = (e) => e.preventDefault();
 
  const dropped = (e) => {
    e.preventDefault();
    const tile = e.dataTransfer.getData("tile");
    const oldPlace = Number(document.getElementById(tile).parentElement.id.slice(6)) - 1;
    const newPlace = Number(e.target.id.slice(6)) - 1;
 
    if (!(Math.abs(oldPlace - newPlace) == 4 || Math.abs(oldPlace - newPlace) == 1)) return;
 
    const [i, j] = [Math.min(oldPlace, newPlace), Math.max(oldPlace, newPlace)];
    setShuffledArray([
      ...shuffledArray.slice(0, i),
      shuffledArray[j],
      ...shuffledArray.slice(i + 1, j),
      shuffledArray[i],
      ...shuffledArray.slice(j + 1),
    ]);
    setMoves(moves + 1);
  };
 
  return (
    <div className="h-screen flex text-gray-300 bg-gray-950">
      <div className="mx-auto mt-8">
        {win && (
          <div className="rounded-md border-l-4 border-green-500 bg-green-100 p-2 mb-2">
            <div className="flex items-center justify-center space-x-4">
              <p className="font-medium text-green-600">
                HURRAY!! You have won the game 🙂
              </p>
            </div>
          </div>
        )}
        <h1 className="text-3xl text-emerald-600 font-bold text-center">
          GeeksforGeeks
        </h1>
        <h3 className="text-xl font-bold text-center bg-clip-text text-transparent bg-gradient-to-r from-indigo-500 from-10% via-sky-500 via-30% to-emerald-500 to-90%">
          15 Puzzle Game
        </h3>
        <div className="flex justify-between px-6 mt-2">
          <p>Moves: {moves}</p>
          <Timer time={time} timerActive={timerActive} setTime={setTime} />
        </div>
        <Puzzle shuffledArray={shuffledArray} dragStart={dragStart} dragOver={dragOver} dropped={dropped}/>
        <div className="px-6 mt-4">
          <button
            onClick={newGame}
            className="text-black font-bold block bg-gray-900 p-2 rounded w-full h-full bg-gradient-to-r from-indigo-500 from-10% via-sky-500 via-30% to-emerald-500 to-90%"
          >
            New Game
          </button>
        </div>
      </div>
    </div>
  );
}

Javascript

// Puzzle.js
 
import { FilledTile, EmptyTile } from "./Tile";
 
export default function Puzzle({ shuffledArray, dragOver, dragStart, dropped }){
    return (
        <div className="grid grid-cols-4 gap-8 mt-6 px-6 rounded">
        {shuffledArray.map((value, index) => {
          if (value === "")
            return (
              <EmptyTile dragOver={dragOver} dropped={dropped} index={index} />
            );
          return (
            <FilledTile index={index} value={value} dragStart={dragStart} />
          );
        })}
      </div>
    )
}

Javascript

// Tile.js
 
export function FilledTile({index, value, dragStart}) {
  return (
    <div
      id={`place-{index + 1}`}
      className={
        "shadow w-20 h-20 rounded " +
        (index == value - 1
          ? "bg-gradient-to-r from-pink-500 to-yellow-500"
          : "bg-gray-900")
      }
    >
      <p
        id={`tile-{value}`}
        draggable="true"
        onDragStart={dragStart}
        className="fw-bold text-xl grid grid-cols-1 place-items-center w-20 h-20 rounded cursor-pointer hover:bg-gray-800"
      >
        {value}
      </p>
    </div>
  );
}
 
export function EmptyTile({dragOver, dropped, index}) {
  return (
    <div
      onDragOver={dragOver}
      onDrop={dropped}
      id={`place-${index + 1}`}
      className="bg-gray-900 shadow w-20 h-20 rounded"
    ></div>
  );
}

JavaScript

// Timer.js
 
import { useEffect } from "react";
 
export default function Timer({ time, setTime, timerActive }) {
  useEffect(() => {
    let interval = null;
    if (timerActive)
      interval = setInterval(() => {
        setTime((time) => time + 1);
      }, 1000);
    else clearInterval(interval);
    return () => {
      clearInterval(interval);
    };
  }, [timerActive]);
 
  return <p>Time: {time}s</p>;
}

Javascript

// shuffleFunction.js
 
export default function shuffleArray() {
  let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ""];
  for (let i = array.length - 1; i > 0; i--) {
    let j = Math.floor(Math.random() * (i + 1));
    [array[i], array[j]] = [array[j], array[i]];
  }
  return array;
}

HTML

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>Project | 15 Puzzle Game</title>
    <script src="https://cdn.tailwindcss.com"></script>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

运行应用程序的步骤:

1. 在终端中输入以下命令:

npm start

2. 在网络浏览器中打开以下URL:

http://localhost:3000/

输出:

15 Puzzle Game使用ReactJS

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程