I am doing a rock, paper, scissors screensaver and i wanted to implement a counter, which shows you the current amount of each emoji but my implementation doesnt work. It only shows the amount what the user is typing at the beginning.
Here is my script part
const navbar = document.querySelector('#navbar');
const formContainer = document.querySelector('#form-container');
const emojiCountInput = document.querySelector('#emoji-count');
const startButton = document.querySelector('#start');
const emojisContainer = document.querySelector('#emojis');
const resetButton = document.querySelector('#reset');
const pauseButton = document.querySelector('#pause');
const playButton = document.querySelector('#play');
const scissorsCountElement = document.querySelector('#scissors-count');
const rockCountElement = document.querySelector('#rock-count');
const paperCountElement = document.querySelector('#paper-count');
let interval;
startButton.addEventListener('click', () => {
formContainer.classList.add('hidden');
emojisContainer.innerHTML = '';
const emojiCount = parseInt(emojiCountInput.value);
for (let i = 0; i < emojiCount; i++) {
emojisContainer.innerHTML += '<div class="emoji scissors">✂️</div>';
emojisContainer.innerHTML += '<div class="emoji rock">🪨</div>';
emojisContainer.innerHTML += '<div class="emoji paper">📄</div>';
}
const emojis = document.querySelectorAll('.emoji');
function moveEmojis() {
emojis.forEach(emoji => {
if (!emoji.x) emoji.x = Math.random() * window.innerWidth;
if (!emoji.y) emoji.y = Math.random() * (window.innerHeight - navbar.offsetHeight) + navbar.offsetHeight;
if (!emoji.vx) emoji.vx = Math.random() * 10 - 5;
if (!emoji.vy) emoji.vy = Math.random() * 10 - 5;
emoji.x += emoji.vx;
emoji.y += emoji.vy;
// abprallen vom Bild
if (emoji.x < 0 || emoji.x > window.innerWidth) emoji.vx = -emoji.vx;
if (emoji.y < navbar.offsetHeight || emoji.y > window.innerHeight) emoji.vy = -emoji.vy;
emoji.style.left = emoji.x + 'px';
emoji.style.top = emoji.y + 'px';
});
}
function checkCollision(emoji1, emoji2) {
const rect1 = emoji1.getBoundingClientRect();
const rect2 = emoji2.getBoundingClientRect();
return !(rect1.right < rect2.left ||
rect1.left > rect2.right ||
rect1.bottom < rect2.top ||
rect1.top > rect2.bottom);
}
function updateState(emoji1, emoji2) {
if (emoji1.textContent === '✂️' && emoji2.textContent === '📄') {
emoji2.textContent = '✂️';
} else if (emoji1.textContent === '📄' && emoji2.textContent === '✂️') {
emoji1.textContent = '✂️';
} else if (emoji1.textContent === '🪨' && emoji2.textContent === '✂️') {
emoji2.textContent = '🪨';
} else if (emoji1.textContent === '✂️' && emoji2.textContent === '🪨') {
emoji1.textContent = '🪨';
} else if (emoji1.textContent === '📄' && emoji2.textContent === '🪨') {
emoji2.textContent = '📄';
} else if (emoji1.textContent === '🪨' && emoji2.textContent === '📄') {
emoji1.textContent = '📄';
}
}
function updateCounters() {
const scissorsCount = document.querySelectorAll('.scissors').length;
const rockCount = document.querySelectorAll('.rock').length;
const paperCount = document.querySelectorAll('.paper').length;
scissorsCountElement.textContent = scissorsCount;
rockCountElement.textContent = rockCount;
paperCountElement.textContent = paperCount;
}
function resetEmojis() {
emojis.forEach(emoji => {
delete emoji.x;
delete emoji.y;
delete emoji.vx;
delete emoji.vy;
delete emoji.locked;
});
}
resetButton.addEventListener('click', () => {
formContainer.classList.remove('hidden');
emojisContainer.innerHTML = '';
clearInterval(interval);
});
pauseButton.addEventListener('click', () => {
clearInterval(interval);
});
playButton.addEventListener('click', () => {
interval = setInterval(() => {
moveEmojis();
for (let i = 0; i < emojis.length; i++) {
for (let j = i + 1; j < emojis.length; j++) {
if (checkCollision(emojis[i], emojis[j])) {
updateState(emojis[i], emojis[j]);
}
}
}
updateCounters();
}, 100);
});
internal = setInterval(() => {
moveEmojis();
for (let i = 0; i < emojis.length; i++) {
for (let j = i + 1; j < emojis.length; j++) {
if (checkCollision(emojis[i], emojis[j])) {
updateState(emojis[i], emojis[j]);
}
}
}
updateCounters();
}, 100);
});
function handleResize() {
const emojis = document.querySelectorAll('.emoji');
emojis.forEach(emoji => {
if (emoji.x > window.innerWidth) emoji.x = window.innerWidth;
if (emoji.y > window.innerHeight) emoji.y = window.innerHeight - navbar.offsetHeight;
});
}
window.addEventListener('resize', handleResize);
body {
background-color: black;
color: white;
font-family: 'Roboto', sans-serif;
}
.emoji {
position: absolute;
font-size: 24px;
}
#navbar {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 50px;
background-color: #8585ad;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
}
#form-container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
#form-container.hidden {
display: none;
}
#counters {
margin: auto;
}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital@1&display=swap" rel="stylesheet">
<div id="navbar">
<div>
<button id="reset">Reset</button>
<button id="pause">Pause</button>
<button id="play">Play</button>
</div>
<div id="counters">
<span>✂️ <span id="scissors-count">0</span></span>
<span>🪨 <span id="rock-count">0</span></span>
<span>📄 <span id="paper-count">0</span></span>
</div>
</div>
<div id="form-container">
<label for="emoji-count">Number of emoji:</label>
<input type="number" id="emoji-count" value="50">
<button id="start">Start</button>
</div>
<div id="emojis"></div>
You can also visit my github repo on that, to maybe see what I mean.
3
Answers
In your code, when a collisions happens, you set the text of the losing element (i.e. rock when rock and paper fight) to the emoji of the winning emoji.
What you do not do, is update the
class
of the losing element to theclass
of the winning element.This is important as you calculate the number of a specific emoji by getting the number of elements with a rock/paper/scissor
class
with the this chunk of code:See Remove CSS class from element with JavaScript (no jQuery) to remove a class (remove the losing class when an emoji loses), and see How to add a class to a given element? to add the class of the winning emoji to the losing emoji.
An alternative to calculating the number of elements with a given class name would be to just have 3 variables (one for each emoji type) which you increment of decrement when a collisions happens.
The problem here is you didn’t update your class name of the element. You were only updating the textContent.
Corrected Code:
Your problem is that in
updateCounters
you count your elements by their classes, but inupdateState
you only ever change thetextContent
of your elements but never their classes.So you need to also change the class of your element when you change their text content: