Construindo um Jogo de Quebra-Cabeça Drag-and-Drop em React

JavaScriptBeginner
Pratique Agora

Introdução

Neste projeto, criaremos um jogo de quebra-cabeça com funcionalidade de arrastar e soltar usando React. Este é um excelente projeto para iniciantes aprenderem sobre componentes React, gerenciamento de estado e como lidar com interações do usuário. Ao final deste projeto, você terá um jogo de quebra-cabeça funcional.

👀 Pré-visualização

Puzzle game preview animation

🎯 Tarefas

Neste projeto, você aprenderá:

  • Como configurar uma nova aplicação React
  • Como criar o componente principal do jogo de quebra-cabeça
  • Como gerenciar o estado e configurar a imagem do quebra-cabeça
  • Como exibir as peças do quebra-cabeça na tela
  • Como implementar a funcionalidade de arrastar e soltar (drag and drop)
  • Como incorporar o componente PuzzleGame no arquivo principal da aplicação
  • Como adicionar CSS para estilizar o quebra-cabeça

🏆 Conquistas

Após concluir este projeto, você será capaz de:

  • Configurar uma aplicação React e criar um componente
  • Gerenciar o estado e lidar com interações do usuário
  • Implementar a funcionalidade de arrastar e soltar (drag and drop)
  • Incorporar estilos para tornar o quebra-cabeça visualmente atraente

Configuração do Projeto

Objetivo: A base do nosso jogo de quebra-cabeça é uma nova aplicação React.

  • Abra seu terminal.

  • Navegue até o diretório do seu projeto:

    cd puzzle-game
  • Instale as dependências do projeto:

    npm install
✨ Verificar Solução e Praticar

Criar Componente PuzzleGame

Objetivo: Configurar o componente principal do jogo de quebra-cabeça.

  • Dentro do diretório src, crie uma pasta chamada components.
  • Dentro de components, crie um novo arquivo chamado PuzzleGame.js.
  • Adicione a seguinte estrutura básica a PuzzleGame.js:
// src/components/PuzzleGame.js
// Importando React e useState para gerenciar o estado do componente
import React, { useState, useEffect } from "react";

// Definindo o componente PuzzleGame
const PuzzleGame = () => {
  // Este componente irá lidar com a lógica e a interface do jogo
  return (
    <div className="game-container">
      {/* Aqui é onde o quebra-cabeça será renderizado */}
    </div>
  );
};

// Exportando o componente para uso em outros arquivos
export default PuzzleGame;
✨ Verificar Solução e Praticar

Implementar Estado e Configuração da Imagem

Objetivo: Configurar o estado para gerenciar as peças do quebra-cabeça e definir a imagem do quebra-cabeça.

  • Em PuzzleGame.js, importe useState do React.
  • Defina uma variável de estado para acompanhar as posições das peças do quebra-cabeça.
  • Defina a URL da imagem do quebra-cabeça (coloque uma imagem chamada corgi.png na pasta public).
// src/components/PuzzleGame.js

// ...outras importações
const PuzzleGame = () => {
  // Define a URL da imagem e as posições iniciais das peças do quebra-cabeça
  const imgUrl = "corgi.png"; // Certifique-se de que esta imagem existe na pasta public
  const [positions, setPositions] = useState([...Array(16).keys()]);

  useEffect(() => {
    // Embaralha as posições para a configuração inicial do quebra-cabeça
    setPositions((prevPositions) => {
      const newPos = [...prevPositions];
      newPos.sort(() => Math.random() - 0.5);
      return newPos;
    });
  }, []);

  // Declaração de retorno do componente
  return (
    <div className="game-container">
      {/* A interface do quebra-cabeça será adicionada aqui em etapas posteriores */}
    </div>
  );
};

// Exportando o componente PuzzleGame
export default PuzzleGame;
✨ Verificar Solução e Praticar

Renderizar Peças do Quebra-Cabeça

Objetivo: Exibir as peças do quebra-cabeça na tela.

  • Mapear sobre o estado positions para renderizar peças individuais do quebra-cabeça.
  • Cada peça deve exibir uma porção da imagem.
// src/components/PuzzleGame.js
const PuzzleGame = () => {
  // ...código anterior

  return (
    <div className="game-container">
      <div className="reference-image">
        <img src={imgUrl} alt="Reference Image" />
      </div>
      <div className="puzzle-container">
        {positions.map((pos, index) => {
          const x = (pos % 4) * 100;
          const y = Math.floor(pos / 4) * 100;
          return (
            <div
              key={index}
              className="puzzle-piece"
              style={{
                backgroundImage: `url('${imgUrl}')`,
                backgroundPosition: `-${x}px -${y}px`
              }}
            />
          );
        })}
      </div>
    </div>
  );
};
✨ Verificar Solução e Praticar

Adicionar Funcionalidade de Arrastar e Soltar

Objetivo: Implementar a lógica para arrastar e soltar as peças do quebra-cabeça.

  • Adicionar manipuladores (handlers) para os eventos de início de arrasto (drag start), arrastar sobre (drag over) e soltar (drop).
  • Implementar a lógica para trocar as peças do quebra-cabeça quando soltas.
// src/components/PuzzleGame.js

const PuzzleGame = () => {
  // ...código anterior

  // Manipulando o início de um evento de arrasto
  const handleDragStart = (e, position) => {
    e.dataTransfer.setData("text/plain", position);
  };

  // Manipulando o evento de soltar
  const handleDrop = (e, position) => {
    e.preventDefault();
    const originalPosition = e.dataTransfer.getData("text");
    // Adicione a lógica aqui para trocar as posições das peças do quebra-cabeça
    setPositions((prevPositions) => {
      const newPos = [...prevPositions];
      [newPos[originalPosition], newPos[position]] = [
        newPos[position],
        newPos[originalPosition]
      ];
      return newPos;
    });
  };

  // Permitindo a ação de soltar, prevenindo o comportamento padrão
  const handleDragOver = (e) => {
    e.preventDefault();
  };

  // Renderizar as peças do quebra-cabeça com os manipuladores de arrastar e soltar adicionados
};
// src/components/PuzzleGame.js
const PuzzleGame = () => {
  // ...código anterior

  return (
    <div className="game-container">
      <div className="reference-image">
        <img src={imgUrl} alt="Reference Image" />
      </div>
      <div className="puzzle-container">
        {positions.map((pos, index) => {
          const x = (pos % 4) * 100;
          const y = Math.floor(pos / 4) * 100;
          return (
            <div
              key={index}
              className="puzzle-piece"
              draggable
              onDragStart={(e) => handleDragStart(e, index)}
              onDrop={(e) => handleDrop(e, index)}
              onDragOver={handleDragOver}
              style={{
                backgroundImage: `url('${imgUrl}')`,
                backgroundPosition: `-${x}px -${y}px`
              }}
            />
          );
        })}
      </div>
    </div>
  );
};
✨ Verificar Solução e Praticar

Atualizando o Componente App

Objetivo: Incorporar o componente PuzzleGame no arquivo principal da aplicação.

  • Abra src/App.js.
  • Renderize o componente PuzzleGame.
// src/App.js

import React from "react";
import "./App.css";
import PuzzleGame from "./components/PuzzleGame";

// Componente App que renderiza o componente PuzzleGame
function App() {
  return (
    <div className="App">
      <PuzzleGame />
    </div>
  );
}

export default App;
✨ Verificar Solução e Praticar

Estilizando o Quebra-Cabeça

Objetivo: Adicionar CSS para tornar o quebra-cabeça visualmente atraente.

  • Abra src/App.css.
  • Adicione estilos para .game-container e .puzzle-piece para posicionar o quebra-cabeça corretamente.
body {
  font-family: "Arial", sans-serif;
  text-align: center;
  padding: 20px;
  background: #f0f0f0;
}

.game-container {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 20px;
}

.reference-image {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 3px solid #aaa9a9;
  /* Adicione uma borda para consistência */
  padding: 10px;
  /* Adicione algum preenchimento em torno da imagem */
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  /* Adicione sombra para profundidade */
}

.reference-image img {
  display: block;
  /* Remova qualquer espaçamento inline padrão */
  max-width: 200px;
}

.puzzle-container {
  width: 400px;
  height: 400px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2px;
  border: 5px solid #aaa9a9;
  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
  /* Adicione uma sombra maior para um efeito 3D */
  background: #ddd;
  /* Fundo claro para as lacunas */
}

.puzzle-piece {
  width: 100%;
  height: 100%;
  background-size: 400px 400px;
  cursor: grab;
  box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.3);
  /* Adicione sombra interna para cada peça */
}
✨ Verificar Solução e Praticar

Executando a Aplicação

Objetivo: Iniciar a aplicação para ver o jogo de quebra-cabeça completo.

  • No diretório do seu projeto, execute:

    npm start
  • A aplicação deve abrir no seu navegador web, exibindo o jogo de quebra-cabeça.

✨ Verificar Solução e Praticar

Resumo

Parabéns! Você construiu com sucesso um jogo de quebra-cabeça de arrastar e soltar em React. Este projeto abordou a configuração de um projeto React, a criação de componentes, o gerenciamento de estado, o tratamento de interações do usuário e a aplicação de estilos básicos. Agora você pode experimentar a adição de mais recursos, como um cronômetro, pontuação ou diferentes níveis para aprimorar o jogo.