Как загрузить все изображения перед началом игры? (JavaScript, Предварительный загрузчик)

#javascript #preloading #image-preloader

Вопрос:

Я разработал эту игру, это мой первый проект. Это спин-офф от «Игры в свинью» в курсе JavaScript. Я изменил шаблоны HTML и CSS игры Pig для пользовательского интерфейса, но я сделал дизайн и кодирование игры с нуля. Вы можете поиграть в эту игру здесь: https://jeffparadox.000webhostapp.com/

У меня есть несколько вопросов, если кого-то это волнует:

  1. Как вы думаете, видите ли вы какие-либо проблемы? Может ли что-нибудь быть яснее (особенно с точки зрения пользовательского интерфейса), чем сейчас?
  2. Игра быстро работает на моем компьютере. Но когда я захожу на сайт, изображения не начинают вращаться сразу; требуется около 30 секунд, чтобы начать видеть, как изображения заметно вращаются. Я думаю, это потому, что браузер загружает изображения, но код работает быстрее. Есть ли способ предварительно загрузить эти изображения в код, чтобы игра началась правильно? Или, если я почищу свой код, будет ли игра загружаться быстрее без необходимости предварительной загрузки изображений?
  3. Вот мой код JS. Если кто-нибудь заинтересован в том, чтобы проверить это и сказать мне, какие части я могу очистить и оптимизировать, я был бы очень признателен. Заранее благодарю:
 "use strict";

// Selecting elements
const player0El = document.querySelector(".player--0");
const player1El = document.querySelector(".player--1");
const tries0El = document.getElementById("tries--0");
const tries1El = document.getElementById("tries--1");
const current0El = document.getElementById("current--0");
const current1El = document.getElementById("current--1");

const animalEl = document.querySelector(".animal");
const btnSpin = document.querySelector(".btn--spin");
const btnReset = document.querySelector(".btn--reset");
const btnRestart = document.querySelector(".btn--restart");

const youWin0El = document.querySelector("#you-win--0");
const youWin1El = document.querySelector("#you-win--1");

const highScore0El = document.querySelector(".high-score--0");
const highScore1El = document.querySelector(".high-score--1");

// Declare let variables
let triesLeft,
  playerScores,
  highScores,
  activePlayer,
  round,
  currentScore,
  playing;

// Starting conditions
const init = function () {
  youWin0El.classList.add("hidden");
  youWin1El.classList.add("hidden");
  youWin1El.textContent = "You Win! 🎉";
  youWin0El.textContent = "You Win! 🎉";
  currentScore = 0;
  triesLeft = [10, 10];
  playerScores = [0, 0];
  highScores = [0, 0];
  activePlayer = 0;
  round = 3;
  playing = true;

  btnRestart.textContent = `🕑 ROUND: ${round}`;

  tries0El.textContent = 10;
  tries1El.textContent = 10;
  current0El.textContent = 0;
  current1El.textContent = 0;

  animalEl.src = "noAnimal.jpg";
  player0El.classList.remove("player--winner");
  player1El.classList.remove("player--winner");
  player0El.classList.add("player--active");
  player1El.classList.remove("player--active");
};

// Initialize game
init();

// ***GAME FUNCTIONS***

// Switch players
const switchPlayer = function () {
  activePlayer = activePlayer === 0 ? 1 : 0;
  player0El.classList.toggle("player--active");
  player1El.classList.toggle("player--active");
};

// Check how many rounds left
const checkRound = function () {
  btnRestart.textContent = `🕑 ROUND: ${round}`;
  if (round < 1) {
    gameOver();
  } else if (triesLeft[activePlayer] < 1 amp;amp; round > 0) {
    if (triesLeft[0] === 0 amp;amp; triesLeft[1] === 0) {
      triesLeft[0] = 10;
      triesLeft[1] = 10;
      tries0El.textContent = 10;
      tries1El.textContent = 10;
    }
    switchPlayer();
  }
};

// End of game
const gameOver = function () {
  playing = false;
  if (playerScores[0] > playerScores[1]) {
    youWin0El.classList.remove("hidden");
  } else if (playerScores[0] < playerScores[1]) {
    youWin1El.classList.remove("hidden");
  } else if (playerScores[0] === playerScores[1]) {
    youWin1El.textContent = "It's a Tie 😲";
    youWin0El.textContent = "It's a Tie 😳";
    youWin1El.classList.remove("hidden");
    youWin0El.classList.remove("hidden");
  }
};

// Check the rabbit, increase and log the score
const checkRabbit = function () {
  if (imageNumber === 0) {
    currentScore =
      Number(document.getElementById(`current--${activePlayer}`).textContent)  
      1;
    playerScores[activePlayer] = currentScore;
    document.getElementById(
      `current--${activePlayer}`
    ).textContent = currentScore;
  }
};

// Update tries left
const triesUpdate = function () {
  triesLeft[activePlayer] -= 1;
  document.getElementById(`tries--${activePlayer}`).textContent =
    triesLeft[activePlayer];
};

// Update high scores
const registerHighScore = function () {
  if (playerScores[activePlayer] > highScores[activePlayer]) {
    highScores[activePlayer] = playerScores[activePlayer];
    document.getElementById(
      `high-score--${activePlayer}`
    ).textContent = `High Score: ${highScores[activePlayer]}`;
  }
};

// ***GAME ENGINE***

// Declare game engine variables
let interval, imageNumber;

// Spinning images
btnSpin.addEventListener("click", function () {
  if (playing) {
    // Change button to Stop
    btnSpin.textContent = `⛔ STOP!`;
    // Stop the spinning (Runs only when interval is declared)
    if (interval) {
      clearInterval(interval);
      interval = null;
      btnSpin.textContent = `🎰 SPIN!`;
      triesUpdate();
      checkRabbit();
      registerHighScore();
      if (triesLeft[0] < 1 amp;amp; triesLeft[1] < 1) {
        round -= 1;
      }
      checkRound();
      // Start the spinning (Runs only when interval is null or undefined)
    } else {
      // Loop with time intervals
      interval = setInterval(function () {
        // Genarate image number
        imageNumber = Math.trunc(Math.random() * 10);
        // Show image with the generated number
        animalEl.src = `animal-${imageNumber}.jpg`;
      }, 5);
    }
  }
});

// ***RESET GAME***
btnReset.addEventListener("click", init);
 

Комментарии:

1. Для получения мнений об общем рабочем коде, codereview.stackexchange.com это то место, которое вы хотите посетить.

2. Я здесь новенькая. Конечно. Спасибо!

3. В качестве небольшой обратной связи: мне нравится пользовательский интерфейс, он очень чистый. Изображение животного может быть больше, а кнопка «Вращаться!» и не-кнопка «Круглый» выглядят одинаково, но это незначительно. Одна вещь, которую я пропустил в первый раз, заключалась в том, что целью было «поймать кролика» — это написано на маленьком изображении кролика-заполнителя, но больше нигде. Кроме того, вы устанавливаете вращение на 5 мс за шаг-200 кадров в секунду, что невозможно даже на большинстве мониторов, что делает игру исключительно основанной на удаче. Попробуйте поэкспериментировать с более длительными интервалами, чтобы это действительно проверило ваши рефлексы.

4. Отличные предложения, большое спасибо!

Ответ №1:

Вы можете предварительно загрузить изображения, поместив это в свой <head> для каждого используемого изображения:

 <link rel="preload" as="image" href="animal-1.png">
 

Дополнительная документация здесь: https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content

Что касается других вопросов, они могут лучше подойти для обзора кода SE: https://codereview.stackexchange.com/

Комментарии:

1. Большое спасибо за помощь. Теперь у меня есть еще одна проблема: Math.random иногда создает одно и то же число дважды подряд, что дает игроку больше времени, чтобы поймать кролика, чем установленный мной интервал. Есть ли способ быть случайным без повторения? Я могу сделать это, чтобы свести к минимуму шансы, но это все равно не устраняет проблему:

2. interval = setInterval(function () { imageNumber = Math.trunc(Math.random() * 10); if (imageNumber !== isSameNumber) { animalEl.src = животное-${Номер изображения}.jpg ; isSameNumber = imageNumber; } else { imageNumber = Math.trunc(Math.random() * 10); animalEl.src = животное-${номер изображения}.jpg ; isSameNumber = imageNumber; } }, 500);

3. Я бы использовал что-то вроде let nextNumber = Math.trunc(Math.random() * 9); if(nextNumber == previousNumber) nextNumber ;