🎮ArcadeLab

Learn English

by RocketHawk87
692 lines12.9 KB
▶ Play
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Learn English</title>

<style>
* {
  box-sizing: border-box;
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 20px;
  font-family: "Trebuchet MS", Arial, sans-serif;
  background: linear-gradient(135deg, #dbeafe, #ede9fe);
  color: #1e293b;
  transition: 0.4s;
}

.game-container {
  width: 100%;
  max-width: 850px;
  min-height: 550px;
  padding: 35px;
  background: rgba(255, 255, 255, 0.95);
  border-radius: 25px;
  box-shadow: 0 12px 35px rgba(0, 0, 0, 0.15);
  text-align: center;
}

h1 {
  margin: 0;
  font-family: Georgia, serif;
  font-size: clamp(2.2rem, 7vw, 4rem);
  color: #4f46e5;
  cursor: pointer;
  user-select: none;
}

#impossible-word {
  min-height: 28px;
  margin: 5px 0 25px;
  font-size: 1.4rem;
  font-weight: bold;
  color: transparent;
}

h2 {
  font-size: clamp(1.3rem, 4vw, 2rem);
  margin-bottom: 25px;
}

.hidden {
  display: none !important;
}

button {
  border: 0;
  border-radius: 12px;
  padding: 14px 24px;
  margin: 8px;
  font-size: 1rem;
  font-weight: bold;
  cursor: pointer;
  transition: 0.2s;
}

button:hover {
  transform: scale(1.05);
}

button:active {
  transform: scale(0.97);
}

.play-button {
  background: #4f46e5;
  color: white;
  font-size: 1.2rem;
  padding: 16px 45px;
}

.difficulty-button {
  display: block;
  width: min(100%, 300px);
  margin: 15px auto;
  color: white;
}

.easy {
  background: #16a34a;
}

.medium {
  background: #d97706;
}

.hard {
  background: #dc2626;
}

.back-button {
  background: #64748b;
  color: white;
  margin-top: 25px;
}

#score,
#timer,
#question-counter {
  font-size: 1.15rem;
  font-weight: bold;
  margin: 10px;
}

#timer {
  color: #dc2626;
}

#options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 15px;
  margin-top: 25px;
}

.option {
  min-height: 120px;
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0;
  padding: 15px;
  background: #f1f5f9;
  border: 3px solid transparent;
  border-radius: 18px;
  font-size: 3rem;
  transition: 0.2s;
}

.option:hover {
  background: #dbeafe;
  border-color: #6366f1;
  transform: scale(1.05);
}

.correct {
  background: #bbf7d0 !important;
  border-color: #16a34a !important;
}

.incorrect {
  background: #fecaca !important;
  border-color: #dc2626 !important;
}

#feedback {
  min-height: 30px;
  margin-top: 20px;
  font-size: 1.2rem;
  font-weight: bold;
}

.correct-text {
  color: #16a34a;
}

.wrong-text {
  color: #dc2626;
}

#final-score {
  font-size: 1.5rem;
  font-weight: bold;
  margin: 25px 0;
}

/* MODO IMPOSSÍVEL */

body.impossible-mode {
  background: red;
  color: yellow;
}

body.impossible-mode .game-container {
  background: #b00000;
  border: 4px solid yellow;
  box-shadow: 0 0 30px yellow;
}

body.impossible-mode h1,
body.impossible-mode h2,
body.impossible-mode p,
body.impossible-mode #impossible-word,
body.impossible-mode #score,
body.impossible-mode #timer,
body.impossible-mode #question-counter {
  color: yellow !important;
}

body.impossible-mode button {
  border: 2px solid yellow;
}

body.impossible-mode .option {
  background: #8b0000;
  border-color: yellow;
  color: yellow;
}

body.impossible-mode .option:hover {
  background: #d00000;
}

body.impossible-mode .back-button {
  background: #650000;
  color: yellow;
}

@media (max-width: 600px) {
  .game-container {
    padding: 25px 15px;
  }

  #options {
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
  }

  .option {
    min-height: 90px;
    font-size: 2.4rem;
  }
}
</style>
</head>

<body>

<main class="game-container">

  <!-- MENU PRINCIPAL -->
  <section id="menu-screen">
    <h1 id="game-title">Learn English</h1>
    <p id="impossible-word">impossível</p>

    <p>Aprenda palavras em inglês enquanto joga!</p>

    <button id="play-button" class="play-button">
      Jogar
    </button>
  </section>

  <!-- ESCOLHA DE DIFICULDADE -->
  <section id="difficulty-screen" class="hidden">
    <h2>Escolha a dificuldade</h2>

    <button class="difficulty-button easy" data-difficulty="easy">
      Fácil
    </button>

    <button class="difficulty-button medium" data-difficulty="medium">
      Médio
    </button>

    <button class="difficulty-button hard" data-difficulty="hard">
      Difícil
    </button>

    <button id="difficulty-back-button" class="back-button">
      Voltar
    </button>
  </section>

  <!-- JOGO -->
  <section id="game-screen" class="hidden">
    <h2 id="question"></h2>

    <p id="question-counter">Pergunta: 1</p>
    <p id="score">Pontos: 0</p>
    <p id="timer" class="hidden">Tempo: 30s</p>

    <div id="options"></div>

    <p id="feedback"></p>

    <button id="game-back-button" class="back-button">
      Sair
    </button>
  </section>

  <!-- RESULTADO -->
  <section id="victory-screen" class="hidden">
    <h2 id="result-title">Você venceu!</h2>

    <p id="final-score"></p>

    <button id="restart-button" class="play-button">
      Jogar novamente
    </button>

    <button id="menu-button" class="back-button">
      Menu principal
    </button>
  </section>

</main>

<script>
const words = [
  { english: "Glue", emoji: "🧴" },
  { english: "Notebook", emoji: "📓" },
  { english: "Book", emoji: "📚" },
  { english: "Pencil", emoji: "✏️" },
  { english: "Pen", emoji: "🖊️" },
  { english: "Pair of scissors", emoji: "✂️" },
  { english: "Schoolbag", emoji: "🎒" },
  { english: "Ruler", emoji: "📏" },
  { english: "Marker", emoji: "🖍️" },
  { english: "Eraser", emoji: "🧽" },
  { english: "Ball", emoji: "⚽" },
  { english: "Doll", emoji: "🪆" },
  { english: "Cat", emoji: "🐱" },
  { english: "Dog", emoji: "🐶" }
];

/*
  Dificuldades normais:
  Fácil: 2 opções, meta de 10 pontos.
  Médio: 4 opções, meta de 10 pontos.
  Difícil: 8 opções, meta de 20 pontos.

  Modo impossível:
  Fácil: 5 opções, 20 segundos.
  Médio: 10 opções, 20 segundos.
  Difícil: 14 opções, 30 segundos.
*/

const normalSettings = {
  easy: {
    options: 2,
    target: 10,
    penalty: 1
  },

  medium: {
    options: 4,
    target: 10,
    penalty: 1
  },

  hard: {
    options: 8,
    target: 20,
    penalty: 2
  }
};

const impossibleSettings = {
  easy: {
    options: 5,
    target: 10,
    penalty: 1,
    time: 20
  },

  medium: {
    options: 10,
    target: 10,
    penalty: 1,
    time: 20
  },

  hard: {
    options: 14,
    target: 20,
    penalty: 2,
    time: 30
  }
};

const menuScreen = document.getElementById("menu-screen");
const difficultyScreen = document.getElementById("difficulty-screen");
const gameScreen = document.getElementById("game-screen");
const victoryScreen = document.getElementById("victory-screen");

const gameTitle = document.getElementById("game-title");
const impossibleWord = document.getElementById("impossible-word");

const playButton = document.getElementById("play-button");
const difficultyBackButton =
  document.getElementById("difficulty-back-button");

const gameBackButton =
  document.getElementById("game-back-button");

const restartButton =
  document.getElementById("restart-button");

const menuButton =
  document.getElementById("menu-button");

const questionElement =
  document.getElementById("question");

const questionCounterElement =
  document.getElementById("question-counter");

const scoreElement =
  document.getElementById("score");

const timerElement =
  document.getElementById("timer");

const optionsElement =
  document.getElementById("options");

const feedbackElement =
  document.getElementById("feedback");

const resultTitle =
  document.getElementById("result-title");

const finalScoreElement =
  document.getElementById("final-score");

let currentDifficulty = "easy";
let currentWord = null;
let score = 0;
let questionNumber = 0;
let titleClicks = 0;
let timeLeft = 0;
let timerInterval = null;
let questionLocked = false;

function showScreen(screen) {
  menuScreen.classList.add("hidden");
  difficultyScreen.classList.add("hidden");
  gameScreen.classList.add("hidden");
  victoryScreen.classList.add("hidden");

  screen.classList.remove("hidden");
}

function shuffle(array) {
  return [...array].sort(() => Math.random() - 0.5);
}

function getSettings() {
  if (document.body.classList.contains("impossible-mode")) {
    return impossibleSettings[currentDifficulty];
  }

  return normalSettings[currentDifficulty];
}

/*
  O cronômetro só existe no modo impossível.
  Ele começa uma vez no início da partida
  e NÃO é reiniciado nas próximas perguntas.
*/

function startTimerOnce() {
  stopTimer();

  const settings = impossibleSettings[currentDifficulty];

  timeLeft = settings.time;

  timerElement.classList.remove("hidden");
  timerElement.textContent = `Tempo: ${timeLeft}s`;

  timerInterval = setInterval(() => {
    timeLeft--;

    timerElement.textContent = `Tempo: ${timeLeft}s`;

    if (timeLeft <= 0) {
      stopTimer();

      if (!questionLocked) {
        questionLocked = true;

        feedbackElement.textContent = "Tempo esgotado!";
        feedbackElement.className = "wrong-text";

        setTimeout(() => {
          endGame(false);
        }, 700);
      }
    }
  }, 1000);
}

function stopTimer() {
  clearInterval(timerInterval);
  timerInterval = null;
}

function startGame(difficulty) {
  currentDifficulty = difficulty;
  score = 0;
  questionNumber = 0;
  questionLocked = false;

  scoreElement.textContent = "Pontos: 0";
  feedbackElement.textContent = "";
  feedbackElement.className = "";

  timerElement.classList.add("hidden");

  showScreen(gameScreen);

  /*
    O cronômetro é iniciado somente uma vez,
    antes da primeira pergunta.
  */
  if (document.body.classList.contains("impossible-mode")) {
    startTimerOnce();
  }

  nextQuestion();
}

function nextQuestion() {
  const settings = getSettings();

  questionLocked = false;

  feedbackElement.textContent = "";
  feedbackElement.className = "";

  questionNumber++;

  currentWord =
    words[Math.floor(Math.random() * words.length)];

  questionElement.textContent =
    `Clique em: ${currentWord.english}`;

  questionCounterElement.textContent =
    `Pergunta: ${questionNumber}`;

  let selectedWords =
    shuffle(words).slice(0, settings.options);

  if (
    !selectedWords.some(
      word => word.english === currentWord.english
    )
  ) {
    selectedWords[0] = currentWord;
  }

  const finalOptions = shuffle(selectedWords);

  optionsElement.innerHTML = "";

  finalOptions.forEach(word => {
    const option = document.createElement("button");

    option.className = "option";
    option.textContent = word.emoji;
    option.setAttribute("aria-label", "Opção de resposta");

    option.addEventListener("click", () => {
      checkAnswer(word, option);
    });

    optionsElement.appendChild(option);
  });

  /*
    NÃO iniciar o cronômetro aqui.
    Isso evita que o tempo seja resetado.
  */
}

function checkAnswer(selectedWord, selectedButton) {
  if (questionLocked) {
    return;
  }

  questionLocked = true;

  const settings = getSettings();

  if (selectedWord.english === currentWord.english) {
    score++;

    selectedButton.classList.add("correct");

    feedbackElement.textContent = "Correto!";
    feedbackElement.className = "correct-text";
  } else {
    score -= settings.penalty;

    selectedButton.classList.add("incorrect");

    feedbackElement.textContent =
      `Errado! −${settings.penalty} ponto(s)`;

    feedbackElement.className = "wrong-text";
  }

  scoreElement.textContent = `Pontos: ${score}`;

  if (score >= settings.target) {
    setTimeout(() => {
      endGame(true);
    }, 700);

    return;
  }

  setTimeout(() => {
    nextQuestion();
  }, 700);
}

function endGame(won) {
  stopTimer();

  questionLocked = true;

  showScreen(victoryScreen);

  if (won) {
    resultTitle.textContent = "Você venceu!";
  } else {
    resultTitle.textContent = "Tempo esgotado!";
  }

  finalScoreElement.textContent =
    `Pontuação final: ${score}`;
}

/* Eventos do menu */

playButton.addEventListener("click", () => {
  showScreen(difficultyScreen);
});

document.querySelectorAll(".difficulty-button").forEach(button => {
  button.addEventListener("click", () => {
    startGame(button.dataset.difficulty);
  });
});

difficultyBackButton.addEventListener("click", () => {
  showScreen(menuScreen);
});

gameBackButton.addEventListener("click", () => {
  stopTimer();
  showScreen(menuScreen);
});

restartButton.addEventListener("click", () => {
  showScreen(difficultyScreen);
});

menuButton.addEventListener("click", () => {
  showScreen(menuScreen);
});

/*
  Ao clicar 20 vezes no título:
  - ativa o modo impossível;
  - deixa o fundo vermelho;
  - deixa os textos amarelos;
  - mostra "impossível".
*/

gameTitle.addEventListener("click", () => {
  titleClicks++;

  if (titleClicks >= 20) {
    document.body.classList.add("impossible-mode");
    impossibleWord.style.color = "yellow";
  }
});
</script>

</body>
</html>

Game Source: Learn English

Creator: RocketHawk87

Libraries: none

Complexity: complex (692 lines, 12.9 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: learn-english-rockethawk87-mtrcmshi" to link back to the original. Then publish at arcadelab.ai/publish.