I need to make a high-score list for this Javascript game - javascript

I hope you can give me a hand with this. My idea is to show a list of high-scores after the game is finished for a Doodle Jump project (javascript). The high-scores are presented successfully as you will see in my code, but the presentation is poor. Hence, I want to show them in a blank page, if possible using the same html. I will leave my code for you to reproduce the issue and help me. I thought about some document command, but you tell me.
Thanks in advance.
document.addEventListener('DOMContentLoaded', () => {
const grid = document.querySelector('.grid')
const doodler = document.createElement('div')
const unMutedIcon = document.createElement('div')
let doodlerLeftSpace = 50
let startPoint = 150
let doodlerBottomSpace = startPoint
let isGameOver = false
let platformCount = 5
let platforms = []
let upTimerid
let downTimerId
let isJumping = true
let isGoingLeft = false
let isGoingRight = false
let leftTimerId
let rightTimerId
let score = 0
let context
let musicIsPlaying = false
let copyRightMessage = " DoodleJump version by Santiago Hernandez \n all rights reserved \n Copyright © "
const NO_OF_HIGH_SCORES = 10;
const HIGH_SCORES = 'highScores';
function createDoodler() {
grid.appendChild(doodler)
doodler.classList.add('doodler')
doodlerLeftSpace = platforms[0].left
doodler.style.left = doodlerLeftSpace + 'px'
doodler.style.bottom = doodlerBottomSpace + 'px'
}
function control(e) {
if (e.key === "ArrowLeft") {
moveLeft()
} else if (e.key === "ArrowRight") {
moveRight()
} else if (e.key === "ArrowUp") {
moveStraight()
}
}
class Platform {
constructor(newPlatBottom) {
this.bottom = newPlatBottom
this.left = Math.random() * 315
this.visual = document.createElement('div')
const visual = this.visual
visual.classList.add('platform')
visual.style.left = this.left + 'px'
visual.style.bottom = this.bottom + 'px'
grid.appendChild(visual)
}
}
function createPlatforms() {
for (let i = 0; i < platformCount; i++) {
let platGap = 600 / platformCount
let newPlatBottom = 100 + i * platGap
let newPlatform = new Platform(newPlatBottom)
platforms.push(newPlatform)
console.log(platforms)
}
}
function movePlatforms() {
if (doodlerBottomSpace > 200) {
platforms.forEach(platform => {
platform.bottom -= 4
let visual = platform.visual
visual.style.bottom = platform.bottom + 'px'
if (platform.bottom < 10) {
let firstPlatform = platforms[0].visual
firstPlatform.classList.remove('platform')
platforms.shift()
score++
console.log(score)
console.log(platforms)
let newPlatform = new Platform(600)
platforms.push(newPlatform)
}
})
}
}
function jump() {
clearInterval(downTimerId)
isJumping = true
upTimerId = setInterval(function() {
doodlerBottomSpace += 20
doodler.style.bottom = doodlerBottomSpace + 'px'
if (doodlerBottomSpace > startPoint + 200) {
fall()
}
}, 30)
}
function fall() {
clearInterval(upTimerId)
isJumping = false
downTimerId = setInterval(function() {
doodlerBottomSpace -= 5
doodler.style.bottom = doodlerBottomSpace + 'px'
if (doodlerBottomSpace <= 0) {
gameOver()
}
platforms.forEach(platform => {
if ((doodlerBottomSpace >= platform.bottom) &&
(doodlerBottomSpace <= platform.bottom + 15) &&
((doodlerLeftSpace + 60) >= platform.left) &&
(doodlerLeftSpace <= (platform.left + 85)) &&
!isJumping
) {
console.log('landed')
startPoint = doodlerBottomSpace
jump()
}
})
}, 30)
}
function moveLeft() {
if (isGoingRight) {
clearInterval(rightTimerId)
isGoingRight = false
}
isGoingLeft = true
leftTimerId = setInterval(function() {
if (doodlerLeftSpace >= 0) {
doodlerLeftSpace -= 5
doodler.style.left = doodlerLeftSpace + 'px'
} else moveRight()
}, 30)
}
function moveRight() {
if (isGoingLeft) {
clearInterval(leftTimerId)
isGoingLeft = false
}
isGoingRight = true
rightTimerId = setInterval(function() {
if (doodlerLeftSpace <= 340) {
doodlerLeftSpace += 5
doodler.style.left = doodlerLeftSpace + 'px'
} else moveLeft()
}, 30)
}
function moveStraight() {
isGoingRight = false
isGoingLeft = false
clearInterval(rightTimerId)
clearInterval(leftTimerId)
}
function gameOver() {
console.log('GAME OVER')
isGameOver = true
try {
context.pause()
while (grid.firstChild) {
grid.removeChild(grid.firstChild)
}
grid.innerHTML = score
clearInterval(upTimerId)
clearInterval(downTimerId)
clearInterval(leftTimerId)
clearInterval(rightTimerId)
} catch (err) {
console.log('there was an error at gameover')
while (grid.firstChild) {
grid.removeChild(grid.firstChild)
}
grid.innerHTML = score
clearInterval(upTimerId)
clearInterval(downTimerId)
clearInterval(leftTimerId)
clearInterval(rightTimerId)
}
checkHighScore()
}
function saveHighScore(score, highScores) {
const name = prompt('You got a highscore! Enter name:');
const newScore = {
score,
name
};
// 1. Add to list
highScores.push(newScore);
// 2. Sort the list
highScores.sort((a, b) => b.score - a.score);
// 3. Select new list
highScores.splice(NO_OF_HIGH_SCORES);
// 4. Save to local storage
localStorage.setItem(HIGH_SCORES, JSON.stringify(highScores));
};
function checkHighScore() {
const highScores = JSON.parse(localStorage.getItem(HIGH_SCORES)) ? ? [];
const lowestScore = highScores[NO_OF_HIGH_SCORES - 1] ? .score ? ? 0;
if (score > lowestScore) {
saveHighScore(score, highScores); // TODO
showHighScores(); // TODO
}
}
function showHighScores() {
const highScores = JSON.parse(localStorage.getItem(HIGH_SCORES)) ? ? [];
const highScoreList = document.getElementById('highScores');
highScoreList.innerHTML = highScores.map((score) =>
`<li>${score.score} - ${score.name}</li>`
);
}
function start() {
if (!isGameOver) {
createPlatforms()
createDoodler()
setInterval(movePlatforms, 30)
jump()
document.addEventListener('keyup', control)
}
}
document.addEventListener('keypressed', control)
//attach to buttom
start()
//event listener to play music
document.addEventListener('keypress', function(e) {
if (e.keyCode == 32 || e.code == "Space") {
musicIsPlaying = true
context = new Audio("Music_level1.wav");
context.play()
context.loop = true
}
}) //end of event listener
})
.grid {
width: 400px;
height: 600px;
background-color: yellow;
position: relative;
font-size: 200px;
text-align: center;
background-image: url(bluesky_level1.gif);
background-size: contain;
background-repeat: no-repeat;
background-size: 400px 600px;
margin-right: auto;
margin-left: auto;
}
.doodler {
width: 60px;
height: 85px;
position: absolute;
background-image: url(mariobros_level1.png);
background-size: contain;
background-repeat: no-repeat;
background-size: 60px 85px;
filter: brightness(1.1);
mix-blend-mode: multiply;
}
#audio {
display: none
}
.platform {
width: 85px;
height: 15px;
position: absolute;
background-image: url(platform_tramp_level1.png);
background-size: contain;
background-repeat: no-repeat;
background-size: 85px 15px;
}
.volumeIcon {
width: 30px;
height: 30px;
position: absolute;
top: 570px;
background-image: url(volumeIconMuted.png);
background-size: contain;
background-repeat: no-repeat;
background-size: 30px 30px;
}
.unmutedIcon {
width: 30px;
height: 30px;
position: absolute;
top: 570px;
background-image: url(VolumeIcon.png);
background-size: contain;
background-repeat: no-repeat;
background-size: 30px 30px;
}
#highScores {
width: 400px;
height: 300px;
font-size: 30px;
font-family: "Georgia", "Times New Roman";
text-align: center;
position: absolute;
}
<ol id="highScores"></ol>
<div class="grid">
<div class="volumeIcon"></div>
</div>
I included what I think will reproduce the situation. Hope this helps you help me.

Why not just put:
<ol id = "highScores"></ol>
within a <div> and give that a class that has display: none initally? Like this:
<div class="high-scores-container">
<ol id = "highScores"></ol>
</div>
.high-scores-container {
display: none;
height: 100%;
}
Then when you run your showHighScores() function, grab the high-scores-container div and change the display to block and then at the same time, grab the grid div and set that to display: none. That will give you the effect of displaying your high scores on a separate page but you're just doing so with JS/CSS.

Related

Increase or decrease value continuously using mousedown JavaScript

I copied some code from here.
The following code has some errors when the value reaches the minFontSize or maxFontSize.
I don't know how to fix this...
const decreaseFontSizeBtn = document.querySelector(".fontsize-via-btn #decrease");
const increaseFontSizeBtn = document.querySelector(".fontsize-via-btn #increase");
const fontSizeDisplay = document.querySelector(".fontsize-via-btn .current-fontsize");
const defaultFontSize = 20;
const minFontSize = 16;
const maxFontSize = 40;
let currentFontSize = defaultFontSize;
var timeout, interval;
[decreaseFontSizeBtn, increaseFontSizeBtn].forEach(btn => {
btn.addEventListener("mousedown", () => {
if (btn.id === "decrease") {
decreaseFontSize();
hold(decreaseFontSize);
}
if (btn.id === "increase") {
increaseFontSize();
hold(increaseFontSize);
}
saveFontSize();
})
btn.addEventListener("mouseup", clearTimers);
btn.addEventListener("mouseleave", clearTimers);
function clearTimers() {
clearTimeout(timeout);
clearInterval(interval);
}
})
function hold(func) {
timeout = setTimeout(() => {
interval = setInterval(() => {
func();
saveFontSize();
}, 50)
}, 300)
}
function decreaseFontSize() {
if (currentFontSize > minFontSize) {
currentFontSize -= 2;
}
if (currentFontSize === minFontSize) {
decreaseFontSizeBtn.disabled = true;
} else {
increaseFontSizeBtn.disabled = false;
}
}
function increaseFontSize() {
if (currentFontSize < maxFontSize) {
currentFontSize += 2;
}
if (currentFontSize === maxFontSize) {
increaseFontSizeBtn.disabled = true;
} else {
decreaseFontSizeBtn.disabled = false;
}
}
function saveFontSize() {
fontSizeDisplay.textContent = currentFontSize;
// localStorage ...
}
.fontsize-via-btn {
width: 100px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
font-size: 2rem;
}
<div class="fontsize-via-btn">
<button id="decrease">A-</button>
<div class="current-fontsize">20</div>
<button id="increase">A+</button>
</div>
Your timers are not cleared when you hit the minimum or maximum because (as #timmmmmb already said) disabled buttons don't trigger mouse events. Thus, when you try to go in the other direction, the original timer is again executed.
The simplest would probably be, calling clearTimers also when you hit the end of the range
const decreaseFontSizeBtn = document.querySelector(".fontsize-via-btn #decrease");
const increaseFontSizeBtn = document.querySelector(".fontsize-via-btn #increase");
const fontSizeDisplay = document.querySelector(".fontsize-via-btn .current-fontsize");
const defaultFontSize = 20;
const minFontSize = 16;
const maxFontSize = 40;
let currentFontSize = defaultFontSize;
var timeout, interval;
function clearTimers() {
clearTimeout(timeout);
clearInterval(interval);
}
[decreaseFontSizeBtn, increaseFontSizeBtn].forEach(btn => {
btn.addEventListener("mousedown", () => {
if (btn.id === "decrease") {
decreaseFontSize();
hold(decreaseFontSize);
}
if (btn.id === "increase") {
increaseFontSize();
hold(increaseFontSize);
}
saveFontSize();
})
btn.addEventListener("mouseup", clearTimers);
btn.addEventListener("mouseleave", clearTimers);
})
function hold(func) {
timeout = setTimeout(() => {
interval = setInterval(() => {
func();
saveFontSize();
}, 50)
}, 300)
}
function decreaseFontSize() {
if (currentFontSize > minFontSize) {
currentFontSize -= 2;
}
if (currentFontSize === minFontSize) {
decreaseFontSizeBtn.disabled = true;
clearTimers();
} else {
increaseFontSizeBtn.disabled = false;
}
}
function increaseFontSize() {
if (currentFontSize < maxFontSize) {
currentFontSize += 2;
}
if (currentFontSize === maxFontSize) {
clearTimers();
increaseFontSizeBtn.disabled = true;
} else {
decreaseFontSizeBtn.disabled = false;
}
}
function saveFontSize() {
fontSizeDisplay.textContent = currentFontSize;
// localStorage ...
}
.fontsize-via-btn {
width: 100px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
font-size: 2rem;
}
<div class="fontsize-via-btn">
<button id="decrease">A-</button>
<div class="current-fontsize">20</div>
<button id="increase">A+</button>
</div>
I think the problem is, that when you reach the max Fontsize you disable the button and that means your mouseup event will not be triggerd. I moved the mouseup event away from the buttons and on the container and i think it works now.
const decreaseFontSizeBtn = document.querySelector(".fontsize-via-btn #decrease");
const increaseFontSizeBtn = document.querySelector(".fontsize-via-btn #increase");
const fontSizeDisplay = document.querySelector(".fontsize-via-btn .current-fontsize");
const fontSizeContainer = document.querySelector(".fontsize-via-btn");
const defaultFontSize = 20;
const minFontSize = 16;
const maxFontSize = 40;
let currentFontSize = defaultFontSize;
var timeout, interval;
fontSizeContainer.addEventListener("mouseup", clearTimers);
fontSizeContainer.addEventListener("mouseleave", clearTimers);
function clearTimers() {
clearTimeout(timeout);
clearInterval(interval);
}
[decreaseFontSizeBtn, increaseFontSizeBtn].forEach(btn => {
btn.addEventListener("mousedown", () => {
if (btn.id === "decrease") {
decreaseFontSize();
hold(decreaseFontSize);
}
if (btn.id === "increase") {
increaseFontSize();
hold(increaseFontSize);
}
saveFontSize();
})
})
function hold(func) {
timeout = setTimeout(() => {
interval = setInterval(() => {
func();
saveFontSize();
}, 50)
}, 300)
}
function decreaseFontSize() {
if (currentFontSize > minFontSize) {
currentFontSize -= 2;
}
if (currentFontSize === minFontSize) {
decreaseFontSizeBtn.disabled = true;
} else {
increaseFontSizeBtn.disabled = false;
}
}
function increaseFontSize() {
if (currentFontSize < maxFontSize) {
currentFontSize += 2;
}
if (currentFontSize === maxFontSize) {
increaseFontSizeBtn.disabled = true;
} else {
decreaseFontSizeBtn.disabled = false;
}
}
function saveFontSize() {
fontSizeDisplay.textContent = currentFontSize;
// localStorage ...
}
.fontsize-via-btn {
width: 100px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
font-size: 2rem;
}
<div class="fontsize-via-btn">
<button id="decrease">A-</button>
<div class="current-fontsize">20</div>
<button id="increase">A+</button>
</div>
Discrepancies
"mouseup" and "mouseleave" needs to be registered on each button or the events must be delegated to the buttons. Right now the mouse events only affect the <div> which doesn't have any functions firing off on it. So that's why the buttons get stuck -- they are consantly repeating themselves even after the user releases the mousebutton.
The example below has separate event handlers for each button. Normally I prefer to use one event handler to control everything through
event delegation, but because of the need to use set\clearInterval() as event handlers, the event object gets lost. I could solve that problem with a closure, but your code was close enough that a radical change wouldn't be to your benifet.
Saving with localStorage (I know it's not part of the question) is omitted from this version since this site blocks it's use. I wrote another version that saves the current font-size and loads it as well, to review that one go to this Plunker.
const io = document.forms.UI.elements;
let current = 1.5;
let repeatInc = null;
let repeatDec = null;
function holdInc(e) {
if (repeatInc === null) {
repeatInc = setInterval(incFontSize, 100);
}
};
function releaseInc(e) {
if (repeatInc != null) {
clearInterval(repeatInc);
repeatInc = null;
}
};
function incFontSize() {
const io = document.forms.UI.elements;
const max = 4;
if (current < max) {
current += 0.25;
io.dec.disabled = false;
}
if (current == max) {
io.inc.disabled = true;
releaseInc();
}
io.fSize.value = current.toFixed(2);
io.text.style.fontSize = `${current}rem`
};
function holdDec(e) {
if (repeatDec == null) {
repeatDec = setInterval(decFontSize, 100);
}
};
function releaseDec(e) {
if (repeatDec != null) {
clearInterval(repeatDec);
repeatDec = null;
}
};
function decFontSize() {
const io = document.forms.UI.elements;
const min = 1;
if (current > min) {
current -= 0.25;
io.inc.disabled = false;
}
if (current == min) {
io.dec.disabled = true;
releaseDec()
}
io.fSize.value = current.toFixed(2);
io.text.style.fontSize = `${current}rem`
};
io.inc.addEventListener('mousedown', holdInc);
io.inc.addEventListener('mouseup', releaseInc);
io.inc.addEventListener('mousemove', releaseInc);
io.dec.addEventListener('mousedown', holdDec);
io.dec.addEventListener('mouseup', releaseDec);
io.dec.addEventListener('mouseleave', releaseDec);
:root {
font: 2ch/1 'Segoe UI'
}
body {
font-size: 1ch;
}
.ctrl {
display: flex;
align-items: center;
justify-content: flex-start;
font-size: 1rem;
padding: 5px;
}
#fSize {
display: block;
width: 5ch;
margin: 0 4px;
font-family: Consolas;
text-align: center;
}
button {
display: block;
width: max-content;
font: inherit;
cursor: pointer;
}
label {
display: block;
width: max-content;
margin: 0 8px;
font-size: 1rem;
}
.text {
min-height: 50px;
font-size: 1.25rem;
}
<form id='UI'>
<fieldset name='ctrl' class='ctrl'>
<button id="dec" type='button'>🗛-</button>
<output id="fSize">1.50</output>
<button id="inc" type='button'>🗚+</button>
<label>Scale: 1ch => 1rem</label>
</fieldset>
<fieldset name='text' class='text' contenteditable>
This test area has editable content
</fieldset>
</form>

Can't make a simple If Else statement work

Hello I'm making a simple counter that is counting to 3 every time i click the button. The counter works just fine, because I can see how he changes in the console. The problem is, my JS isn't affecting the CSS. When I delete the else statements and leave only one, this is the one that is working.
CSS. note: The strongAttackBtn and strongAttackBtnLoading are in the same div.
.strongAttackBtn {
height: 50px;
width: 150px;
color: black;
font-weight: 800;
}
.strongAttackBtnLoading {
position: absolute;
height: 50px;
width: 150px;
background-color: rgba(0,0,0,0.5);
}
JS
const strongAttackBtnLoading = document.querySelector('.strongAttackBtnLoading');
const strongAttackBtn = document.querySelector('.strongAttackBtn');
let strongAttackCounter = 0;
if (strongAttackCounter === 3) {
strongAttackBtnLoading.style.width = '150px';
} else if (strongAttackCounter === 2) {
strongAttackBtnLoading.style.width = '100px';
} else if (strongAttackCounter === 1) {
strongAttackBtnLoading.style.width = '50px';
} else if (strongAttackCounter === 0) {
strongAttackBtnLoading.style.width = '0px';
}
strongAttackBtn.addEventListener('click', function(){
strongAttackCounter++;
})
Try this code.
You have to assign CSS to both DIVs and put your if statement code in the addEventListener click function.
const strongAttackBtn = document.querySelector('.strongAttackBtn');
const strongAttackBtnLoading =document.querySelector('.strongAttackBtnLoading');
var strongAttackCounter = 0;
strongAttackBtn.addEventListener('click', function(){
strongAttackCounter++;
if (strongAttackCounter === 3) {
strongAttackCounter=0; // set it to zero again;
strongAttackBtnLoading.style.width = '150px';
strongAttackBtn.style.width = '150px';
} else if (strongAttackCounter === 2) {
strongAttackBtnLoading.style.width = '100px';
strongAttackBtn.style.width = '100px';
} else if (strongAttackCounter === 1) {
strongAttackBtnLoading.style.width = '50px';
strongAttackBtn.style.width = '50px';
} else if (strongAttackCounter === 0) {
strongAttackBtnLoading.style.width = '0px';
strongAttackBtn.style.width = '0px';
}
})
.strongAttackBtn {
height: 50px;
width: 150px;
color: black;
font-weight: 800;
}
.strongAttackBtnLoading {
position: absolute;
height: 50px;
width: 150px;
background-color: rgba(0,0,0,0.5);
}
<div class="strongAttackBtnLoading"><input class="strongAttackBtn" type="button" value="strongAttackBtn"></div>

Javascript - Multiple File Uploader with Limit

This Javascript function allows for multiple file uploads and includes a file size limit, however it is missing a maximum number of files allowed to be uploaded.
The function handleFile(e) has the file type and size arguments passed through it but do not know where to introduce a limit on the allowable number of files to be uploaded.
const fInputs = document.querySelectorAll('.btcd-f-input>div>input')
function getFileSize(size) {
let _size = size
let unt = ['Bytes', 'KB', 'MB', 'GB'],
i = 0; while (_size > 900) { _size /= 1024; i++; }
return (Math.round(_size * 100) / 100) + ' ' + unt[i];
}
function delItem(el) {
fileList = { files: [] }
let fInp = el.parentNode.parentNode.parentNode.querySelector('input[type="file"]')
for (let i = 0; i < fInp.files.length; i++) {
fileList.files.push(fInp.files[i])
}
fileList.files.splice(el.getAttribute('data-index'), 1)
fInp.files = createFileList(...fileList.files)
if (fInp.files.length > 0) {
el.parentNode.parentNode.parentNode.querySelector('.btcd-f-title').innerHTML = `${fInp.files.length} File Selected`
} else {
el.parentNode.parentNode.parentNode.querySelector('.btcd-f-title').innerHTML = 'No File Chosen'
}
el.parentNode.remove()
}
function fade(element) {
let op = 1; // initial opacity
let timer = setInterval(function () {
if (op <= 0.1) {
clearInterval(timer);
element.style.display = 'none';
}
element.style.opacity = op;
element.style.filter = 'alpha(opacity=' + op * 100 + ")";
op -= op * 0.1;
}, 50);
}
function unfade(element) {
let op = 0.01; // initial opacity
element.style.opacity = op;
element.style.display = 'flex';
let timer = setInterval(function () {
if (op >= 1) {
clearInterval(timer);
}
element.style.opacity = op;
element.style.filter = 'alpha(opacity=' + op * 100 + ")";
op += op * 0.1;
}, 13);
}
function get_browser() {
let ua = navigator.userAgent, tem, M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if (/trident/i.test(M[1])) {
tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
return { name: 'IE', version: (tem[1] || '') };
}
if (M[1] === 'Chrome') {
tem = ua.match(/\bOPR|Edge\/(\d+)/)
if (tem != null) { return { name: 'Opera', version: tem[1] }; }
}
M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
if ((tem = ua.match(/version\/(\d+)/i)) != null) { M.splice(1, 1, tem[1]); }
return {
name: M[0],
version: M[1]
};
}
for (let inp of fInputs) {
inp.parentNode.querySelector('.btcd-inpBtn>img').src = ''
inp.addEventListener('mousedown', function (e) { setPrevData(e) })
inp.addEventListener('change', function (e) { handleFile(e) })
}
let fileList = { files: [] }
let fName = null
let mxSiz = null
function setPrevData(e) {
if (e.target.hasAttribute('multiple') && fName !== e.target.name) {
console.log('multiple')
fName = e.target.name
fileList = fileList = { files: [] }
if (e.target.files.length > 0) {
for (let i = 0; i < e.target.files.length; i += 1) {
console.log(e.target.files[i])
fileList.files.push(e.target.files[i])
}
}
}
}
function handleFile(e) {
let err = []
const fLen = e.target.files.length;
mxSiz = e.target.parentNode.querySelector('.f-max')
mxSiz = mxSiz != null && (Number(mxSiz.innerHTML.replace(/\D/g, '')) * Math.pow(1024, 2))
if (e.target.hasAttribute('multiple')) {
for (let i = 0; i < fLen; i += 1) {
fileList.files.push(e.target.files[i])
}
} else {
fileList.files.push(e.target.files[0])
}
//type validate
if (e.target.hasAttribute('accept')) {
let tmpf = []
let type = new RegExp(e.target.getAttribute('accept').split(",").join("$|") + '$', 'gi')
for (let i = 0; i < fileList.files.length; i += 1) {
if (fileList.files[i].name.match(type)) {
tmpf.push(fileList.files[i])
} else {
err.push('Wrong File Type Selected')
}
}
fileList.files = tmpf
}
// size validate
if (mxSiz > 0) {
let tmpf = []
for (let i = 0; i < fileList.files.length; i += 1) {
if (fileList.files[i].size < mxSiz) {
tmpf.push(fileList.files[i])
mxSiz -= fileList.files[i].size
} else {
console.log('rejected', i, fileList.files[i].size)
err.push('Max Upload Size Exceeded')
}
}
fileList.files = tmpf
}
if (e.target.hasAttribute('multiple')) {
e.target.files = createFileList(...fileList.files)
} else {
e.target.files = createFileList(fileList.files[fileList.files.length - 1])
fileList = { files: [] }
}
// set File list view
if (e.target.files.length > 0) {
e.target.parentNode.querySelector('.btcd-f-title').innerHTML = e.target.files.length + ' File Selected'
e.target.parentNode.parentNode.querySelector('.btcd-files').innerHTML = ''
for (let i = 0; i < e.target.files.length; i += 1) {
let img = null
if (e.target.files[i].type.match(/image-*/)) {
img = window.URL.createObjectURL(e.target.files[i])
}
else {
img = ''
}
e.target.parentNode.parentNode.querySelector('.btcd-files').insertAdjacentHTML('beforeend', `<div>
<img src="${img}" alt="img" title="${e.target.files[i].name}">
<div>
<span title="${e.target.files[i].name}">${e.target.files[i].name}</span>
<br/>
<small>${getFileSize(e.target.files[i].size)}</small>
</div>
<button type="button" onclick="delItem(this)" data-index="${i}" title="Remove This File"><span>×</span></button>
</div>`)
}
}
// set eror
if (err.length > 0) {
for (let i = 0; i < err.length; i += 1) {
e.target.parentNode.parentNode.querySelector('.btcd-files').insertAdjacentHTML('afterbegin', `
<div style="background: #fff2f2;color: darkred;display:none" class="btcd-f-err">
<img src="" alt="img">
<span>${err[i]}</span>
</div>`)
}
const errNods = e.target.parentNode.parentNode.querySelectorAll('.btcd-files>.btcd-f-err')
for (let i = 0; i < errNods.length; i += 1) {
unfade(errNods[i])
setTimeout(() => { fade(errNods[i]) }, 3000);
setTimeout(() => { errNods[i].remove() }, 4000);
}
err = []
}
}
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
font-family: Arial, Helvetica, sans-serif;
}
.btcd-f-input {
display: inline-block;
width: 340px;
position: relative;
overflow: hidden;
}
.btcd-f-input>div>input::-webkit-file-upload-button {
cursor: pointer;
}
.btcd-f-wrp {
cursor: pointer;
}
.btcd-f-wrp>small {
color: gray;
}
.btcd-f-wrp>button {
cursor: pointer;
background: #f3f3f3;
padding: 5px;
display: inline-block;
border-radius: 9px;
border: none;
margin-right: 8px;
height: 35px;
}
.btcd-f-wrp>button>img {
width: 24px;
}
.btcd-f-wrp>button>span,
.btcd-f-wrp>span,
.btcd-f-wrp>small {
vertical-align: super;
}
.btcd-f-input>.btcd-f-wrp>input {
z-index: 100;
width: 100%;
position: absolute;
opacity: 0;
left: 0;
height: 37px;
cursor: pointer;
}
.btcd-f-wrp:hover {
background: #fafafa;
border-radius: 10px;
}
.btcd-files>div {
display: flex;
align-items: center;
background: #f8f8f8;
border-radius: 10px;
margin-left: 30px;
width: 91%;
margin-top: 10px;
height: 40px;
}
.btcd-files>div>div {
display: inline-block;
width: 73%;
}
.btcd-files>div>div>small {
color: gray;
}
.btcd-files>div>img {
width: 40px;
height: 40px;
margin-right: 10px;
border-radius: 10px;
}
.btcd-files>div>div>span {
display: inline-block;
width: 100%;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.btcd-files>div>button {
background: #e8e8e8;
border: none;
border-radius: 50px;
width: 25px;
height: 25px;
font-size: 20px;
margin-right: 6px;
padding: 0;
}
.btcd-files>div>button:hover {
background: #bbbbbb;
}
<div class="btcd-f-input">
<small>Multiple Upload</small>
<div class="btcd-f-wrp">
<button class="btcd-inpBtn" type="button"> <img src="" alt=""> <span> Attach File</span></button>
<span class="btcd-f-title">No File Chosen</span>
<small class="f-max">(Max 1 MB)</small>
<input multiple type="file" name="snd_multiple" id="">
</div>
<div class="btcd-files">
</div>
</div>
<script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>
<script src="https://unpkg.com/create-file-list#1.0.1/dist/create-file-list.min.js"></script>
In the function handleFile before type validate:
let maxFileNum = 10; // Maximum number of files
if (fileList.files.length > maxFileNum){
err.push("Too many files selected");
}

Page gets slow when I show new elements on a Swipable slider, ¿How can I fix that?

I making a swipable slider using touch events, when remains one visible element of visible elements I want to load new elements, for that I'm using this method:
initInteractionWithItems(elementsToMakeVisible) {
let totalMargin = 0 //the items are stacked and in the loop, the margin gradually gets bigger
let indexZ = 0 //the indexZ also gets bigger in the loop (is the z-index for the stacked elems)
const sizeItems = this.items.length
let styleElement = document.createElement("style")
document.head.appendChild(styleElement)
if (elementsToMakeVisible) {
firstInTheList.style.zIndex = "" + (elementsToMakeVisible + 1) * 1000
} else {
elementsToMakeVisible = this.itemsVisibleLength
}
totalMargin = this.marginTopFactor * elementsToMakeVisible
indexZ = elementsToMakeVisible * 1000
//while the list have elements, I show a portion of those
while ((elementsToMakeVisible !== 0) && (this.elementsCount < sizeItems)) {
let rule = ".swipeItem-" + this.elementsCount + "{ opacity: " + "1;" + "margin-top:" + totalMargin + "px;" + "z-index:" + indexZ + ";}"
this.items[this.elementsCount].classList.add("swipeItem-" + this.elementsCount)
totalMargin -= this.marginTopFactor
indexZ -= 1000
elementsToMakeVisible--
this.elementsCount++
styleElement.sheet.insertRule(rule)
}
}
}
The method do the job of show the elements, this same method I use when the page loads and I need
to show the first elements. but when I have to show more elements when the slider have only one element
the page gets slow, the element I removed (because I swipe it) gets stuck and lates to hide totally. finally the elements that I want load are show.
When I have to delete an element because was selected I use this method:
function sendTarget(event) {
if (event.cancelable) {
canSlide = false
event.preventDefault()
if (!has_option_selected) { //if a element has been selected
event.target.offsetParent.style.transform = "rotateZ(0deg)"
} else {
firstInTheList.remove()
firstInTheList = iteratorItems.next().value
countElements--
if (countElements === 1) { //if in the slider remains only one element
swipeReference.initInteractionWithItems(2)
}
}
}
}
Only the first element have the touch events, and every time an element gets selected I removed that element and the first element will be the next in the array I use for have the elements I want to show, for that I use this generator function:
function* getFirstItem(arrayElements) {
for (let i = 0; i < arrayElements.length; i++) {
arrayElements[i].addEventListener("touchstart", getCoords, true)
arrayElements[i].addEventListener("touchmove", slideTarget, true)
arrayElements[i].addEventListener("touchend", sendTarget, true)
yield arrayElements[i]
}
}
When I remove an element and I don't have to show new elements the sendTarget method works fine. the trouble is when I have to show new elements and I have to inkove initInteractionWithItems again.
How can I fix that?, what approach can I do for solve this performance trouble?
The full project:
let has_option_selected = false
let canSlide = false
let firstTime = true
let current_coord_x
let current_coord_y
let firstInTheList = null
let swipeItsClassName
let countElements = 3
let swipeReference = null
let iteratorItems = null
function getCoords(event) {
if (event.target.offsetParent.classList.contains("swipeItem") && event.cancelable) {
event.preventDefault()
canSlide = true
current_coord_x = event.changedTouches[0].clientX
current_coord_y = event.changedTouches[0].clientY
} else {
current_coord_x = event.clientX
current_coord_y = event.clientY
}
}
function calcRotation(translateXValue, element) {
let rotateValue = translateXValue * 0.10
if (rotateValue <= -15) {
notifySelection(element, 1)
return -15
} else if (rotateValue >= 15) {
notifySelection(element, -1)
return 15
} else {
notifySelection(element, 0)
return rotateValue
}
}
function moveTarget(event, target) {
let translateX = (event.changedTouches[0].clientX - current_coord_x)
let translateY = (event.changedTouches[0].clientY - current_coord_y)
if (event instanceof TouchEvent) {
if (firstTime) {
translateY += 100
}
target.style.transform = "translateX(" + translateX + "px" + ")" + " " + "translateY(" + translateY + "px)" + " " + "rotateZ(" + calcRotation(translateX, target) + "deg)"
}
}
function notifySelection(target, state) {
if (state === 1) {
//target.offsetParent.style.color = "green"
has_option_selected = true
} else if (state === -1) {
//target.offsetParent.style.color = "red"
has_option_selected = true
} else {
// target.offsetParent.style.color = "yellow"
has_option_selected = false
}
}
function sendTarget(event) {
if (event.cancelable) {
canSlide = false
event.preventDefault()
if (!has_option_selected) {
event.target.offsetParent.style.transform = "rotateZ(0deg)"
} else {
firstInTheList.remove()
firstInTheList = iteratorItems.next().value
countElements--
if (countElements === 1) {
swipeReference.initInteractionWithItems(2)
}
}
}
}
function slideTarget(e) {
let parentTarget = e.target.offsetParent
let hasClassItem = parentTarget.classList.contains("swipeItem")
if ((canSlide && e.cancelable && hasClassItem) && (firstInTheList === parentTarget)) {
e.preventDefault()
moveTarget(e, parentTarget)
}
}
function* getFirstItem(arrayElements) {
for (let i = 0; i < arrayElements.length; i++) {
arrayElements[i].addEventListener("touchstart", getCoords, true)
arrayElements[i].addEventListener("touchmove", slideTarget, true)
arrayElements[i].addEventListener("touchend", sendTarget, true)
yield arrayElements[i]
}
}
class SwipeSlider {
constructor(swipeItems, marginTopFactor = 30, itemsVisibleLenght = 3) {
//swipeItsClassName = swipeItemsClassName
swipeReference = this
this.items = swipeItems
iteratorItems = getFirstItem(this.items)
firstInTheList = iteratorItems.next().value
this.itemsVisibleLength = itemsVisibleLenght
this.marginTopFactor = marginTopFactor
this.totalMarginSize = (this.marginTopFactor * itemsVisibleLenght)
this.elementsCount = 0
}
initInteractionWithItems(elementsToMakeVisible) {
let totalMargin = 0
let indexZ = 0
const sizeItems = this.items.length
let styleElement = document.createElement("style")
document.head.appendChild(styleElement)
if (elementsToMakeVisible) {
firstInTheList.style.zIndex = "" + (elementsToMakeVisible + 1) * 1000
} else {
elementsToMakeVisible = this.itemsVisibleLength
}
totalMargin = this.marginTopFactor * elementsToMakeVisible
indexZ = elementsToMakeVisible * 1000
while ((elementsToMakeVisible !== 0) && (this.elementsCount < sizeItems)) {
let rule = ".swipeItem-" + this.elementsCount + "{ opacity: " + "1;" + "margin-top:" + totalMargin + "px;" + "z-index:" + indexZ + ";}"
this.items[this.elementsCount].classList.add("swipeItem-" + this.elementsCount)
totalMargin -= this.marginTopFactor
indexZ -= 1000
elementsToMakeVisible--
this.elementsCount++
styleElement.sheet.insertRule(rule)
}
}
}
function getArrayElements(elements) {
let array = []
for (let i = 0; i < 6; i++) {
array.push(elements[i])
}
return array
}
let arrayElements = getArrayElements(document.querySelectorAll(".swipeItem"))
let slider = new SwipeSlider(arrayElements)
slider.initInteractionWithItems()
#import url('https://fonts.googleapis.com/css?family=Solway&display=swap');
:root{
--fontHeadingProspect: 25px;
}
*{
box-sizing: border-box;
padding: 0;
margin: 0;
}
.swipeImg{
width: 100%;
height: 300px;
grid-row: 1;
grid-column: 1;
object-fit: cover;
object-position: center;
border-radius: 15px;
}
.swipeContainer{
position: relative;
display: grid;
min-height: 100vh;
justify-content: center;
align-content: center;
align-items: center;
justify-items: center;
grid-template-rows: minmax(300px,auto);
}
.gridSwipeItem{
display: grid;
}
.swipeItem{
background-color: rgb(252, 237, 223);
position: relative;
max-width: 270px;
grid-column: 1 ;
grid-row: 1;
opacity: 0;
font-family: 'Solway', serif;
box-shadow: 0px 0px 5px rgb(233, 209, 130);
border-radius: 15px;
transition: opacity 0.5s;
z-index: 0;
}
.headingProspect{
grid-row: 1;
grid-column: 1;
font-size: var(--fontHeadingProspect);
color: white;
z-index: 1;
align-self: end;
margin-left: 15px;
margin-bottom: 15px;
}
.headingProspectSection{
writing-mode: vertical-rl;
grid-column: 1 / 2;
justify-self: start;
transform: rotateZ(180deg);
margin-left: 30px;
font-size: 34px;
font-family: 'Solway', serif;
text-align: center;
text-transform: uppercase;
color: #f74040;
}
.selection-zone{
background-image: rgb(255, 225, 169);
}
.visibleTarget{
opacity: 1;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<section class="selection-zone">
<div class="swipeContainer" id="swipeContainer">
<article class="swipeItem gridSwipeItem" id="swipeItem">
<img src="http://lorempixel.com/1200/1200" class="swipeImg">
<h1 id="prospectState" class="headingProspect">Rose Ann, 19</h1>
</article>
<article class="swipeItem gridSwipeItem">
<img src="http://lorempixel.com/1200/1200" class="swipeImg">
<h1 id="prospectState" class="headingProspect">Mary Wolfstoncraft, 24</h1>
</article>
<article class="swipeItem gridSwipeItem">
<img src="http://lorempixel.com/1200/1200" class="swipeImg">
<h1 id="prospectState" class="headingProspect">Rose Doe, 34</h1>
</article>
<article class="swipeItem gridSwipeItem">
<img src="http://lorempixel.com/1200/1200" class="swipeImg">
<h1 id="prospectState" class="headingProspect">Joane Smith, 34</h1>
</article>
<article class="swipeItem gridSwipeItem">
<img src="http://lorempixel.com/1200/1200" class="swipeImg">
<h1 id="prospectState" class="headingProspect">Mary Wolfstoncraft, 24</h1>
</article>
</div>
</section>
<script src="script.js"></script>
</body>
</html>

Javascript end game when click on image

Hey this is my first time on Stackoverflow!
I am building a small javascript html5 game where you click on objects kind of like whack-a-mole.. The goal is to kill as many "gem green" and " gem blue" as possible in 10 seconds, and when you click on the "gem red".. the game ends and plays a sound.
I got most things to work, except I can't find a way to make the game end when clicking on "gem red".. I have tried lots of functions and listeners.. but to no avail.. can anyone help me figure this out?
Here is the code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>HTML 5 Gem Game</title>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1">
<style>
section#game {
width: 480px;
height: 800px;
max-width: 100%;
max-height: 100%;
overflow: hidden;
position: relative;
background-image: url('img/Splash.png');
position: relative;
color: #ffffff;
font-size: 30px;
font-family: "arial,sans-serif";
}
section#game .score{
display: block;
position: absolute;
top: 10px;
left: 10px;
}
section#game .time{
display: block;
position: absolute;
top: 10px;
right: 10px;
}
section#game .start{
display: block;
padding-top: 40%;
margin: 0 auto 0 auto;
text-align: center;
width: 70%;
cursor: pointer;
}
section#game .start .high-scores{
text-align: left;
}
section#game .gem{
display: block;
position: absolute;
width: 40px;
height: 44px;
cursor: pointer;
}
section#game .gem.green{
background: url('img/Gem Green.png') no-repeat top left;
}
section#game .gem.blue{
background: url('img/Gem Blue.png') no-repeat top left;
}
section#game .gem.red{
background: url('img/Gem Red.png') no-repeat top left;
}
</style>
<script>
function addEvent(element, event, delegate ) {
if (typeof (window.event) != 'undefined' && element.attachEvent)
element.attachEvent('on' + event, delegate);
else
element.addEventListener(event, delegate, false);
}
function Game(){
var game = document.querySelector("section#game");
var score = game.querySelector("section#game span.score");
var high_scores = game.querySelector("section#game ol.high-scores");
var time = game.querySelector("section#game span.time");
var start = game.querySelector("section#game span.start");
function Gem(Class, Value, MaxTTL) {
this.Class = Class;
this.Value = Value;
this.MaxTTL = MaxTTL;
};
var gems = new Array();
gems[0] = new Gem('green', 10, 1.2);
gems[1] = new Gem('blue', 20, 1);
gems[2] = new Gem('red', 50, 0.75);
function Click(event)
{
if(event.preventDefault) event.preventDefault();
if (event.stopPropagation) event.stopPropagation();
else event.cancelBubble = true;
var target = event.target || event.srcElement;
if(target.className.indexOf('gem') > -1){
var value = parseInt(target.getAttribute('data-value'));
var current = parseInt( score.innerHTML );
var audio = new Audio('music/blaster.mp3');
audio.play();
score.innerHTML = current + value;
target.parentNode.removeChild(target);
}
return false;
}
function Remove(id) {
var gem = game.querySelector("#" + id);
if(typeof(gem) != 'undefined')
gem.parentNode.removeChild(gem);
}
function Spawn() {
var index = Math.floor( ( Math.random() * 3 ) );
var gem = gems[index];
var id = Math.floor( ( Math.random() * 1000 ) + 1 );
var ttl = Math.floor( ( Math.random() * parseInt(gem.MaxTTL) * 1000 ) + 1000 ); //between 1s and MaxTTL
var x = Math.floor( ( Math.random() * ( game.offsetWidth - 40 ) ) );
var y = Math.floor( ( Math.random() * ( game.offsetHeight - 44 ) ) );
var fragment = document.createElement('span');
fragment.id = "gem-" + id;
fragment.setAttribute('class', "gem " + gem.Class);
fragment.setAttribute('data-value', gem.Value);
game.appendChild(fragment);
fragment.style.left = x + "px";
fragment.style.top = y + "px";
setTimeout( function(){
Remove(fragment.id);
}, ttl)
}
<!-- parse high score keeper -->
function HighScores() {
if(typeof(Storage)!=="undefined"){
var scores = false;
if(localStorage["high-scores"]) {
high_scores.style.display = "block";
high_scores.innerHTML = '';
scores = JSON.parse(localStorage["high-scores"]);
scores = scores.sort(function(a,b){return parseInt(b)-parseInt(a)});
for(var i = 0; i < 10; i++){
var s = scores[i];
var fragment = document.createElement('li');
fragment.innerHTML = (typeof(s) != "undefined" ? s : "" );
high_scores.appendChild(fragment);
}
}
} else {
high_scores.style.display = "none";
}
}
function UpdateScore() {
if(typeof(Storage)!=="undefined"){
var current = parseInt(score.innerHTML);
var scores = false;
if(localStorage["high-scores"]) {
scores = JSON.parse(localStorage["high-scores"]);
scores = scores.sort(function(a,b){return parseInt(b)-parseInt(a)});
for(var i = 0; i < 10; i++){
var s = parseInt(scores[i]);
var val = (!isNaN(s) ? s : 0 );
if(current > val)
{
val = current;
scores.splice(i, 0, parseInt(current));
break;
}
}
scores.length = 10;
localStorage["high-scores"] = JSON.stringify(scores);
} else {
var scores = new Array();
scores[0] = current;
localStorage["high-scores"] = JSON.stringify(scores);
}
HighScores();
}
}
function Stop(interval) {
clearInterval(interval);
}
this.Start = function() {
score.innerHTML = "0";
start.style.display = "none";
var interval = setInterval(Spawn, 750);
var count = 10;
var counter = null;
function timer()
{
count = count-1;
if (count <= 0)
{
var left = document.querySelectorAll("section#game .gem");
for (var i = 0; i < left.length; i++) {
if(left[i] && left[i].parentNode) {
left[i].parentNode.removeChild(left[i]);
}
}
Stop(interval);
Stop(counter);
time.innerHTML = "Game Over!";
start.style.display = "block";
UpdateScore();
return;
} else {
time.innerHTML = count + "s left";
}
}
counter = setInterval(timer, 1000);
setTimeout( function(){
Stop(interval);
}, count * 1000)
};
addEvent(game, 'click', Click);
addEvent(start, 'click', this.Start);
HighScores();
}
addEvent(document, 'readystatechange', function() {
if ( document.readyState !== "complete" )
return true;
var game = new Game();
});
</script>
</head>
<body>
<div id="page">
<section id="game">
<span class="score">0</span>
<span class="time">0</span>
<span class="start">START!
<ol class="high-scores"></ol>
</span>
</section>
</div>
</body>
</html>
Alessio -
You only need a few minor changes to your code to make it work. The example below should help you get started in the right direction. Good luck.
Changes:
Add an endGame() function and move the stop game logic from the timer() function into it.
Add a line to the click() function to check for red gem clicks.
if (target.className.indexOf('red') > 0) endGame("Red Gem - You win!");
Declare the count, counter, and interval variables at the top of your Game object.
The code below also has a few minor CSS changes used for debugging which you can remove.
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>HTML 5 Gem Game</title>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1">
<style>
section#game {
width: 480px;
height: 800px;
max-width: 100%;
max-height: 100%;
overflow: hidden;
position: relative;
background-image: url('img/Splash.png');
border: 1px red dotted;
position: relative;
color: red;
font-size: 30px;
font-family: "arial,sans-serif";
}
section#game .score{
display: block;
position: absolute;
top: 10px;
left: 10px;
}
section#game .time{
display: block;
position: absolute;
top: 10px;
right: 10px;
}
section#game .start{
display: block;
padding-top: 40%;
margin: 0 auto 0 auto;
text-align: center;
width: 70%;
cursor: pointer;
}
section#game .start .high-scores{
text-align: left;
}
section#game .gem{
display: block;
position: absolute;
width: 40px;
height: 44px;
cursor: pointer;
}
section#game .gem.green{
background: url('img/Gem Green.png') no-repeat top left;
background-color: green;
}
section#game .gem.blue{
background: url('img/Gem Blue.png') no-repeat top left;
background-color: blue;
}
section#game .gem.red{
background: url('img/Gem Red.png') no-repeat top left;
background-color: red;
}
</style>
<script>
function addEvent(element, event, delegate ) {
if (typeof (window.event) != 'undefined' && element.attachEvent)
element.attachEvent('on' + event, delegate);
else
element.addEventListener(event, delegate, false);
}
function Game(){
var game = document.querySelector("section#game");
var score = game.querySelector("section#game span.score");
var high_scores = game.querySelector("section#game ol.high-scores");
var time = game.querySelector("section#game span.time");
var start = game.querySelector("section#game span.start");
var interval, counter, count;
function Gem(Class, Value, MaxTTL) {
this.Class = Class;
this.Value = Value;
this.MaxTTL = MaxTTL;
};
var gems = new Array();
gems[0] = new Gem('green', 10, 1.2);
gems[1] = new Gem('blue', 20, 1);
gems[2] = new Gem('red', 50, 0.75);
function Click(event)
{
if(event.preventDefault) event.preventDefault();
if (event.stopPropagation) event.stopPropagation();
else event.cancelBubble = true;
var target = event.target || event.srcElement;
if(target.className.indexOf('gem') > -1){
var value = parseInt(target.getAttribute('data-value'));
var current = parseInt( score.innerHTML );
var audio = new Audio('music/blaster.mp3');
audio.play();
score.innerHTML = current + value;
target.parentNode.removeChild(target);
if (target.className.indexOf('red') > 0) endGame("Red Gem - You win!");
}
return false;
}
function Remove(id) {
var gem = game.querySelector("#" + id);
if(typeof(gem) != 'undefined')
gem.parentNode.removeChild(gem);
}
function Spawn() {
var index = Math.floor( ( Math.random() * 3 ) );
var gem = gems[index];
var id = Math.floor( ( Math.random() * 1000 ) + 1 );
var ttl = Math.floor( ( Math.random() * parseInt(gem.MaxTTL) * 1000 ) + 1000 ); //between 1s and MaxTTL
var x = Math.floor( ( Math.random() * ( game.offsetWidth - 40 ) ) );
var y = Math.floor( ( Math.random() * ( game.offsetHeight - 44 ) ) );
var fragment = document.createElement('span');
fragment.id = "gem-" + id;
fragment.setAttribute('class', "gem " + gem.Class);
fragment.setAttribute('data-value', gem.Value);
game.appendChild(fragment);
fragment.style.left = x + "px";
fragment.style.top = y + "px";
setTimeout( function(){
Remove(fragment.id);
}, ttl)
}
<!-- parse high score keeper -->
function HighScores() {
if(typeof(Storage)!=="undefined"){
var scores = false;
if(localStorage["high-scores"]) {
high_scores.style.display = "block";
high_scores.innerHTML = '';
scores = JSON.parse(localStorage["high-scores"]);
scores = scores.sort(function(a,b){return parseInt(b)-parseInt(a)});
for(var i = 0; i < 10; i++){
var s = scores[i];
var fragment = document.createElement('li');
fragment.innerHTML = (typeof(s) != "undefined" ? s : "" );
high_scores.appendChild(fragment);
}
}
} else {
high_scores.style.display = "none";
}
}
function UpdateScore() {
if(typeof(Storage)!=="undefined"){
var current = parseInt(score.innerHTML);
var scores = false;
if(localStorage["high-scores"]) {
scores = JSON.parse(localStorage["high-scores"]);
scores = scores.sort(function(a,b){return parseInt(b)-parseInt(a)});
for(var i = 0; i < 10; i++){
var s = parseInt(scores[i]);
var val = (!isNaN(s) ? s : 0 );
if(current > val)
{
val = current;
scores.splice(i, 0, parseInt(current));
break;
}
}
scores.length = 10;
localStorage["high-scores"] = JSON.stringify(scores);
} else {
var scores = new Array();
scores[0] = current;
localStorage["high-scores"] = JSON.stringify(scores);
}
HighScores();
}
}
function Stop(interval) {
clearInterval(interval);
}
function endGame( msg ) {
count = 0;
Stop(interval);
Stop(counter);
var left = document.querySelectorAll("section#game .gem");
for (var i = 0; i < left.length; i++) {
if(left[i] && left[i].parentNode) {
left[i].parentNode.removeChild(left[i]);
}
}
time.innerHTML = msg || "Game Over!";
start.style.display = "block";
UpdateScore();
}
this.Start = function() {
score.innerHTML = "0";
start.style.display = "none";
interval = setInterval(Spawn, 750);
count = 10;
counter = null;
function timer()
{
count = count-1;
if (count <= 0)
{
endGame();
return;
} else {
time.innerHTML = count + "s left";
}
}
counter = setInterval(timer, 1000);
setTimeout( function(){
Stop(interval);
}, count * 1000)
};
addEvent(game, 'click', Click);
addEvent(start, 'click', this.Start);
HighScores();
}
addEvent(document, 'readystatechange', function() {
if ( document.readyState !== "complete" )
return true;
var game = new Game();
});
</script>
</head>
<body>
<div id="page">
<section id="game">
<span class="score">0</span>
<span class="time">0</span>
<span class="start">START!
<ol class="high-scores"></ol>
</span>
</section>
</div>
</body>
</html>
For starters, you shouldn't include a style sheet and your entire HTML file since neither is relevant and you should use a canvas element instead of this chaotic use of CSS and html elements, which would allow the size of your code to be halved. Furthermore, you should be able to fix this by just changing some global boolean variable to false when the red gem is clicked and when the boolean variable is false (this if statement belongs at the end of your game loop) you call Stop(arg)/clearInterval(arg). Given that your current code doesn't seem to have a global boolean variable indicating game state (using an enumeration would generally be a cleaner solution but a simple boolean seems to suit this case)

Categories