How to load all images before the game starts? (JavaScript, Preloader) - javascript
I've designed this game, it's my first project. It's a spin-off from "The Pig Game" in a JavaScript course. I tweaked the HTML and CSS templates of the Pig Game for the UI, but I did the game design and coding from scratch. You can play the game here: https://jeffparadox.000webhostapp.com/
I've got some questions, if anyone cares:
What do you think, do you see any problems? Can anything be clearer (especially in terms of UI) than it is now?
Game works fast on my comp. But when I visit the site, images don't start spinning right away; it takes about 30 seconds to start seeing images spin visibly. I think it's because the browser is loading the images but the code runs faster. Is there a way to pre-load these images in the code, so the game starts properly? Or, if I clean up my code, will the game load faster without needing to pre-load the images?
Here's my JS code. If anyone's interested in checking it and telling me which parts I can clean-up and optimize, I'd really appreciate it. Thanks in advace:
"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 && round > 0) {
if (triesLeft[0] === 0 && 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 && 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);
You can preload images by putting this in your <head> for each image you use:
<link rel="preload" as="image" href="animal-1.png">
More documentation here: https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content
As for the other questions, they may be a better fit at SE Code Review: https://codereview.stackexchange.com/
Related
why is MIDI scripter dropping events after 20x loops in MainStage 3
my drum riff script seems to work up until the riff is repeated (i think around) 20 times. then some notes like snare... start to dissappear. if i hit the global stop and play again it works. also if i reload the script it doesn't help which makes me think... but come up with the road to nowhere. any ideas? The problem starts at beat position 640 (20x 32 beats per loop). const riffs = [ ['11th Hour',[[1,49,114,1,0],[0,49,0,1.25,0],[1,46,89,1.501,20],[1,36,101,1.748,0],[0,46,0,1.751,20],[0,36,0,1.998,0],[1,46,92,2.001,30],[0,46,0,2.251,30],[1,36,114,2.495,0],[1,46,84,2.498,30],[0,36,0,2.745,0],[0,46,0,2.748,30],[1,38,120,2.999,0],[1,46,113,3.003,30],[0,38,64,3.249,0],[0,46,0,3.253,30],[1,46,85,3.499,20],[0,46,0,3.749,20],[1,46,88,4.002,30],[0,46,0,4.252,30],[1,46,87,4.504,30],[1,36,77,4.743,0],[0,46,0,4.754,30],[0,36,0,4.993,0],[1,36,114,4.999,0],[1,46,107,5.002,30],[0,36,0,5.249,0],[0,46,0,5.252,30],[1,46,82,5.506,30],[1,36,106,5.744,0],[0,46,0,5.756,30],[0,36,0,5.994,0],[1,46,92,5.999,30],[0,46,0,6.249,30],[1,36,114,6.489,0],[1,46,84,6.504,20],[0,36,0,6.739,0],[0,46,0,6.754,20],[1,46,113,6.992,30],[1,38,120,7,0],[0,46,0,7.242,30],[0,38,64,7.25,0],[1,46,81,7.505,20],[0,46,0,7.755,20],[1,46,90,7.999,30],[1,36,102,8.243,0],[0,46,0,8.248,30],[0,36,0,8.493,0],[1,38,120,8.495,0],[1,46,113,8.498,30],[0,38,64,8.745,0],[0,46,0,8.748,30],[1,36,114,8.995,0],[1,46,107,9.002,30],[0,36,0,9.245,0],[0,46,0,9.252,30],[1,46,85,9.502,20],[1,36,101,9.745,0],[0,46,0,9.752,20],[0,36,0,9.995,0],[1,46,93,9.998,30],[0,46,0,10.248,30],[1,36,114,10.49,0],[1,46,84,10.498,20],[0,36,0,10.74,0],[0,46,0,10.748,20],[1,38,120,10.995,0],[1,46,113,10.998,30],[0,38,64,11.245,0],[0,46,0,11.248,30],[1,46,81,11.495,30],[0,46,0,11.745,30],[1,46,90,12,30],[0,46,0,12.25,30],[1,46,84,12.498,20],[1,36,77,12.737,0],[0,46,0,12.748,20],[0,36,0,12.988,0],[1,36,114,12.994,0],[1,46,107,13,30],[0,36,0,13.244,0],[0,46,0,13.25,30],[1,46,88,13.498,30],[1,36,104,13.734,0],[0,46,0,13.748,30],[0,36,0,13.984,0],[1,46,86,13.995,30],[0,46,0,14.245,30],[1,36,114,14.494,0],[1,46,89,14.501,20],[0,36,0,14.744,0],[0,46,0,14.751,20],[1,46,113,14.99,30],[1,38,120,14.994,0],[0,46,0,15.24,30],[1,36,99,15.242,0],[0,38,64,15.244,0],[0,36,0,15.492,0],[1,46,88,15.501,20],[1,36,106,15.735,0],[0,46,0,15.751,20],[0,36,0,15.985,0],[1,46,89,15.997,30],[0,46,0,16.247,30],[1,38,83,16.49,0],[0,38,64,16.74,0],[1,40,105,16.743,0],[1,57,114,16.991,0],[0,40,64,16.993,0],[1,36,114,16.993,0],[0,57,0,17.241,0],[0,36,0,17.243,0],[1,46,86,17.499,30],[1,36,101,17.744,0],[0,46,0,17.749,30],[0,36,0,17.994,0],[1,46,88,18,30],[0,46,0,18.25,30],[1,36,114,18.494,0],[1,46,84,18.499,30],[0,36,0,18.744,0],[0,46,0,18.749,30],[1,46,113,19,30],[1,38,120,19.003,0],[0,46,0,19.25,30],[0,38,64,19.253,0],[1,46,81,19.503,20],[0,46,0,19.753,20],[1,46,91,19.999,30],[0,46,0,20.249,30],[1,46,84,20.5,30],[0,46,0,20.75,30],[1,36,114,20.998,0],[1,46,107,20.999,30],[0,36,0,21.248,0],[0,46,0,21.249,30],[1,46,85,21.502,20],[1,36,98,21.74,0],[0,46,0,21.752,20],[0,36,0,21.99,0],[1,46,85,22.003,30],[0,46,0,22.253,30],[1,36,114,22.497,0],[1,46,86,22.5,20],[0,36,0,22.747,0],[0,46,0,22.75,20],[1,46,113,22.992,30],[1,38,120,23,0],[0,46,0,23.242,30],[0,38,64,23.25,0],[1,46,85,23.502,30],[0,46,0,23.752,30],[1,46,91,24.002,30],[1,36,99,24.241,0],[0,46,0,24.252,30],[0,36,0,24.491,0],[1,38,120,24.496,0],[1,46,113,24.502,30],[0,38,64,24.746,0],[0,46,0,24.752,30],[1,36,114,24.996,0],[1,46,107,24.996,30],[0,46,0,25.246,30],[0,36,0,25.246,0],[1,46,89,25.498,20],[1,36,102,25.743,0],[0,46,0,25.748,20],[0,36,0,25.993,0],[1,46,91,25.999,30],[0,46,0,26.249,30],[1,36,114,26.49,0],[1,46,88,26.503,20],[0,36,0,26.74,0],[0,46,0,26.753,20],[1,46,113,26.994,30],[1,38,120,27.001,0],[0,46,0,27.244,30],[0,38,64,27.251,0],[1,46,89,27.5,30],[0,46,0,27.75,30],[1,46,93,28,30],[0,46,0,28.25,30],[1,46,81,28.499,20],[0,46,0,28.749,20],[1,36,114,28.997,0],[1,46,107,29,30],[0,36,0,29.247,0],[0,46,0,29.25,30],[1,46,86,29.505,30],[1,36,105,29.741,0],[0,46,0,29.755,30],[0,36,0,29.991,0],[1,46,94,30,30],[0,46,0,30.25,30],[1,36,114,30.498,0],[1,46,86,30.501,30],[0,36,0,30.748,0],[0,46,0,30.751,30],[1,46,113,30.997,30],[1,38,120,30.998,0],[0,46,0,31.247,30],[0,38,64,31.248,0],[1,36,102,31.492,0],[1,46,86,31.503,30],[0,36,64,31.742,0],[0,46,0,31.753,30],[1,47,99,31.992,0],[1,33,110,31.994,0],[1,40,110,32.008,0],[0,47,64,32.241,0],[0,33,64,32.244,0],[0,40,64,32.258,0],[1,36,86,32.494,0],[0,36,64,32.744,0]]], ['Black Veil',[[1,36,118,0.994,0],[1,33,39,0.998,0],[1,57,118,1.002,0],[0,36,0,1.244,0],[0,33,64,1.248,0],[0,57,0,1.252,0],[1,45,72,1.497,0],[1,33,13,1.501,0],[1,36,87,1.738,0],[0,45,0,1.747,0],[0,33,64,1.751,0],[0,36,0,1.987,0],[1,45,86,1.999,0],[1,33,39,2.001,0],[1,38,123,2.003,0],[0,45,0,2.249,0],[0,33,64,2.252,0],[0,38,0,2.253,0],[1,45,72,2.501,0],[1,33,7,2.502,0],[1,36,62,2.748,0],[0,45,0,2.751,0],[0,33,64,2.752,0],[1,33,41,2.993,0],[1,36,118,2.995,0],[0,36,0,2.995,0],[1,45,88,2.996,0],[0,33,64,3.243,0],[0,36,0,3.245,0],[0,45,0,3.246,0],[1,45,73,3.498,0],[1,33,13,3.503,0],[0,45,0,3.748,0],[0,33,64,3.753,0],[1,45,85,3.999,0],[1,33,36,4.002,0],[1,38,123,4.003,0],[0,45,0,4.249,0],[0,33,64,4.252,0],[0,38,0,4.253,0],[1,45,72,4.502,0],[1,33,7,4.504,0],[0,45,0,4.752,0],[0,33,64,4.754,0],[1,36,118,4.997,0],[1,33,40,5.003,0],[1,45,80,5.003,0],[0,36,0,5.247,0],[0,45,0,5.253,0],[0,33,64,5.253,0],[1,45,74,5.502,0],[1,33,11,5.504,0],[1,36,92,5.738,0],[0,45,0,5.752,0],[0,33,64,5.754,0],[0,36,0,5.988,0],[1,45,84,6,0],[1,33,35,6.001,0],[1,38,123,6.002,0],[1,36,88,6.242,0],[0,45,0,6.25,0],[0,33,64,6.251,0],[0,38,0,6.252,0],[0,36,0,6.492,0],[1,33,8,6.498,0],[1,45,72,6.501,0],[1,36,61,6.741,0],[0,33,64,6.748,0],[0,45,0,6.751,0],[0,36,0,6.991,0],[1,45,87,6.992,0],[1,33,41,6.996,0],[1,36,118,6.996,0],[0,45,0,7.242,0],[0,36,0,7.246,0],[0,33,64,7.246,0],[1,36,93,7.49,0],[1,45,81,7.499,0],[1,33,16,7.503,0],[0,36,0,7.74,0],[0,45,0,7.749,0],[0,33,64,7.753,0],[1,45,81,7.997,0],[1,33,34,8,0],[1,38,123,8,0],[0,45,0,8.247,0],[0,33,64,8.25,0],[0,38,0,8.251,0],[1,45,69,8.497,0],[1,33,16,8.503,0],[0,45,0,8.747,0],[0,33,64,8.753,0],[1,36,118,8.997,0],[1,33,40,9,0],[1,45,84,9.002,0],[0,36,0,9.247,0],[0,33,64,9.25,0],[0,45,0,9.252,0],[1,45,76,9.495,0],[1,33,5,9.497,0],[0,45,0,9.745,0],[0,33,64,9.747,0],[1,38,123,9.998,0],[1,45,84,10,0],[1,33,33,10.001,0],[0,38,0,10.248,0],[0,45,0,10.25,0],[0,33,64,10.251,0],[1,45,73,10.495,0],[1,33,12,10.504,0],[1,36,62,10.742,0],[0,45,0,10.745,0],[0,33,64,10.754,0],[1,45,86,10.991,0],[0,36,0,10.992,0],[1,36,118,10.993,0],[1,33,35,10.998,0],[0,45,0,11.241,0],[0,36,0,11.243,0],[0,33,64,11.248,0],[1,45,77,11.497,0],[1,33,15,11.503,0],[0,45,0,11.747,0],[0,33,64,11.753,0],[1,45,82,11.997,0],[1,38,123,11.998,0],[1,33,36,12,0],[1,36,91,12.238,0],[0,45,0,12.247,0],[0,38,0,12.248,0],[0,33,64,12.25,0],[0,36,0,12.488,0],[1,45,71,12.494,0],[1,33,10,12.495,0],[0,45,0,12.744,0],[0,33,64,12.745,0],[1,36,118,12.995,0],[1,33,37,12.997,0],[1,45,82,13,0],[0,36,0,13.245,0],[0,33,64,13.247,0],[0,45,0,13.25,0],[1,33,12,13.495,0],[1,45,69,13.498,0],[1,36,85,13.738,0],[0,33,64,13.745,0],[0,45,0,13.748,0],[0,36,0,13.988,0],[1,45,86,13.995,0],[1,33,42,13.995,0],[1,38,123,14,0],[1,36,92,14.234,0],[0,45,0,14.245,0],[0,33,64,14.245,0],[0,38,0,14.25,0],[0,36,0,14.484,0],[1,45,70,14.493,0],[1,33,7,14.501,0],[0,45,0,14.743,0],[1,36,63,14.743,0],[0,33,64,14.751,0],[1,45,82,14.99,0],[0,36,0,14.993,0],[1,33,43,14.995,0],[1,36,118,14.995,0],[0,45,0,15.24,0],[0,36,0,15.245,0],[0,33,64,15.245,0],[1,36,93,15.491,0],[1,33,15,15.498,0],[1,45,89,15.498,0],[0,36,0,15.741,0],[0,33,64,15.748,0],[0,45,0,15.748,0],[1,47,116,15.993,0],[1,45,86,15.995,0],[1,33,41,15.997,0],[1,36,85,16.241,0],[0,47,64,16.243,0],[0,45,0,16.245,0],[0,33,64,16.247,0],[0,36,64,16.361,0],[1,36,99,16.363,0],[1,47,116,16.496,0],[1,45,77,16.497,0],[1,33,6,16.503,0],[0,36,64,16.612,0],[1,36,107,16.736,0],[0,47,64,16.746,0],[0,45,0,16.747,0],[0,33,64,16.753,0],[0,36,64,16.986,0],[1,36,118,16.995,0],[1,33,32,16.996,0],[1,57,118,16.999,0],[0,36,0,17.245,0],[0,33,64,17.246,0],[0,57,0,17.249,0],[1,45,74,17.494,0],[1,33,7,17.502,0],[0,45,0,17.744,0],[1,36,84,17.745,0],[0,33,64,17.752,0],[0,36,0,17.995,0],[1,45,86,17.996,0],[1,38,123,18,0],[1,33,38,18.001,0],[0,45,0,18.246,0],[0,38,0,18.25,0],[0,33,64,18.251,0],[1,33,10,18.499,0],[1,45,78,18.5,0],[1,36,57,18.741,0],[0,33,64,18.749,0],[0,45,0,18.75,0],[0,36,0,18.991,0],[1,36,118,18.994,0],[1,33,43,18.995,0],[1,45,85,19,0],[0,36,0,19.244,0],[0,33,64,19.245,0],[0,45,0,19.25,0],[1,45,75,19.499,0],[1,33,5,19.503,0],[0,45,0,19.749,0],[0,33,64,19.753,0],[1,33,42,19.999,0],[1,45,86,19.999,0],[1,38,123,20.003,0],[0,45,0,20.249,0],[0,33,64,20.249,0],[0,38,0,20.253,0],[1,45,77,20.501,0],[1,33,12,20.505,0],[0,45,0,20.751,0],[0,33,64,20.755,0],[1,33,32,20.994,0],[1,45,81,20.994,0],[1,36,118,20.998,0],[0,45,0,21.244,0],[0,33,64,21.244,0],[0,36,0,21.248,0],[1,45,70,21.499,0],[1,33,8,21.502,0],[1,36,88,21.748,0],[0,45,0,21.749,0],[0,33,64,21.752,0],[0,36,0,21.998,0],[1,33,43,21.999,0],[1,45,88,21.999,0],[1,38,123,22.003,0],[0,45,0,22.249,0],[0,33,64,22.249,0],[0,38,0,22.253,0],[1,33,14,22.498,0],[1,45,72,22.501,0],[1,36,59,22.747,0],[0,33,64,22.748,0],[0,45,0,22.751,0],[1,45,89,22.992,0],[0,36,0,22.994,0],[1,36,118,22.994,0],[1,33,36,23.001,0],[0,45,0,23.242,0],[0,36,0,23.244,0],[0,33,64,23.251,0],[1,36,93,23.493,0],[1,45,79,23.496,0],[1,33,15,23.505,0],[0,36,0,23.743,0],[0,45,0,23.746,0],[0,33,64,23.755,0],[1,33,33,23.999,0],[1,45,89,23.999,0],[1,38,123,24.003,0],[1,36,91,24.24,0],[0,45,0,24.249,0],[0,33,64,24.249,0],[0,38,0,24.253,0],[0,36,0,24.49,0],[1,45,77,24.494,0],[1,33,11,24.503,0],[0,45,0,24.744,0],[0,33,64,24.753,0],[1,33,41,24.996,0],[1,45,80,24.996,0],[1,36,118,24.998,0],[0,45,0,25.246,0],[0,33,64,25.246,0],[0,36,0,25.248,0],[1,33,11,25.498,0],[1,45,74,25.499,0],[1,36,86,25.745,0],[0,33,64,25.748,0],[0,45,0,25.749,0],[0,36,0,25.995,0],[1,38,123,26,0],[1,45,88,26.001,0],[1,33,41,26.002,0],[0,38,0,26.25,0],[0,45,0,26.251,0],[0,33,64,26.252,0],[1,33,8,26.498,0],[1,45,71,26.499,0],[1,36,56,26.737,0],[0,33,64,26.748,0],[0,45,0,26.749,0],[0,36,0,26.988,0],[1,33,35,26.994,0],[1,36,118,26.994,0],[1,45,89,27.001,0],[0,36,0,27.244,0],[0,33,64,27.244,0],[0,45,0,27.251,0],[1,45,71,27.495,0],[1,33,13,27.505,0],[0,45,0,27.745,0],[0,33,64,27.755,0],[1,45,87,28.001,0],[1,33,41,28.002,0],[1,38,123,28.003,0],[0,45,0,28.251,0],[0,33,64,28.252,0],[0,38,0,28.253,0],[1,45,77,28.499,0],[1,33,8,28.501,0],[0,45,0,28.749,0],[0,33,64,28.751,0],[1,36,118,28.994,0],[1,45,84,28.999,0],[1,33,43,29.002,0],[1,36,80,29.243,0],[0,36,0,29.243,0],[0,45,0,29.249,0],[0,33,64,29.252,0],[0,36,0,29.493,0],[1,45,70,29.495,0],[1,33,13,29.501,0],[1,36,86,29.742,0],[0,45,0,29.745,0],[0,33,64,29.751,0],[0,36,0,29.992,0],[1,45,87,30,0],[1,38,123,30.001,0],[1,33,35,30.002,0],[0,45,0,30.25,0],[0,38,0,30.251,0],[0,33,64,30.252,0],[1,45,77,30.497,0],[1,33,14,30.498,0],[1,36,58,30.745,0],[0,45,0,30.747,0],[0,33,64,30.748,0],[0,36,0,30.995,0],[1,40,116,31.015,0],[1,40,116,31.232,0],[0,40,64,31.233,0],[0,40,64,31.482,0],[1,38,104,31.498,0],[1,38,48,31.744,0],[0,38,64,31.744,0],[0,38,64,31.994,0],[1,40,116,31.999,0],[1,38,104,32.244,0],[0,40,64,32.248,0],[0,38,64,32.494,0],[1,38,114,32.498,0],[1,38,104,32.741,0],[0,38,64,32.741,0],[0,38,64,32.992,0]]], ['Crimson',[[1,49,117,0.999,0],[1,36,116,1,0],[0,49,0,1.249,0],[0,36,0,1.25,0],[1,57,76,1.507,0],[0,57,0,1.757,0],[1,57,93,2.005,0],[1,38,122,2.008,0],[0,57,0,2.255,0],[0,38,0,2.258,0],[1,57,83,2.51,0],[1,36,94,2.745,0],[0,57,0,2.76,0],[0,36,0,2.995,0],[1,57,78,3.006,0],[1,36,74,3.251,0],[0,57,0,3.256,0],[0,36,0,3.499,0],[1,36,116,3.499,0],[1,57,89,3.507,0],[0,36,0,3.749,0],[0,57,0,3.757,0],[1,57,99,4.006,0],[1,38,122,4.011,0],[0,57,0,4.257,0],[0,38,0,4.261,0],[1,57,74,4.511,0],[0,57,0,4.761,0],[1,36,116,5.001,0],[1,57,94,5.006,0],[0,36,0,5.251,0],[0,57,0,5.256,0],[1,57,65,5.513,0],[1,36,99,5.744,0],[0,57,0,5.763,0],[0,36,0,5.994,0],[1,57,91,6.006,0],[1,38,122,6.008,0],[0,57,0,6.256,0],[0,38,0,6.258,0],[1,57,76,6.505,0],[1,36,95,6.752,0],[0,57,0,6.755,0],[0,36,0,7.002,0],[1,57,79,7.004,0],[0,57,0,7.254,0],[1,36,116,7.499,0],[1,57,78,7.511,0],[0,36,0,7.749,0],[0,57,0,7.761,0],[1,38,122,8.007,0],[1,57,88,8.007,0],[1,36,96,8.245,0],[0,57,0,8.257,0],[0,38,0,8.257,0],[0,36,0,8.495,0],[1,36,115,8.498,0],[1,57,80,8.506,0],[0,36,0,8.748,0],[0,57,0,8.756,0],[1,57,93,8.997,0],[1,36,116,9.001,0],[0,57,0,9.247,0],[0,36,0,9.251,0],[1,57,75,9.505,0],[0,57,0,9.755,0],[1,38,122,10.005,0],[1,57,105,10.008,0],[0,38,0,10.255,0],[0,57,0,10.258,0],[1,57,76,10.505,0],[1,36,97,10.748,0],[0,57,0,10.755,0],[0,36,0,10.998,0],[1,57,80,11,0],[0,57,0,11.25,0],[1,36,116,11.495,0],[1,57,82,11.506,0],[0,36,0,11.745,0],[0,57,0,11.756,0],[1,57,98,12.005,0],[1,38,122,12.008,0],[1,36,98,12.243,0],[0,57,0,12.255,0],[0,38,0,12.258,0],[0,36,0,12.493,0],[1,57,80,12.507,0],[0,57,0,12.757,0],[1,36,116,12.998,0],[1,57,93,13.006,0],[0,36,0,13.248,0],[0,57,0,13.256,0],[1,57,74,13.507,0],[1,36,92,13.743,0],[0,57,0,13.757,0],[0,36,0,13.993,0],[1,38,122,14.003,0],[1,57,90,14.004,0],[0,38,0,14.253,0],[0,57,0,14.254,0],[1,57,75,14.505,0],[1,36,99,14.748,0],[0,57,0,14.755,0],[0,36,0,14.998,0],[1,57,84,15.003,0],[1,36,75,15.248,0],[0,57,0,15.253,0],[0,36,0,15.498,0],[1,36,116,15.498,0],[1,57,81,15.507,0],[0,36,0,15.748,0],[0,57,0,15.757,0],[1,57,89,16.007,0],[1,38,122,16.008,0],[1,36,94,16.243,0],[0,57,0,16.257,0],[0,38,0,16.258,0],[1,48,111,16.478,0],[0,36,0,16.493,0],[1,45,118,16.51,0],[0,48,64,16.728,0],[0,45,64,16.751,0],[1,45,112,16.751,0],[1,49,117,17,0],[0,45,64,17.001,0],[1,36,116,17.002,0],[0,49,0,17.25,0],[0,36,0,17.252,0],[1,57,86,17.505,0],[0,57,0,17.755,0],[1,57,104,18.004,0],[1,38,122,18.009,0],[0,57,0,18.254,0],[0,38,0,18.259,0],[1,57,76,18.507,0],[1,36,91,18.754,0],[0,57,0,18.757,0],[1,57,81,19.003,0],[0,36,0,19.004,0],[0,57,0,19.253,0],[1,36,116,19.499,0],[1,57,96,19.504,0],[0,36,0,19.749,0],[0,57,0,19.754,0],[1,57,102,20.007,0],[1,38,122,20.008,0],[1,36,92,20.251,0],[0,57,0,20.257,0],[0,38,0,20.258,0],[0,36,0,20.501,0],[1,57,68,20.511,0],[0,57,0,20.761,0],[1,36,116,21.002,0],[1,57,99,21.007,0],[0,36,0,21.252,0],[0,57,0,21.257,0],[1,57,84,21.513,0],[1,36,95,21.747,0],[0,57,0,21.763,0],[0,36,0,21.997,0],[1,38,122,22.006,0],[1,57,100,22.009,0],[0,38,0,22.256,0],[0,57,0,22.259,0],[1,57,83,22.511,0],[1,36,94,22.752,0],[0,57,0,22.761,0],[0,36,0,23.002,0],[1,57,66,23.005,0],[1,36,75,23.245,0],[0,57,0,23.255,0],[0,36,0,23.495,0],[1,36,116,23.501,0],[1,57,85,23.508,0],[0,36,0,23.751,0],[0,57,0,23.758,0],[1,57,105,24.007,0],[1,38,122,24.01,0],[0,57,0,24.257,0],[0,38,0,24.26,0],[1,57,72,24.511,0],[0,57,0,24.761,0],[1,57,99,24.998,0],[1,36,116,25.004,0],[0,57,0,25.248,0],[0,36,0,25.254,0],[1,57,69,25.504,0],[1,36,93,25.751,0],[0,57,0,25.754,0],[0,36,0,26.001,0],[1,57,91,26.005,0],[1,38,122,26.006,0],[0,57,0,26.255,0],[0,38,0,26.256,0],[1,57,79,26.509,0],[1,36,91,26.75,0],[0,57,0,26.759,0],[0,36,0,27,0],[1,57,81,27.005,0],[0,57,0,27.255,0],[1,36,116,27.499,0],[1,57,97,27.504,0],[0,36,0,27.749,0],[0,57,0,27.754,0],[1,57,88,28.007,0],[1,38,122,28.009,0],[0,57,0,28.257,0],[0,38,0,28.259,0],[1,57,78,28.507,0],[0,57,0,28.757,0],[1,36,116,29.003,0],[1,57,101,29.007,0],[0,36,0,29.253,0],[0,57,0,29.257,0],[1,57,78,29.511,0],[1,36,96,29.75,0],[0,57,0,29.761,0],[0,36,0,30,0],[1,38,122,30.006,0],[1,57,89,30.008,0],[0,38,0,30.256,0],[0,57,0,30.258,0],[1,57,73,30.506,0],[1,36,93,30.755,0],[0,57,0,30.756,0],[1,57,83,30.998,0],[0,36,0,31.005,0],[1,36,70,31.246,0],[0,57,0,31.248,0],[1,48,104,31.484,0],[0,36,0,31.496,0],[1,47,102,31.521,0],[0,48,64,31.734,0],[1,36,112,31.748,0],[0,47,64,31.771,0],[0,36,64,31.998,0],[1,36,112,32.252,0],[1,47,98,32.461,0],[0,36,64,32.502,0],[1,43,107,32.518,0],[0,47,64,32.711,0],[0,43,64,32.768,0]]] ]; var riffData = riffs[0][1]; var NeedsTimingInfo = true; var ResetParameterDefaults = true; function ParameterChanged(index, value) { var name = PluginParameters[index].name; Trace("parameterChanged($index:"+index+" ["+name+"], $value:"+value+")"); if (name == 'Riff') { setRiff(value); } } function setRiff(riff) { Trace("Riff Changed To: "+riff+": "+riffs[riff][0]); riffData = riffs[riff][1]; MIDI.allNotesOff(); } function ProcessMIDI() { var musicInfo = GetTimingInfo(); if (musicInfo.playing) { var blockStartBeat = musicInfo.blockStartBeat; var blockEndBeat = musicInfo.blockEndBeat; var riffStart = blockStartBeat - (blockStartBeat % 32); var length = riffData.length; var i = 0; for (i; i < length; i++) { var data = riffData[i]; var pos = data[3] + riffStart; // its before the process block if (pos < blockStartBeat) { continue; } // its after the process block if (pos > blockEndBeat) { break; } //Trace("["+data[0]+","+data[1]+","+data[2]+","+data[3]+","+data[4]+"] "); if (data[0] == 1) { note = new NoteOn(); } else { note = new NoteOff(); } note.pitch = data[1]; note.velocity = data[2]; note.articulationID = data[4]; note.sendAtBeat(pos); // no more riff events but might still be processing so begin next riff if (i + 1 >= length) { riffStart+= 32; i = 0; } } } } //define the UI ----------------------------------------------------------------- var PluginParameters = []; // add select riff control PluginParameters.push( { name: "Riff", type: "menu", valueStrings: [ riffs[0][0], riffs[1][0] ], defaultValue: 0 }); The scripter plugin was loaded on a drum kit software instrument channel and works great for the most part. I've traced each beat with another scripter plugin and all the notes have been logged, so i assume they've all been sent properly. All the notes should be there but they just can't be heard. I've tried all kinds of things, i'm stuck!
How to wait for place ship click event to complete before calling next place ship function in JavaScript Battleship game loop
Problem: I call playerPlaceShip (from a DOM interaction module) inside a game loop module. This lets the user hover the board, click to place the ship, and finally in the event handler call board.placeShip() (from the gameBoard module). This works in isolation, but when I add another playerPlaceShip call to place an additional ship, it executes immediately before the first ship can be placed by clicking. Desired outcome: A way to wait until the click event from the first function call completes before the next function call begins. What I've tried: Hours of unsuccessfully trying to write and use promises. Hours of reading about promises. Spent a lot of time unsuccessfully trying to rethink how the code is structured. It seems like the click event should be driving the next action, but I don't see how to do that without writing more and more function calls inside the click event handler, which would seem to take control of the game flow away from the game loop module and put it in the DOM interaction module. Full modules on GitHub: https://github.com/Pete-Fowler/battleship/tree/player-place-ships/src/modules Code excerpts: // In game loop module after creating ships, players, and board objects: // Render Board renderBoard(p1Board, p1Box); renderBoard(p2Board, p2Box); // Player place ships - lets user hover and click board to place playerPlaceShip(p1Board, p1Carrier); playerPlaceShip(p1Board, p1Battleship); // this gets called too soon before click event from the first call completes // In DOM module: const clickToPlace = (e, board, ship) => { let { x, y } = e.target.dataset; x = parseInt(x, 10); y = parseInt(y, 10) board.place(ship, x, y, axis); renderShadow(e, 'place', ship.length); removeListeners(); } // Main function for player to place ship const playerPlaceShip = (board, ship) => { const squares = document.querySelectorAll('#p1 .board .square'); narrative.textContent = `Lead your ${ship.type} into battle. Press X to steer.`; squares.forEach(square => { square.addEventListener('mouseover', (e) => renderShadow(e, 'fill', ship.length)); square.addEventListener('mouseout', (e) => renderShadow(e, 'clear', ship.length)); square.addEventListener('click', (e) => clickToPlace(e, board, ship)); }); window.addEventListener('keydown', (e) => { if(e.key === 'x') { switchAxis(); squares.forEach(square => square.classList.remove('hovered')); renderShadow(lastCoords, 'fill', ship.length); } }); } Thanks!
I wasn't able to checkout the branch, got a strange error: invalid path 'src/images/background.jpg:Zone.Identifier', maybe because of the colon : after jpg. So I downloaded the zip. Otherwise I would have done a pull request, that would be easier for you to merge. I added logic so that the ship is always inside the board, and created a custom event to trigger after place ship. There are comments, see if this will help you move on. game.js import gameBoard from "./gameBoard"; import player from "./player"; import makeShip from "./ship"; import { p1Box, p2Box, playerPlaceShip, placeShipEventName, AIPlaceShip, renderBoard, UIAttack } from "./DOM"; const startingShipCount = 5; // SETUP // Make game boards const p1Board = gameBoard(); p1Board.init(); const p2Board = gameBoard(); p2Board.init(); // Make players const p1 = player("Gustav", p1Board, "human"); const p2 = player("Terminator", p2Board, "AI"); // Make p1 ships const p1Ptb = makeShip("patrolBoat"); const p1Sub = makeShip("sub"); const p1Destroyer = makeShip("destroyer"); const p1Battleship = makeShip("battleship"); const p1Carrier = makeShip("carrier"); // Make AI ships const p2Ptb = makeShip("patrolBoat"); const p2Sub = makeShip("sub"); const p2Destroyer = makeShip("destroyer"); const p2Battleship = makeShip("battleship"); const p2Carrier = makeShip("carrier"); // Render Board renderBoard(p1Board, p1Box); renderBoard(p2Board, p2Box); // AI place ships p2Board.place(p2Ptb, 0, 1, "y"); p2Board.place(p2Sub, 2, 6, "y"); p2Board.place(p2Destroyer, 4, 2, "y"); p2Board.place(p2Battleship, 6, 6, "y"); p2Board.place(p2Carrier, 8, 4, "y"); renderBoard(p1Board, p1Box); renderBoard(p2Board, p2Box); //################################################ //###################### HANDLE placeShipPhase //################################################ let countShipsPlaced = 0; const handlePlaceShipPhase = () => { countShipsPlaced++; if (countShipsPlaced == startingShipCount) { startGame(); } else { playerPlaceShip(p1Board, p1Carrier); } }; //###################################################### //####### LISTENING to the custom event Place Ship //###################################################### window.addEventListener(placeShipEventName, handlePlaceShipPhase); // Player places ships playerPlaceShip(p1Board, p1Carrier); const startGame = () => { alert("Game started, battle!"); }; // MAIN GAME LOOP - will need loop // Player attack // UIAttack(p2Board); // AI attack // Gameover - after exit loop // The game loop should set up a new game by creating Players and Gameboards. // For now just populate each Gameboard with predetermined coordinates. You can // implement a system for allowing players to place their ships later. // The game loop should step through the game turn by turn using only methods // from other objects. If at any point you are tempted to write a new function // inside the game loop, step back and figure out which class or module that // function should belong to. // Create conditions so that the game ends once one players ships have all // been sunk. This function is appropriate for the Game module. DOM.js /* eslint-disable no-unused-expressions */ const p1Box = document.querySelector("#p1"); const p2Box = document.querySelector("#p2"); const narrative = document.querySelector("#narrative"); let axis = "y"; // used to render shadow in playerPlaceShip let selectedSquares = []; let lastCoords; const boardSize = 10; //save the current ship to be used in the "x" key event listender let currentShip; //moved outside of the placeship otherwise will add duplicated events window.addEventListener("keydown", (e) => { if (e.key.toLocaleLowerCase() === "x") { const squares = document.querySelectorAll("#p1 .board .square"); switchAxis(); squares.forEach((square) => square.classList.remove("hovered")); renderShadow(lastCoords, "fill", currentShip.length); } }); //############################################# //##### CREATING the custom event Place Ship //############################################# const placeShipEventName = "playerplaceship"; const placeShipEvent = new Event(placeShipEventName); // Helper functions for playerPlaceShip const switchAxis = () => { axis === "x" ? (axis = "y") : (axis = "x"); }; const renderShadow = (e, fill, length) => { let { x, y } = e.target.dataset; x = parseInt(x, 10); y = parseInt(y, 10); selectedSquares = []; let count = countOfSquaresOutOfBoard(x, y, length); //#### LOGIC TO RENDER SHIP ALWAYS INSIDE BOARD for (let i = -count; i < length - count; i++) { setSelectedSquares(x, y, i); } for (const el of selectedSquares) { fill === "fill" ? el.classList.add("hovered") : el.classList.remove("hovered"); if (fill === "place") { el.classList.add("placed"); } } lastCoords = e; }; const removeListeners = () => { const squares = document.querySelectorAll("#p1 .board .square"); squares.forEach((square) => { square.replaceWith(square.cloneNode()); }); }; const clickToPlace = (shipSquare, board, ship) => { let { x, y } = shipSquare.dataset; x = parseInt(x, 10); y = parseInt(y, 10); board.place(ship, x, y, axis); renderShadow(lastCoords, "place", ship.length); removeListeners(); //####################################################### //############# TRIGGERING the custom event place ship //######################################################### window.dispatchEvent(placeShipEvent); console.log(board.getMap()); }; // Main function for player to place ship const playerPlaceShip = (board, ship) => { currentShip = ship; const squares = document.querySelectorAll("#p1 .board .square"); narrative.textContent = `Lead your ${ship.type} into battle. Press X to steer.`; squares.forEach((square) => { square.addEventListener("mouseover", (e) => renderShadow(e, "fill", ship.length)); square.addEventListener("mouseout", (e) => renderShadow(e, "clear", ship.length)); square.addEventListener("click", (e) => clickToPlace(selectedSquares[0], board, ship)); }); }; const countOfSquaresOutOfBoard = (x, y, length) => { let count = 0; if (axis === "x") { count = x + length - boardSize; } if (axis === "y") { count = y + length - boardSize; } return count < 0 ? 0 : count; }; const setSelectedSquares = (x, y, i) => { if (axis === "x") { selectedSquares.push(document.querySelector(`#p1 .square[data-x="${x + i}"][data-y="${y}"]`)); } else { selectedSquares.push(document.querySelector(`#p1 .square[data-x="${x}"][data-y="${y + i}"]`)); } }; // Lets AI place ship const AIPlaceShip = (board) => {}; const renderBoard = (board, box) => { // Clear old content prior to re-render if needed let grid = document.querySelector(`#${box.id} .board`); if (grid) { grid.textContent = ""; } else { grid = document.createElement("div"); grid.className = "board"; } // Individual squares on board for (let i = 0; i <= 9; i += 1) { for (let j = 9; j >= 0; j -= 1) { const square = document.createElement("div"); square.className = "square"; square.dataset.x = i; square.dataset.y = j; grid.append(square); } } box.append(grid); }; // Player attack phase - sends x, y from clicked square to board.incoming() const attackCallback = (e, board) => { const { x, y } = e.target.dataset; board.incoming(x, y); const squares = document.querySelectorAll("#p2 .square"); squares.forEach((el) => { el.removeEventListener("click", attackCallback); el.classList.remove("hoverable"); }); console.log(board.getMap()); }; // Player attack phase - adds click event listener and hover effect const UIAttack = (board) => { const squares = document.querySelectorAll("#p2 .square"); squares.forEach((el) => { el.addEventListener("click", (e) => attackCallback(e, board)); el.classList.add("hoverable"); }); narrative.textContent = "Click to fire on the enemy fleet"; }; export { p1Box, p2Box, placeShipEventName, playerPlaceShip, AIPlaceShip, renderBoard, UIAttack };
Guessing game using random number. How to get new number without refreshing the page?
Im relativly new to js so im making a gueessing game from 1 to 100 using Math.random to get my random number. I have a play again button that clears all previous guesses from a previous round but when you click it the random number does not change so the next rounds number is the same I tried stating random again in the play again function but it did not work and I also tried putting the variable in the function but then it changed upon every guess the user inputed let random = Math.floor(Math.random() * 101) console.log(random) const guess = document.querySelector('.guess') const button = document.querySelector('.submit') const myForm = document.querySelector('.myForm') let numguesses = 0 myForm.addEventListener('submit', click) function click(e) { e.preventDefault(); const ul = document.querySelector('.guesses') if(guess.value > 100 || guess.value < 0 || isNaN(guess.value)) { alert("please a enter number between 0 to 100") } else { numguesses++; if(random != guess.value) { if(guess.value > random) { const eachguess = document.createElement('li') eachguess.innerText= `${guess.value} was too High` eachguess.classList.add('wrong') ul.append(eachguess) guess.value = ''; } else { const eachguess = document.createElement('li') eachguess.innerText = `${guess.value} was too Low` eachguess.classList.add('low') ul.append(eachguess) guess.value = ''; } } else { const eachguess = document.createElement('li') eachguess.innerText = `Well done you gueesed Correctly the number was ${random} it took ${numguesses} guesses` eachguess.classList.add('correct') ul.append(eachguess) guess.value = '' return } } } const PlayAgain = document.querySelector('#playAgain') PlayAgain.addEventListener('click', Play) function Play() { const ul = document.querySelector('.guesses') while (ul.firstChild) { ul.removeChild(ul.firstChild) numguesses = 0 } }
You can assign a new value within the Play function: let random; // ... function Play() { const ul = document.querySelector('.guesses') while (ul.firstChild) { ul.removeChild(ul.firstChild) } numguesses = 0 random = Math.floor(Math.random() * 101) // <------ console.log(random) } You must not add the let keyword here as that would declare the random variable locally within the Play function - but in your case you want to re-assign the existing variable from the outer scope).
THREE.js - Updating BufferGeometry position twice, causes my FPS to suffer
I have an array of TubeBufferGeometrys that im making animate to look as if they're growing out in length. When the animation runs the first time, it works really smoothly at 60fps. But once i set the geometrys position attributes back to zero, the FPS drop to 30. Ive isolated my animation to run and then rerun once it finished with only the below changing. Heres the basics of my code: Animation control view stop() { this.play = false; // Start it again setTimeout(() => { let i = this.tubeCount; while (i--) { this.tubes[i].lastSegmentSet = 0; this.tubes[i].updateToPercent(0); } this.elapsedTime = 0; this.startTime = Date.now(); this.play = true; }, 2000) } update() { requestAnimationFrame(this.animate); // ..render stuff + composer that ive disabled without effect if (this.play) { let percent = (Date.now() - this.startTime) / ANIMATE_DURATION; if (percent >= 1) { this.stop(); } let i = this.lineCount; while (i--) { this.tubes[i].updateToPercent(percent); } } } Tube class (The main animation code) constructor() { //..other stuff this.lastSegmentSet = 0; } // I first build the paths, then store the position data to use later to animate to. Then i set all the position data to zero storeVerticies() { this.positions = this.tube.geometry.attributes.position.array.slice(0); const length = this.tube.geometry.attributes.position.array.length; this.tube.geometry.attributes.position.array = new Float32Array(length); } setSegment(segment) { this.setSegmentTo(segment, segment); } setSegmentTo(segment, target) { let position = this.tube.geometry.attributes.position.array; let startPoint = segment * JOINT_DATA_LENGTH; //JOINT_DATA_LENGTH is the number of values in the buffer geometry to update a segment let targetPoint = target * JOINT_DATA_LENGTH; let n = JOINT_DATA_LENGTH; while (n--) { position[startPoint + n] = this.positions[targetPoint + n]; } } updateToPercent(percent) { let endSegment = Math.floor(percent * this.segmentCount); while (this.lastSegmentSet <= endSegment) { this.setSegment(this.lastSegmentSet++); } let n = this.lastSegmentSet; while (n <= this.segmentCount + 1) { this.setSegmentTo(n++, this.lastSegmentSet); } this.tube.geometry.attributes.position.needsUpdate = true; } Will put bounty when possible
Javascript for loop doesn't work (adding numbers to a total)
I am using Jasmine for JS testing, and unfortunately I can't get the following test to pass. it('should know the total game score', function() { frame1 = new Frame; frame2 = new Frame; game = new Game; frame1.score(3, 4); frame2.score(5, 5); expect(game.totalScore()).toEqual(17) }); The error message I get is as follows: Error: Expected 0 to equal 17. The code is as follows: function Game() { this.scorecard = [] }; Game.prototype.add = function(frame) { this.scorecard.push(frame) }; // Why is this not working!!??? Game.prototype.totalScore = function() { total = 0; for(i = 0; i < this.scorecard.length; i++) { total +=this.scorecard[i].rollOne + this.scorecard[i].rollTwo; } return total; }; function Frame() {}; Frame.prototype.score = function(first_roll, second_roll) { this.rollOne = first_roll; this.rollTwo = second_roll; return this }; Frame.prototype.isStrike = function() { return (this.rollOne === 10); }; Frame.prototype.isSpare = function() { return (this.rollOne + this.rollTwo === 10) && (this.rollOne !== 10) }; Adding the numbers together manually seems to work e.g. total = game.scorecard[0].rollOne + this.scorecard[0].rollTwo , but the for loop (even though it looks correct) doesn't seem to work. Any help would be greatly appreciated :)
I am not pretty sure, but it seems that you are not calling the "Add" method, so no data is added to the scorecard.
You have to add the Frames to your game i guess it('should know the total game score', function () { frame1 = new Frame; frame2 = new Frame; game = new Game; // those lines are missing game.add(frame1); game.add(frame2); frame1.score(3, 4); frame2.score(5, 5); expect(17).toEqual(game.totalScore()) }); otherwise, the scorecard-array is empty and the total score is therefore equal to 0.
missing (so no data is added to the scorecard.) game.Add(frame1); game.Add(frame2);