JavaScript Boolean is not working and looping goes wrong - javascript

The demo created is to illustrate the working of the logic described below -
I have created 4x4 tiles using JavaScript instead of hard coding into html
Code highlight the columns one by one in a infinite loop which is achieved by setInterval(colScan,1000)
When user press the mouse on html body, it changes the column scan --> row scan in the selected column which is also achieved by setInterval(rowScan,1000)
When user clicks again on the html body, it changes the row scan --> col scan
Problem:
No matter what, colScan is always activated which you can see in the console log that the column is always increasing.
When user clicks the second time it doesn't reset to column scan.
part of the code where I think the problem is occurring
createtiles();
var k = 0,
m = 0,
selected_col = "",
mousePressed = false,
col_scan = true,
row_scan = false;
scanSelector();
function scanSelector() {
if (col_scan) {
setInterval(colScan, 1000);
} else if (row_scan) {
setInterval(rowScan, 1000);
}
}
document.body.onmousedown = function() {
mousePressed = true;
}
function colScan() {
if (k > 2) k = 0;
else k++;
console.log("col " + k);
var col = ".j_" + k;
$(".tiles").removeClass('highlighter');
$(col).addClass('highlighter');
if (mousePressed) {
mousePressed = false;
col_scan = false;
row_scan = true;
selected_col = col;
scanSelector();
}
}
function rowScan() {
if (m > 2) m = 0;
else m++;
console.log("row " + m);
var row = selected_col + (".i_" + m);
$(".tiles").removeClass('highlighter');
$(row).addClass('highlighter');
if (mousePressed) {
mousePressed = false;
col_scan = true;
row_scan = false;
selected_col = "";
scanSelector();
}
}
function createtiles() {
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
var divTile = $('<div>', {
class: 'tiles ' + ("j_" + j) + " " + ("i_" + i)
});
divTile.appendTo('.comtile');
}
}
}
DEMO -> https://codepen.io/xblack/pen/BdGzYx
createtiles();
var k = 0,
m = 0,
selected_col = "",
mousePressed = false,
col_scan = true,
row_scan = false;
scanSelector();
function scanSelector() {
if (col_scan) {
setInterval(colScan, 1000);
} else if (row_scan) {
setInterval(rowScan, 1000);
}
}
document.body.onmousedown = function() {
mousePressed = true;
}
function colScan() {
if (k > 2) k = 0;
else k++;
console.log("col " + k);
var col = ".j_" + k;
$(".tiles").removeClass('highlighter');
$(col).addClass('highlighter');
if (mousePressed) {
mousePressed = false;
col_scan = false;
row_scan = true;
selected_col = col;
scanSelector();
}
}
function rowScan() {
if (m > 2) m = 0;
else m++;
console.log("row " + m);
var row = selected_col + (".i_" + m);
$(".tiles").removeClass('highlighter');
$(row).addClass('highlighter');
if (mousePressed) {
mousePressed = false;
col_scan = true;
row_scan = false;
selected_col = "";
scanSelector();
}
}
function createtiles() {
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
var divTile = $('<div>', {
class: 'tiles ' + ("j_" + j) + " " + ("i_" + i)
});
divTile.appendTo('.comtile');
}
}
}
html,
body {
margin: 0px;
padding: 0px;
height: 100%;
min-height: 100%;
overflow: hidden;
font-family: 'Roboto', sans-serif;
background: white;
}
* {
box-sizing: border-box!important;
}
.conatiner {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
grid-template-area: "menu" "comContent";
}
.menu {
grid-area: menu;
height: 5vh;
padding: 2vh;
}
.comtile {
grid-area: comContent;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: auto;
grid-gap: 0.5vh;
height: 95vh;
padding: 2vh;
}
.tiles {
background: #F7F7F7;
border-radius: 0.4vh;
border: 1px solid #EEEBEB;
}
.highlighter {
box-shadow: 0 0 4px rgba(0, 0, 0, 0.15);
transition: box-shadow 0.3s cubic-bezier(0.38, -0.76, 0, 1.69);
border: 1px solid silver;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="container">
<div class="menu">MAIN MENU</div>
<div class="comtile"></div>
</div>

You need to make the following changes:
Replace setInterval with setTimeout for reasons stated by #ASDFGerte.
function scanSelector() {
if (col_scan) {
// Replace setInterval with setTimeout
setTimeout(colScan, 1000);
} else i f (row_scan) {
// Replace setInterval with setTimeout
setTimeout(rowScan, 1000);
}
}
Move the scanSelector() lines in rowScan and colScan. The change is the same for both methods, I will only show the change in rowScan.
function rowScan() {
if (m > 2) m = 0;
else m++;
console.log("row " + m);
var row = selected_col + (".i_" + m);
$(".tiles").removeClass('highlighter');
$(row).addClass('highlighter');
if (mousePressed) {
mousePressed = false;
col_scan = true;
row_scan = false;
selected_col = "";
// Remove this line
// scanSelector();
}
// Because you're no longer using setInterval you need to call
// this method after each timeout.
scanSelector();
}
Every time you were calling scanSelector() it would create another interval. The initial interval will highlight the columns, after the first click you have two intervals running side-by-side: the original interval and an interval to highlight rows. After each click you're only adding intervals.
You could store the interval ID, the result of setInterval and clear this interval when you change from column to row highlight and vice versa. The easier solution is moving from setInterval to setTimeout as outlined in the changed I've shown you above.

Related

Looping a lotto game from codepen

Recently I've been looking at different projects and trying to modify them to try and understand the JS code much better. Recently I came across this lotto game from code pen. So I thought to try to make it to a game where you had coins as lives, then you get some stars based on how many numbers you got right.
The thing that I am struggling at is trying to loop the code on the click of a button. Currently the code is restarting the game by recalling its own link, in this case I just used my index.html as replacement for the href just to work on it for now. I want to change this because it doesn't let me consume all my coins (lives) without refreshing the page.
I tried putting everything in a function instead of calling it through the DOM being loaded. I then called that function when the dom has loaded, then after each draw I tried calling it again by using another button but it doesn't work. Tried changing the href to the function but that doesn't work as well. I also tried a few other things but I cannot make a work around this. Any help is appreciated! I'm still learning Javascript, so please pardon my question.
The code is not owned by me, I am just playing around with it, here's the original codepen link. https://codepen.io/EwaTrojanowskaGrela/pen/KmJMWb
// Declaration of scores and lives
var stars = 0;
var coins = 5;
// End of comment
// For redeclaration in innerHTML
var starsEarned;
// End of comment
// For displaying current score
document.getElementById("star-count").innerHTML = stars;
document.getElementById("coin-count").innerHTML = coins;
// End of comment
document.addEventListener("DOMContentLoaded", function(e){
var body = document.querySelector("body");
var section = document.querySelector("section");
var articleLotto = document.querySelector(".lotto");
var articleBalls = document.querySelector(".balls");
var numbers = [];
var balls = document.getElementsByClassName("ball");
var drawnNums = [];
var chosenByMachine = [];
function createNumberBoard(number){
console.log("I work");
var board = document.createElement("div");
board.classList.add("board");
articleLotto.appendChild(board);
for( var i = 0; i<number; i ++){
var boardEl = document.createElement("button");
boardEl.classList.add("boardEl");
board.appendChild(boardEl);
}
var boardEls = document.getElementsByClassName("boardEl");
for( var i =0; i<boardEls.length; i++){
boardEls[i].setAttribute("data-number", i+1);
var dataNumber = boardEls[i].getAttribute("data-number");
var number = parseInt(dataNumber, 10);
numbers.push(number);
boardEls[i].textContent = number;
}
}
createNumberBoard(49);
var board = document.querySelector(".board");
var boardEls = document.querySelectorAll(".boardEl");
function drawNumbers(){
//boardEls.forEach(boardEl => boardEl.addEventListener("click", selectNums));
for (var i = 0; i<boardEls.length; i++){
boardEls[i].addEventListener("click", selectNums);
}
function selectNums(){
var number = parseInt(this.dataset.number, 10);
if(this.hasAttribute("data-number")){
drawnNums.push(number);
this.removeAttribute("data-number");
this.classList.add("crossedOut");
}
if(drawnNums.length=== 6){
//boardEls.forEach( boardEl => boardEl.removeAttribute("data-number"));
//boardEls.forEach(boardEl => boardEl.addEventListener("click", makeAlert));
for ( var i = 0; i<boardEls.length; i++){
boardEls[i].removeAttribute("data-number");
boardEls[i].addEventListener("click", makeAlert);
}
var startDraw = document.querySelector(".startDraw");
if(startDraw === null){ // you have to prevent creating the button if it is already there!
createButtonForMachineDraw();
} else {
return;
}
}
}
return drawnNums;
}
drawNumbers();
function makeAlert() {
var alertBox = document.createElement("div");
board.appendChild(alertBox);
alertBox.classList.add("alertBox");
alertBox.textContent = "You can only choose 6!";
setTimeout(function() {
alertBox.parentNode.removeChild(alertBox);
}, 1500);
}
function machineDraw(){
for( var i =0; i<6; i++){
var idx = Math.floor(Math.random() * numbers.length)
chosenByMachine.push(numbers[idx]);
/*a very important line of code which prevents machine from drawing the same number again
*/
numbers.splice(idx,1);
console.log(numbers)
/*this line of code allows to check if numbers are taken out*/
}
var btnToRemove = document.querySelector(".startDraw");
btnToRemove.classList.add("invisible");
/* why not remove it entirely? because it might then be accidentally created if for some reason you happen to try to click on board!!! and you may do that*/
return chosenByMachine;
}
//machineDraw();
function createButtonForMachineDraw(){
var startDraw = document.createElement("button");
startDraw.classList.add("startDraw");
section.appendChild(startDraw);
startDraw.textContent ="Release the balls";
startDraw.addEventListener("click", machineDraw);
startDraw.addEventListener("click", compareArrays);
}
function compareArrays(){
for( var i =0; i<balls.length; i++) {
balls[i].textContent = chosenByMachine[i];
(function() {
var j = i;
var f = function(){
balls[j].classList.remove("invisible");
balls[j].classList.add("ball-align");
}
setTimeout(f, 1000*(j+1));
})();
}
var common =[];
var arr1 = chosenByMachine;
var arr2 = drawnNums;
for(var i = 0; i<arr1.length; i++){
for(var j= 0; j<arr2.length; j++){
if(arr1[i]===arr2[j]){
common.push(arr1[i]);
}
}
}
console.log(arr1, arr2, common); /* you can monitor your arrays in console*/
function generateResult(){
// Deduction of coins once draw started
coins = coins - 1;
// End of comment
var resultsBoard = document.createElement("article");
section.appendChild(resultsBoard);
var paragraph = document.createElement("p");
resultsBoard.appendChild(paragraph);
resultsBoard.classList.add("resultsBoard");
resultsBoard.classList.add("invisible");
if(common.length === 0){
paragraph.textContent ="Oh no! You got " + common.length + " Star!";
starsEarned = stars + common.length;
return starsEarned;
} else if(common.length === 1){
paragraph.textContent ="You got " + common.length + " Star!";
starsEarned = stars + common.length;
return starsEarned;
} else if(common.length === 2){
paragraph.textContent ="You got " + common.length + " Stars!";
starsEarned = stars + common.length;
return starsEarned;
} else if(common.length === 3) {
paragraph.textContent ="You got " + common.length + " Stars!";
starsEarned = stars + common.length;
return starsEarned;
} else if(common.length === 4){
paragraph.textContent ="You got " + common.length + " Stars!";
starsEarned = stars + common.length;
return ststarsEarnedars;
} else if(common.length === 5){
paragraph.textContent ="You got " + common.length + " Stars!";
starsEarned = stars + common.length;
return starsEarned;
}
else if(common.length===6){
paragraph.textContent ="A true winner! You got " + common.length + " Stars!";
stars = stars + common.length;
return starsEarned;
}
// Returning of new coins
return coins;
// End of comment
}
setTimeout(function() {
makeComebackBtn();
document.querySelector(".resultsBoard").classList.remove("invisible"); //well, you cannot acces this outside the code
// Displaying of new scores
stars = stars + starsEarned;
document.getElementById("coin-count").innerHTML = coins;
document.getElementById("star-count").innerHTML = stars;
// End of comment
}, 8000);
generateResult();
}
function makeComebackBtn(){
var comebackBtn = document.createElement("a");
comebackBtn.classList.add("comebackBtn");
section.appendChild(comebackBtn);
comebackBtn.textContent ="Go again"
comebackBtn.setAttribute("href", "index.html");
}
})
body {
padding: 0 15%;
}
.game-container {
height: auto;
background-color:#424B54;
font-family: "Allerta", sans-serif;
margin: 0;
max-width: 425px;
height: 750px;
/* padding: 0 2%; */
box-sizing: border-box;
}
section {
margin: 0 auto;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: auto;
padding-bottom: 15px;
}
h1,
p {
width: 100%;
text-align: center;
color: #FF6663;
text-shadow: 3px 3px #A20202;
font-family: "Bungee", cursive;
}
h1 {
font-size: 35px;
margin: 0;
}
p {
font-size: 30px;
margin: 0;
}
h3 {
color: #FF6663;
text-align: center;
text-shadow: 2px 2px #A20202;
font-size: 25px;
margin-bottom: 5px;
}
article {
height: 90%;
width: 250px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-bottom: 1rem;
}
.scores {
width: 100%;
}
.coins,
.stars{
display: flex;
align-items: center;
gap: .5rem;
}
.score-icons {
color: #F6BD60;
font-size: 3rem;
}
.scores span {
color: white;
}
#star-count,
#coin-count{
font-size: 1.5 rem;
}
.invisible {
display: none;
}
.ball-align {
display: flex;
justify-content: center;
align-items: center;
}
.board {
position: relative;
background-color: #FF6663;
width: 13.125rem;
height: 13.125rem;
border: 1px solid #FF6663;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
}
.boardEl {
background-color: #E8F7EE;
width: 28px;
height: 28px;
color: #000000;
text-align: center;
font-size: 15px;
border: none;
}
.crossedOut {
background-color: #424B54;
color: #F7EDE2;
}
.startDraw {
background: #FF6663;
border: none;
font-size: 1.3rem;
font-weight: bolder;
color: #ffffff;
padding: 0.5rem 1rem;
margin: 0 auto;
border-radius: .5rem;
padding: .5rem 1rem;
}
.ball {
width: 2rem;
height: 2rem;
border-radius: 50%;
line-height: 2;
color: #efefef;
font-weight: bold;
text-align: center;
}
.ball:nth-of-type(2n) {
align-self: flex-end;
}
.ball:nth-of-type(2n + 1) {
align-self: flex-start;
}
.ball:first-of-type {
background-color: gold;
border: 1px solid #ccac00;
}
.ball:nth-of-type(2) {
background-color: hotpink;
border: 1px solid #ff369b;
}
.ball:nth-of-type(3) {
background-color: teal;
border: 1px solid #004d4d;
}
.ball:nth-of-type(4) {
background-color: #009900;
border: 1px solid #006600;
}
.ball:nth-of-type(5) {
background-color: #339999;
border: 1px solid #267373;
}
.ball:last-of-type {
background-color: #ff6633;
border: 1px solid #ff4000;
}
#ballContainer {
background-color: inherit;
border-bottom: none;
display: flex;
align-items: center;
gap: 0.1rem;
}
.resultsBoard {
margin-top: .5rem;
text-align: center;
width: 100%;
}
.resultsBoard p {
color: #F6BD60;
font-size: 2rem;
font-family: "Allerta", sans-serif;
text-shadow: none;
}
.comebackBtn {
line-height: 2;
margin-top: 2rem;
font-size: 1.3rem;
text-align: center;
background-color: #FF6663;
text-decoration: none;
color: #ffffff;
padding: .3rem 1rem;
border-radius: .3rem;
text-transform: uppercase;
}
.alertBox {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 3;
color: #ffffff;
background-color: #FF6663;
text-align: center;
line-height: 210px;
}
<!DOCTYPE html>
<html lang="eng-ENG">
<head>
<meta charset="UTF-8">
<title>lotto</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="style.css">
<link href="https://fonts.googleapis.com/css?family=Allerta|Bungee" rel="stylesheet">
<link href='https://unpkg.com/boxicons#2.1.2/css/boxicons.min.css' rel='stylesheet'>
</head>
<body>
<main>
<div class="game-container">
<section>
<h1>Lottery</h1>
<div class="scores">
<div class="coins">
<i class='score-icons bx bxs-star'></i><span id="star-count"></span>
</div>
<div class="stars">
<i class='score-icons bx bx-coin'></i><span id="coin-count"></span>
</div>
</div>
<article class="lotto">
<h3>Pick 6 numbers:</h3>
</article>
<article class="balls">
<div id="ballContainer">
<div class="ball invisible"></div>
<div class="ball invisible"></div>
<div class="ball invisible"></div>
<div class="ball invisible"></div>
<div class="ball invisible"></div>
<div class="ball invisible"></div>
</div>
</article>
</section>
</div>
</main>
<script type="text/javascript" src="index.js"></script>
<!--<script type="text/javascript" src="js/app2.js"></script>-->
</body>
</html>
[UPDATED]
I've tried and modified the js script code and no need to save values in local storage. And in addition, no need to refresh page to reload game state. I implemented in JSFiddle here
var stars = 0;
var coins = 5;
var starsEarned = 0;
// For displaying current score
document.getElementById("star-count").innerHTML = stars;
document.getElementById("coin-count").innerHTML = coins;
document.addEventListener("DOMContentLoaded", function(e){
var body = document.querySelector("body");
var section = document.querySelector("section");
var articleLotto = document.querySelector(".lotto");
var articleBalls = document.querySelector(".balls");
var numbers = [];
var balls = document.getElementsByClassName("ball");
var drawnNums = [];
var chosenByMachine = [];
var board;
var boardEls;
function createNumberBoard(number){
console.log("I work");
numbers = [];
drawnNums = [];
chosenByMachine = [];
var board = document.createElement("div");
board.classList.add("board");
articleLotto.appendChild(board);
for( var i = 0; i<number; i ++){
var boardEl = document.createElement("button");
boardEl.classList.add("boardEl");
board.appendChild(boardEl);
}
var boardEls = document.getElementsByClassName("boardEl");
for( var i =0; i<boardEls.length; i++){
boardEls[i].setAttribute("data-number", i+1);
var dataNumber = boardEls[i].getAttribute("data-number");
var number = parseInt(dataNumber, 10);
numbers.push(number);
boardEls[i].textContent = number;
}
}
createNumberBoard(49);
board = document.querySelector(".board");
boardEls = document.querySelectorAll(".boardEl");
function drawNumbers(){
//boardEls.forEach(boardEl => boardEl.addEventListener("click", selectNums));
for (var i = 0; i<boardEls.length; i++){
boardEls[i].addEventListener("click", selectNums);
}
function selectNums(){
var number = parseInt(this.dataset.number, 10);
if(this.hasAttribute("data-number")){
drawnNums.push(number);
this.removeAttribute("data-number");
this.classList.add("crossedOut");
}
if(drawnNums.length=== 6){
//boardEls.forEach( boardEl => boardEl.removeAttribute("data-number"));
//boardEls.forEach(boardEl => boardEl.addEventListener("click", makeAlert));
for ( var i = 0; i<boardEls.length; i++){
boardEls[i].removeAttribute("data-number");
boardEls[i].addEventListener("click", makeAlert);
}
var startDraw = document.querySelector(".startDraw");
if(startDraw === null){ // you have to prevent creating the button if it is already there!
createButtonForMachineDraw();
} else {
return;
}
}
}
return drawnNums;
}
drawNumbers();
function makeAlert() {
var alertBox = document.createElement("div");
board.appendChild(alertBox);
alertBox.classList.add("alertBox");
alertBox.textContent = "You can only choose 6!";
setTimeout(function() {
alertBox.parentNode.removeChild(alertBox);
}, 1500);
}
function machineDraw(){
for( var i =0; i<6; i++){
var idx = Math.floor(Math.random() * numbers.length)
chosenByMachine.push(numbers[idx]);
/*a very important line of code which prevents machine from drawing the same number again
*/
numbers.splice(idx,1);
/* console.log(numbers) */
/*this line of code allows to check if numbers are taken out*/
}
var btnToRemove = document.querySelector(".startDraw");
btnToRemove.classList.add("invisible");
/* why not remove it entirely? because it might then be accidentally created if for some reason you happen to try to click on board!!! and you may do that*/
return chosenByMachine;
}
//machineDraw();
function createButtonForMachineDraw(){
var startDraw = document.createElement("button");
startDraw.classList.add("startDraw");
section.appendChild(startDraw);
startDraw.textContent ="Release the balls";
startDraw.addEventListener("click", machineDraw);
startDraw.addEventListener("click", compareArrays);
}
function compareArrays(){
for( var i =0; i<balls.length; i++) {
balls[i].textContent = chosenByMachine[i];
(function() {
var j = i;
var f = function(){
balls[j].classList.remove("invisible");
balls[j].classList.add("ball-align");
}
setTimeout(f, 1000*(j+1));
})();
}
var common =[];
var arr1 = chosenByMachine;
var arr2 = drawnNums;
for(var i = 0; i<arr1.length; i++){
for(var j= 0; j<arr2.length; j++){
if(arr1[i]===arr2[j]){
common.push(arr1[i]);
}
}
}
/* console.log(arr1, arr2, common) */; /* you can monitor your arrays in console*/
function generateResult(){
// Deduction of coins once draw started
coins = coins - 1;
// End of comment
var resultsBoard = document.createElement("article");
section.appendChild(resultsBoard);
var paragraph = document.createElement("p");
resultsBoard.appendChild(paragraph);
resultsBoard.classList.add("resultsBoard");
resultsBoard.classList.add("invisible");
if(common.length === 0){
paragraph.textContent ="Oh no! You got " + common.length + " Star!";
starsEarned = stars + common.length;
return starsEarned;
} else if(common.length === 1){
paragraph.textContent ="You got " + common.length + " Star!";
starsEarned = stars + common.length;
return starsEarned;
} else if(common.length === 2){
paragraph.textContent ="You got " + common.length + " Stars!";
starsEarned = stars + common.length;
return starsEarned;
} else if(common.length === 3) {
paragraph.textContent ="You got " + common.length + " Stars!";
starsEarned = stars + common.length;
return starsEarned;
} else if(common.length === 4){
paragraph.textContent ="You got " + common.length + " Stars!";
starsEarned = stars + common.length;
return ststarsEarnedars;
} else if(common.length === 5){
paragraph.textContent ="You got " + common.length + " Stars!";
starsEarned = stars + common.length;
return starsEarned;
}
else if(common.length===6){
paragraph.textContent ="A true winner! You got " + common.length + " Stars!";
stars = stars + common.length;
return starsEarned;
}
// Returning of new coins
return coins;
// End of comment
}
setTimeout(function() {
makeComebackBtn();
document.querySelector(".resultsBoard").classList.remove("invisible"); //well, you cannot acces this outside the code
// Displaying of new scores
stars = starsEarned;
document.getElementById("coin-count").innerHTML = coins;
document.getElementById("star-count").innerHTML = stars;
// End of comment
}, 8000);
generateResult();
}
function makeComebackBtn(){
var comebackBtn = document.createElement("a");
comebackBtn.classList.add("comebackBtn");
section.appendChild(comebackBtn);
comebackBtn.textContent ="Go again";
if (coins === 0) {
comebackBtn.addEventListener("click", function () {
alert("You ran out of coins");
});
} else {
comebackBtn.addEventListener("click", function () {
const board_ = document.querySelector(".board");
board_.parentNode.removeChild(board_);
const startDraw_ = document.querySelector(".startDraw");
startDraw_.parentNode.removeChild(startDraw_);
for( let i=0; i<balls.length; i++) {
balls[i].classList.add("invisible");
balls[i].classList.remove("ball-align");
}
const resultsBoard_ = document.querySelector(".resultsBoard");
resultsBoard_.parentNode.removeChild(resultsBoard_);
createNumberBoard(49);
board = document.querySelector(".board");
boardEls = document.querySelectorAll(".boardEl");
drawNumbers();
const comebackBtn_ = document.querySelector(".comebackBtn");
comebackBtn_.parentNode.removeChild(comebackBtn_);
});
}
}
})
You need to save the values of stars and coins to localStorage using localStorage.setItem("stars", stars) or sessionStorage and get the values again at beginning of each turn.
Also initialize value of variable starsEarned = 0 and check condition of number of coins when reload the page. If run out of coins, alert player.
You can see following code I modified from your
// Declaration of scores and lives
var stars = Number(localStorage.getItem("stars")) || 0;
var coins = Number(localStorage.getItem("coins")) || 5;
// End of comment
// For redeclaration in innerHTML
var starsEarned = 0;
// End of comment
// For displaying current score
document.getElementById("star-count").innerHTML = stars;
document.getElementById("coin-count").innerHTML = coins;
// End of comment
document.addEventListener("DOMContentLoaded", function(e){
var body = document.querySelector("body");
var section = document.querySelector("section");
var articleLotto = document.querySelector(".lotto");
var articleBalls = document.querySelector(".balls");
var numbers = [];
var balls = document.getElementsByClassName("ball");
var drawnNums = [];
var chosenByMachine = [];
function createNumberBoard(number){
console.log("I work");
var board = document.createElement("div");
board.classList.add("board");
articleLotto.appendChild(board);
for( var i = 0; i<number; i ++){
var boardEl = document.createElement("button");
boardEl.classList.add("boardEl");
board.appendChild(boardEl);
}
var boardEls = document.getElementsByClassName("boardEl");
for( var i =0; i<boardEls.length; i++){
boardEls[i].setAttribute("data-number", i+1);
var dataNumber = boardEls[i].getAttribute("data-number");
var number = parseInt(dataNumber, 10);
numbers.push(number);
boardEls[i].textContent = number;
}
}
createNumberBoard(49);
var board = document.querySelector(".board");
var boardEls = document.querySelectorAll(".boardEl");
function drawNumbers(){
//boardEls.forEach(boardEl => boardEl.addEventListener("click", selectNums));
for (var i = 0; i<boardEls.length; i++){
boardEls[i].addEventListener("click", selectNums);
}
function selectNums(){
var number = parseInt(this.dataset.number, 10);
if(this.hasAttribute("data-number")){
drawnNums.push(number);
this.removeAttribute("data-number");
this.classList.add("crossedOut");
}
if(drawnNums.length=== 6){
//boardEls.forEach( boardEl => boardEl.removeAttribute("data-number"));
//boardEls.forEach(boardEl => boardEl.addEventListener("click", makeAlert));
for ( var i = 0; i<boardEls.length; i++){
boardEls[i].removeAttribute("data-number");
boardEls[i].addEventListener("click", makeAlert);
}
var startDraw = document.querySelector(".startDraw");
if(startDraw === null){ // you have to prevent creating the button if it is already there!
createButtonForMachineDraw();
} else {
return;
}
}
}
return drawnNums;
}
drawNumbers();
function makeAlert() {
var alertBox = document.createElement("div");
board.appendChild(alertBox);
alertBox.classList.add("alertBox");
alertBox.textContent = "You can only choose 6!";
setTimeout(function() {
alertBox.parentNode.removeChild(alertBox);
}, 1500);
}
function machineDraw(){
for( var i =0; i<6; i++){
var idx = Math.floor(Math.random() * numbers.length)
chosenByMachine.push(numbers[idx]);
/*a very important line of code which prevents machine from drawing the same number again
*/
numbers.splice(idx,1);
/* console.log(numbers) */
/*this line of code allows to check if numbers are taken out*/
}
var btnToRemove = document.querySelector(".startDraw");
btnToRemove.classList.add("invisible");
/* why not remove it entirely? because it might then be accidentally created if for some reason you happen to try to click on board!!! and you may do that*/
return chosenByMachine;
}
//machineDraw();
function createButtonForMachineDraw(){
var startDraw = document.createElement("button");
startDraw.classList.add("startDraw");
section.appendChild(startDraw);
startDraw.textContent ="Release the balls";
startDraw.addEventListener("click", machineDraw);
startDraw.addEventListener("click", compareArrays);
}
function compareArrays(){
for( var i =0; i<balls.length; i++) {
balls[i].textContent = chosenByMachine[i];
(function() {
var j = i;
var f = function(){
balls[j].classList.remove("invisible");
balls[j].classList.add("ball-align");
}
setTimeout(f, 1000*(j+1));
})();
}
var common =[];
var arr1 = chosenByMachine;
var arr2 = drawnNums;
for(var i = 0; i<arr1.length; i++){
for(var j= 0; j<arr2.length; j++){
if(arr1[i]===arr2[j]){
common.push(arr1[i]);
}
}
}
/* console.log(arr1, arr2, common) */; /* you can monitor your arrays in console*/
function generateResult(){
// Deduction of coins once draw started
coins = coins - 1;
// End of comment
var resultsBoard = document.createElement("article");
section.appendChild(resultsBoard);
var paragraph = document.createElement("p");
resultsBoard.appendChild(paragraph);
resultsBoard.classList.add("resultsBoard");
resultsBoard.classList.add("invisible");
if(common.length === 0){
paragraph.textContent ="Oh no! You got " + common.length + " Star!";
starsEarned = stars + common.length;
return starsEarned;
} else if(common.length === 1){
paragraph.textContent ="You got " + common.length + " Star!";
starsEarned = stars + common.length;
return starsEarned;
} else if(common.length === 2){
paragraph.textContent ="You got " + common.length + " Stars!";
starsEarned = stars + common.length;
return starsEarned;
} else if(common.length === 3) {
paragraph.textContent ="You got " + common.length + " Stars!";
starsEarned = stars + common.length;
return starsEarned;
} else if(common.length === 4){
paragraph.textContent ="You got " + common.length + " Stars!";
starsEarned = stars + common.length;
return ststarsEarnedars;
} else if(common.length === 5){
paragraph.textContent ="You got " + common.length + " Stars!";
starsEarned = stars + common.length;
return starsEarned;
}
else if(common.length===6){
paragraph.textContent ="A true winner! You got " + common.length + " Stars!";
stars = stars + common.length;
return starsEarned;
}
// Returning of new coins
return coins;
// End of comment
}
setTimeout(function() {
makeComebackBtn();
document.querySelector(".resultsBoard").classList.remove("invisible"); //well, you cannot acces this outside the code
// Displaying of new scores
stars = starsEarned;
document.getElementById("coin-count").innerHTML = coins;
document.getElementById("star-count").innerHTML = stars;
localStorage.setItem("stars", stars);
localStorage.setItem("coins", coins);
// End of comment
}, 8000);
generateResult();
}
function makeComebackBtn(){
var comebackBtn = document.createElement("a");
comebackBtn.classList.add("comebackBtn");
section.appendChild(comebackBtn);
comebackBtn.textContent ="Go again";
if (coins === 0) {
comebackBtn.setAttribute("onClick", "alert('You ran out of coins')");
} else {
comebackBtn.setAttribute("onClick", "window.location.reload();");
}
}
})

Stop the audio player

I have an audio script with play/pause, I want to make the audio stop when I click on the square button at the left, and to add the timing to the right
here is the code: https://codepen.io/Amirafik/pen/YzxQZQw
HTML
<div class="title">
Dina Mohamed
</div>
<div class="stop"></div>
<div id="audioButton">
<div id="playerContainer">
<div class="listen">LISTEN</div>
</div>
</div>
<div class="duration">
00:12
</div>
<br>_____________________________________________________</br>
<div class="note">
<p>All items were more than perfect, we loved the experience and will order ONE OAK services again in the future for sure. <!--<span style="color:#F04E36"><br> Dina sent us an amazing feedback about her experience, tap the play button to listen to her cheerful words.</span></p>-->
</div
CSS
#import url('https://fonts.googleapis.com/css?family=montserrat:100,200,300,400,500,600,700,800,900');
body {
background: #ffffff;
color: #000000;
font-size: 16px ;
font-family: "montserrat" ;
font-weight: 500;
-webkit-tap-highlight-color: transparent;
}
a {
color: #F04E36;
}
.title {
max-width: 700px;
margin: 0 auto;
color: #000000;
font-weight:700;
display:inline-block;
}
.note {
max-width: 380px;
margin: 0 auto;
color: #000000;
display:inline-block;
}
.circle-audio-player {
cursor: pointer;
width:25px;
padding:0px;
margin-top:-67%;
margin-bottom:-50%;
margin-left:-7px;
background-color:#EDEBE7;
border-radius:50%;
vertical-align:middle;
}
#playerContainer {
padding: 0px;
vertical-align:middle;
}
#audioButton {
border-radius: 50px;
border: 2px solid #000000;
padding: 10px;
max-width: 85px;
height: 10px;
display: inline-block;
vertical-align:middle;
margin-left:2px;
}
.listen {
margin-left: 5px;
color: #000000;
font-weight:700;
display:inline-block;
float:right;
vertical-align:middle;
margin-top:-5%;
font-size: 14px ;
}
.stop {
max-width: 500px;
margin-left:10px;
height: 10px;
width: 10px;
background-color: #000000;
font-weight:500;
font-size: 14px ;
display:inline-block;
vertical-align:middle;
}
.duration {
max-width: 500px;
margin-left: 2px;
color: #000000;
font-weight:500;
font-size: 14px ;
display:inline-block;
}
JS
// settings
var DEFAULTS = {
borderColor: "#EDEBE7",
playedColor: "#F04E36",
backgroundColor: "#d3cdc2",
iconColor: "#000000",
borderWidth: 2,
size: 48,
className: 'circle-audio-player'
};
// reused values
var pi = Math.PI;
var doublePi = pi * 2;
var arcOffset = -pi / 2;
var animTime = 200;
var loaderTime = 1800;
var CircleAudioPlayer = function (options) {
options = options || {};
for (var property in DEFAULTS) {
this[property] = options[property] || DEFAULTS[property];
}
// create some things we need
this._canvas = document.createElement('canvas');
this._canvas.setAttribute('class', this.className + ' is-loading');
this._canvas.addEventListener('mousedown', (function () {
if (this.playing) {
this.pause();
}
else {
this.play();
}
}).bind(this));
this._ctx = this._canvas.getContext('2d');
// set up initial stuff
this.setAudio(options.audio);
this.setSize(this.size);
// redraw loop
(function cAPAnimationLoop (now) {
// check if we need to update anything
if (this.animating) {
this._updateAnimations(now);
}
if (this._forceDraw || this.playing || this.animating || this.loading) {
this._draw();
this._forceDraw = false;
}
requestAnimationFrame(cAPAnimationLoop.bind(this));
}).call(this, new Date().getTime());
};
CircleAudioPlayer.prototype = {
// private methods
_animateIcon: function (to, from) {
// define a few things the first time
this._animationProps = {
animStart: null,
from: from,
to: to
};
if (from) {
this.animating = true;
}
else {
this._animationProps.current = this._icons[to].slice();
this.draw();
}
},
_updateAnimations: function (now) {
this._animationProps.animStart = this._animationProps.animStart || now;
var deltaTime = now - this._animationProps.animStart;
var perc = (1 - Math.cos(deltaTime / animTime * pi / 2));
if (deltaTime >= animTime) {
this.animating = false;
perc = 1;
this._animationProps.current = this._icons[this._animationProps.to].slice();
this.draw();
}
else {
var from = this._icons[this._animationProps.from];
var current = [];
for (var i = 0; i < from.length; i++) {
current.push([]);
for (var j = 0; j < from[i].length; j++) {
current[i].push([]);
var to = this._icons[this._animationProps.to][i][j];
current[i][j][0] = from[i][j][0] + (to[0] - from[i][j][0]) * perc;
current[i][j][1] = from[i][j][1] + (to[1] - from[i][j][1]) * perc;
}
}
this._animationProps.current = current;
}
},
_draw: function (progress) {
// common settings
if (isNaN(progress)) {
progress = this.audio.currentTime / this.audio.duration || 0;
}
// clear existing
this._ctx.clearRect(0, 0, this.size, this.size);
// draw bg
this._ctx.beginPath();
this._ctx.arc(this._halfSize, this._halfSize, this._halfSize - (this.borderWidth / 2), 0, doublePi);
this._ctx.closePath();
this._ctx.fillStyle = this.backgroundColor;
this._ctx.fill();
// draw border
// our active path is already the full circle, so just stroke it
this._ctx.lineWidth = this.borderWidth;
this._ctx.strokeStyle = this.borderColor;
this._ctx.stroke();
// play progress
if (progress > 0) {
this._ctx.beginPath();
this._ctx.arc(this._halfSize, this._halfSize, this._halfSize - (this.borderWidth / 2), arcOffset, arcOffset + doublePi * progress);
this._ctx.strokeStyle = this.playedColor;
this._ctx.stroke();
}
// icons
this._ctx.fillStyle = this.iconColor;
if (this.loading) {
var loaderOffset = -Math.cos((new Date().getTime() % (loaderTime)) / (loaderTime) * pi) * doublePi - (pi / 3) - (pi / 2);
this._ctx.beginPath();
this._ctx.arc(this._halfSize, this._halfSize, this._halfSize / 3, loaderOffset, loaderOffset + pi / 3 * 2);
this._ctx.strokeStyle = this.iconColor;
this._ctx.stroke();
}
else {
this._ctx.beginPath();
var icon = (this._animationProps && this._animationProps.current) || this._icons.play;
for (var i = 0; i < icon.length; i++) {
this._ctx.moveTo(icon[i][0][0], icon[i][0][1]);
for (var j = 1; j < icon[i].length; j++) {
this._ctx.lineTo(icon[i][j][0], icon[i][j][1]);
}
}
// this._ctx.closePath();
this._ctx.fill();
// stroke to fill in for retina
this._ctx.strokeStyle = this.iconColor;
this._ctx.lineWidth = 2;
this._ctx.lineJoin = 'miter';
this._ctx.stroke();
}
},
_setState: function (state) {
this.playing = false;
this.loading = false;
if (state === 'playing') {
this.playing = true;
this._animateIcon('pause', 'play');
}
else if (state === 'loading') {
this.loading = true;
}
else if (this.state !== 'loading') {
this._animateIcon('play', 'pause');
}
else {
this._animateIcon('play', null);
}
this.state = state;
this._canvas.setAttribute('class', this.className + ' is-' + state);
this.draw();
},
// public methods
draw: function () {
this._forceDraw = true;
},
setSize: function (size) {
this.size = size;
this._halfSize = size / 2; // we do this a lot. it's not heavy, but why repeat?
this._canvas.width = size;
this._canvas.height = size;
// set icon paths
var iconSize = this.size / 2;
var pauseGap = iconSize / 10;
var playLeft = Math.cos(pi / 3 * 2) * (iconSize / 2) + this._halfSize;
var playRight = iconSize / 2 + this._halfSize;
var playHalf = (playRight - playLeft) / 2 + playLeft;
var top = this._halfSize - Math.sin(pi / 3 * 2) * (iconSize / 2);
var bottom = this.size - top;
var pauseLeft = this._halfSize - iconSize / 3;
var pauseRight = this.size - pauseLeft;
this._icons = {
play: [
[
[playLeft, top],
[playHalf, (this._halfSize - top) / 2 + top],
[playHalf, (this._halfSize - top) / 2 + this._halfSize],
[playLeft, bottom]
],
[
[playHalf, (this._halfSize - top) / 2 + top],
[playRight, this._halfSize],
[playRight, this._halfSize],
[playHalf, (this._halfSize - top) / 2 + this._halfSize]
]
],
pause: [
[
[pauseLeft, top + pauseGap],
[this._halfSize - pauseGap, top + pauseGap],
[this._halfSize - pauseGap, bottom - pauseGap],
[pauseLeft, bottom - pauseGap]
],
[
[this._halfSize + pauseGap, top + pauseGap],
[pauseRight, top + pauseGap],
[pauseRight, bottom - pauseGap],
[this._halfSize + pauseGap, bottom - pauseGap]
]
]
};
if (this._animationProps && this._animationProps.current) {
this._animateIcon(this._animationProps.to);
}
if (!this.playing) {
this.draw();
}
},
setAudio: function (audioUrl) {
this.audio = new Audio(audioUrl);
this._setState('loading');
this.audio.addEventListener('canplaythrough', (function () {
this._setState('paused');
}).bind(this));
this.audio.addEventListener('play', (function () {
this._setState('playing');
}).bind(this));
this.audio.addEventListener('pause', (function () {
// reset when finished
if (this.audio.currentTime === this.audio.duration) {
this.audio.currentTime = 0;
}
this._setState('paused');
}).bind(this));
},
appendTo: function (element) {
element.appendChild(this._canvas);
},
play: function () {
this.audio.play();
},
pause: function () {
this.audio.pause();
}
};
// now init one as an example
var cap = new CircleAudioPlayer({
audio: 'https://www.siriusxm.com/content/dam/sxm-com/audio/test/audio-previews/audio_test03.mp3.png',
size: 120,
borderWidth: 8
});
cap.appendTo(playerContainer);
You can simply use AudioElement.pause() to pause an running element, and the next AudioElement.play() will start from where you left off.
You can essentially set the currentTime property of the audio element to start from the beginning
A simple demonstration of how it works
const pause = document.getElementById('pause');
const stop = document.getElementById('stop');
const play = document.getElementById('play');
const container = document.getElementById('player');
const duration = document.getElementById('duration');
const audio = new Audio('https://www.siriusxm.com/content/dam/sxm-com/audio/test/audio-previews/audio_test03.mp3.png');
let played = 0;
let playing = true;
const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
run = async function () {
while(playing) {
if (played == Math.floor(audio.duration)) break;
duration.innerText = `${played} / ${Math.floor(audio.duration)}`;
played++;
await wait(1000);
}
}
container.appendChild(audio);
stop.addEventListener('click', () => {
duration.innerText = `0 / ${Math.floor(audio.duration)}`
audio.pause();
audio.currentTime = 0;
played = 0;
playing = false;
});
pause.addEventListener('click', () => {
audio.pause();
playing = false;
});
play.addEventListener('click', () => {
playing = true
audio.play();
run();
});
<div id="player"></div>
<div id="duration">0.0</div>
<button id="play">play</button>
<button id="stop">stop</button>
<button id="pause">pause</button>

Trouble with jquery mouse events

I am currently working on making a grid of squares for a tile map. I have it set up so clicking on a tile changes its state to explored from unexplored. I am attempting to have it so that dragging with the mouse down will change the state of all underlying tiles, however I can't seem to get it to work.
I have tried using mousedown and mouseup events to set a down boolean value which I then check inside of a mouseover. I have tried going about this in several ways (i.e. the commented out code). The current code will work for clicking but I really want to be able to do a drag to change multiples feature.
var tableString;
var width = 35;
var height = 15;
var cells = [];
var localX;
var localY;
function cell(x, y, c) {
positionX = x;
positionY = y;
category = c;
}
function createMap() {
for (var i = 0; i < height; i++) {
var row = [];
for (var j = 0; j < width; j++) {
let c = new cell();
c.category = "unexplored";
c.positionX = j;
c.positionY = i;
row.push(c);
}
cells.push(row);
}
}
function drawMap() {
tableString = "<table draggable='false'>";
for (var i = 0; i < height; i++) {
tableString += "<tr draggable='false'>";
for (var j = 0; j < width; j++) {
tableString += '<td draggable="false" class="' + cells[i][j].category + '" data-row="' + j + '" data-column="' + i + '"></td>';
}
tableString += "</tr>";
}
tableString += "</table>";
$("#mainContainer").html(tableString);
console.log("drew it");
}
function updateCellCategory(x, y, c) {
cells[x][y].category = c;
drawMap();
}
$(document).ready(function() {
createMap();
drawMap();
// var down = false;
// $(document,"td").mousedown(function () {
// down = true;
// })
// $(document,"td").mouseup(function () {
// down = false;
// });
// $(document,"td").on('mouseover','td',function () {
// if (down) {
// console.log("hovering and holding");
// localX = $(this).attr("data-row");
// localY = $(this).attr("data-column");
// updateCellCategory(localY, localX, "explored");
// }
// });
});
// $(document).on('mousedown',"td, documen",(function () {
// down = true;
// console.log(down);
// }));
// $(document).on('mouseup',"*",(function () {
// down = false;
// console.log(down);
// }));
// $(document).on('mouseover','td',function () {
// if (down) {
// console.log("hovering and holding");
// localX = $(this).attr("data-row");
// localY = $(this).attr("data-column");
// updateCellCategory(localY, localX, "explored");
// }
// });
$("*").delegate('td', 'click', function() {
localX = $(this).attr("data-row");
localY = $(this).attr("data-column");
updateCellCategory(localY, localX, "explored");
});
html,
body {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
}
#mainContainer {
max-width: 100%;
max-height: 90%;
width: 100%;
height: 90%;
display: flex;
align-items: center;
justify-content: center;
}
td {
width: 25px;
height: 25px;
border: .05px solid black;
}
.explored {
background-color: lightblue;
}
.unexplored {
background-color: lightcoral;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<div id="mainContainer">
</div>
</body>
</html>
The main issue I found when working on this is that some of the commented code works sometimes, but the second a drag event happens on a td the code breaks and the mouseup is not recognized causing the mouse cursur to continue affecting tiles even though the mouse was not held down.
OK. Using the click event is not what you want, since that involves pressing the mouse and releasing it.
Instead use, the mousemove, mousedown and mouseup events. Also, keep track of whether the mouse is down or not using a variable.
var tableString;
var width = 35;
var height = 15;
var cells = [];
var localX;
var localY;
var mouseDown = false;
function cell(x, y, c) {
positionX = x;
positionY = y;
category = c;
}
function createMap() {
for (var i = 0; i < height; i++) {
var row = [];
for (var j = 0; j < width; j++) {
let c = new cell();
c.category = "unexplored";
c.positionX = j;
c.positionY = i;
row.push(c);
}
cells.push(row);
}
}
function drawMap() {
tableString = "<table draggable='false'>";
for (var i = 0; i < height; i++) {
tableString += "<tr draggable='false'>";
for (var j = 0; j < width; j++) {
tableString += '<td draggable="false" class="' + cells[i][j].category + '" data-row="' + j + '" data-column="' + i + '"></td>';
}
tableString += "</tr>";
}
tableString += "</table>";
$("#mainContainer").html(tableString);
//console.log("drew it");
}
function updateCellCategory(x, y, c) {
cells[x][y].category = c;
drawMap();
}
$(document).ready(function() {
createMap();
drawMap();
});
$("*").on("mousedown", 'td', function()
{
mouseDown = true;
});
$(document).on("mouseup", function()
{
mouseDown = false;
});
$("*").on("mousemove", 'td', function()
{
if(!mouseDown)
return;
localX = $(this).attr("data-row");
localY = $(this).attr("data-column");
updateCellCategory(localY, localX, "explored");
});
html,
body {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
}
#mainContainer {
max-width: 100%;
max-height: 90%;
width: 100%;
height: 90%;
display: flex;
align-items: center;
justify-content: center;
}
td {
width: 25px;
height: 25px;
border: .05px solid black;
}
.explored {
background-color: lightblue;
}
.unexplored {
background-color: lightcoral;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<div id="mainContainer">
</div>
</body>
</html>
You can check whether or not the mouse is down using the event parameter of the event handler. Look at the last few lines of the snippet.
var tableString;
var width = 35;
var height = 15;
var cells = [];
var localX;
var localY;
function cell(x, y, c) {
positionX = x;
positionY = y;
category = c;
}
function createMap() {
for (var i = 0; i < height; i++) {
var row = [];
for (var j = 0; j < width; j++) {
let c = new cell();
c.category = "unexplored";
c.positionX = j;
c.positionY = i;
row.push(c);
}
cells.push(row);
}
}
function drawMap() {
tableString = "<table draggable='false'>";
for (var i = 0; i < height; i++) {
tableString += "<tr draggable='false'>";
for (var j = 0; j < width; j++) {
tableString += '<td draggable="false" class="' + cells[i][j].category + '" data-row="' + j + '" data-column="' + i + '"></td>';
}
tableString += "</tr>";
}
tableString += "</table>";
$("#mainContainer").html(tableString);
console.log("drew it");
}
function updateCellCategory(x, y, c) {
cells[x][y].category = c;
drawMap();
}
$(document).ready(function() {
createMap();
drawMap();
// var down = false;
// $(document,"td").mousedown(function () {
// down = true;
// })
// $(document,"td").mouseup(function () {
// down = false;
// });
// $(document,"td").on('mouseover','td',function () {
// if (down) {
// console.log("hovering and holding");
// localX = $(this).attr("data-row");
// localY = $(this).attr("data-column");
// updateCellCategory(localY, localX, "explored");
// }
// });
});
// $(document).on('mousedown',"td, documen",(function () {
// down = true;
// console.log(down);
// }));
// $(document).on('mouseup',"*",(function () {
// down = false;
// console.log(down);
// }));
// $(document).on('mouseover','td',function () {
// if (down) {
// console.log("hovering and holding");
// localX = $(this).attr("data-row");
// localY = $(this).attr("data-column");
// updateCellCategory(localY, localX, "explored");
// }
// });
$("*").delegate('td', 'mousedown', function() {
localX = $(this).attr("data-row");
localY = $(this).attr("data-column");
updateCellCategory(localY, localX, "explored");
});
$("*").delegate('td', 'mouseenter', function(event) {
if (event.buttons) {
localX = $(this).attr("data-row");
localY = $(this).attr("data-column");
updateCellCategory(localY, localX, "explored");
}
event.stopPropagation();
});
html,
body {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
}
#mainContainer {
max-width: 100%;
max-height: 90%;
width: 100%;
height: 90%;
display: flex;
align-items: center;
justify-content: center;
}
td {
width: 25px;
height: 25px;
border: .05px solid black;
}
.explored {
background-color: lightblue;
}
.unexplored {
background-color: lightcoral;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<div id="mainContainer">
</div>
</body>
</html>

stopping setTimeout loop in my snake game?

I've created a snake game, and when the snake hit the wall or itself, it still wont stop moving. I figured out if I used the clearTimeout(), it would help. but it didn't.
Is there a way to stop the loop? or it is another issue?
jQuery(document).ready(function($) {
init();
});
var move;
function init() {
board.initBoard();
drawSnake();
food.createFood();
}
function play() {
$('.newGame').css('visibility', 'hidden');
$('.playgame').css('visibility', 'hidden');
moveSnake();
getSnakeDir();
}
function gameover() {
clearTimeout(move);
$('.newGame').css('visibility', 'visible');
}
function playGame() {
$('#gameboard').empty();
$('.newGame').hide();
init();
play();
}
var board = {
DIM: 20,
initBoard: function() {
for (var i = 0; i < board.DIM; i++) {
var row = $('<div class="row-' + i + '"></div>');
for (var j = 0; j < board.DIM; j++) {
var col = ('<div class="col-' + j + '-' + i + '"></div>');
$(row).append(col);
}
$("#gameboard").append(row);
}
}
}
var snake = {
position: ['10-10', '10-11', '10-12'],
direction: 'r',
speed: 200,
};
function drawSnake() {
$('.col-10-10').addClass('snake');
$('.col-11-10').addClass('snake');
}
function getSnakeDir() {
$(document).keydown(function(event) {
//event.preventDefault();
if (event.which == 38) {
snake.direction = 'u';
} else if (event.which == 39) {
snake.direction = 'r';
} else if (event.which == 40) {
snake.direction = 'd';
} else if (event.which == 37) {
snake.direction = 'l';
}
});
}
function moveSnake() {
var tail = snake.position.pop();
$('.col-' + tail).removeClass('snake');
var coords = snake.position[0].split('-');
var x = parseInt(coords[0]);
var y = parseInt(coords[1]);
if (snake.direction == 'r') {
x = x + 1;
} else if (snake.direction == 'd') {
y = y + 1;
} else if (snake.direction == 'l') {
x = x - 1;
} else if (snake.direction == 'u') {
y = y - 1;
}
var currentcoords = x + '-' + y;
snake.position.unshift(currentcoords);
$('.col-' + currentcoords).addClass('snake');
//when snake eats food
if (currentcoords == food.coords) {
console.log('true');
$('.col-' + food.coords).removeClass('food');
snake.position.push(tail);
food.createFood();
}
//game over
if (x < 0 || y < 0 || x > board.DIM || y > board.DIM) {
gameover();
}
//if snake touch itself
if (hitItself(snake.position) == true) {
gameover();
}
move=setTimeout(moveSnake, 200);
}
var food = {
coords: "",
createFood: function() {
var x = Math.floor(Math.random() * (board.DIM-1)) + 1;
var y = Math.floor(Math.random() * (board.DIM-1)) + 1;
var fruitCoords = x + '-' + y;
$('.col-' + fruitCoords).addClass('food');
food.coords = fruitCoords;
},
}
function hitItself(array) {
var valuesSoFar = Object.create(null);
for (var i = 0; i < array.length; ++i) {
var value = array[i];
if (value in valuesSoFar) {
return true;
}
valuesSoFar[value] = true;
}
return false;
}
.buttonnewgame {
position: relative;
}
.newGame {
position: absolute;
top: 45%;
left: 25%;
padding: 15px;
font-size: 1em;
font-family: arial;
visibility: hidden;
}
.gameContainer{
width: 100%;
}
#gameboard {
background-color:#eee;
padding:3px;
}
.playgame {
position: absolute;
top: 45%;
left: 20%;
padding: 15px;
font-size: 1em;
font-family: arial;
}
/* styling the board */
div[class^='row'] {
height: 15px;
text-align: center;
}
div[class*='col']{
display: inline-block;
border: 1px solid grey;
width: 15px;
height: 15px;
}
/*display the snake*/
.snake {
background-color: blue;
z-index: 99;
}
.food {
background: red;
z-index: 99;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="game">
<div class="buttonnewgame">
<input type="button" name="new game" value="new game" class="newGame" onclick="playGame()" />
<button class="playgame" onclick="play()">Play Game</button>
<div class="gameContainer">
<div id="gameboard">
<!-- snake game in here -->
</div>
</div>
</div>
</div>
There were a few problems, but here is the 'working version' (there are more bugs).
1) I renamed drawSnake to createSnake. You weren't fully reinitializing the snake when you called init(). The snakes position was not being reset in the previous drawSnake method, so it would seem like the game was not playable.
After that there were 2 more bugs.
2) You have to return after you call gameOver or the game never really ends does it? Once you clear the timeout in gameover, you immediately set another Timeout for on the last line of moveSnake() because you didn't return once the game was over. That lead to weird results that made it seem like the game was unresponsive.
3) You were using a combination of visibility none or visible and $.hide(). $.hide() uses display: none, so when you tried to show it again with the visibility style change, its still display: none so the new game button would stop appearing.
My advice to any game coder is to learn how to separate the code that handles how the game works (logic of the game, how the clock ticks, initialization of game state, etc) , and how it is displayed (the html and css). Modeling the game logic after a cleanly written system is easy to read and debug. The code becomes harder to understand and modify when the display code is mixed in with game logic. In theory, our game should work perfectly without any kind of rendering. Then we could write a renderer that produces an HTML canvas, html DOM, text in the command line, or OpenGL.
Heres an old project I never finished that should illustrate a separation between model and view.
http://tando.us/ganix/ganix.htm
jQuery(document).ready(function($) {
init();
});
var move;
function init() {
board.initBoard();
createSnake();
food.createFood();
}
function play() {
$('.newGame').hide();
$('.playgame').hide();
moveSnake();
getSnakeDir();
}
function gameover() {
clearTimeout(move);
$('.newGame').show();
}
function playGame() {
$('#gameboard').empty();
$('.newGame').hide();
init();
play();
}
var board = {
DIM: 20,
initBoard: function() {
for (var i = 0; i < board.DIM; i++) {
var row = $('<div class="row-' + i + '"></div>');
for (var j = 0; j < board.DIM; j++) {
var col = ('<div class="col-' + j + '-' + i + '"></div>');
$(row).append(col);
}
$("#gameboard").append(row);
}
}
}
var snake = {
position: ['10-10', '10-11', '10-12'],
direction: 'r',
speed: 200,
};
function createSnake() {
$('.col-10-10').addClass('snake');
$('.col-11-10').addClass('snake');
snake.position = ['10-10', '10-11', '10-12'];
}
function getSnakeDir() {
$(document).keydown(function(event) {
//event.preventDefault();
if (event.which == 38) {
snake.direction = 'u';
} else if (event.which == 39) {
snake.direction = 'r';
} else if (event.which == 40) {
snake.direction = 'd';
} else if (event.which == 37) {
snake.direction = 'l';
}
});
}
function moveSnake() {
var tail = snake.position.pop();
$('.col-' + tail).removeClass('snake');
var coords = snake.position[0].split('-');
var x = parseInt(coords[0]);
var y = parseInt(coords[1]);
if (snake.direction == 'r') {
x = x + 1;
} else if (snake.direction == 'd') {
y = y + 1;
} else if (snake.direction == 'l') {
x = x - 1;
} else if (snake.direction == 'u') {
y = y - 1;
}
var currentcoords = x + '-' + y;
snake.position.unshift(currentcoords);
$('.col-' + currentcoords).addClass('snake');
//when snake eats food
if (currentcoords == food.coords) {
console.log('true');
$('.col-' + food.coords).removeClass('food');
snake.position.push(tail);
food.createFood();
}
//game over
if (x < 0 || y < 0 || x > board.DIM || y > board.DIM) {
gameover();
return;
}
//if snake touch itself
if (hitItself(snake.position) == true) {
gameover();
return;
}
move=setTimeout(moveSnake, 200);
}
var food = {
coords: "",
createFood: function() {
var x = Math.floor(Math.random() * (board.DIM-1)) + 1;
var y = Math.floor(Math.random() * (board.DIM-1)) + 1;
var fruitCoords = x + '-' + y;
$('.col-' + fruitCoords).addClass('food');
food.coords = fruitCoords;
},
}
function hitItself(array) {
var valuesSoFar = Object.create(null);
for (var i = 0; i < array.length; ++i) {
var value = array[i];
if (value in valuesSoFar) {
return true;
}
valuesSoFar[value] = true;
}
return false;
}
.buttonnewgame {
position: relative;
}
.newGame {
position: absolute;
top: 45%;
left: 25%;
padding: 15px;
font-size: 1em;
font-family: arial;
}
.gameContainer{
width: 100%;
}
#gameboard {
background-color:#eee;
padding:3px;
}
.playgame {
position: absolute;
top: 45%;
left: 20%;
padding: 15px;
font-size: 1em;
font-family: arial;
}
/* styling the board */
div[class^='row'] {
height: 15px;
text-align: center;
}
div[class*='col']{
display: inline-block;
border: 1px solid grey;
width: 15px;
height: 15px;
}
/*display the snake*/
.snake {
background-color: blue;
z-index: 99;
}
.food {
background: red;
z-index: 99;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="game">
<div class="buttonnewgame">
<input type="button" name="new game" value="new game" class="newGame" style="display:none;" onclick="playGame()" />
<button class="playgame" onclick="play()">Play Game</button>
<div class="gameContainer">
<div id="gameboard">
<!-- snake game in here -->
</div>
</div>
</div>
You could try not to initiate a new setTimeout call at the and of the moveSnake function, but instead using.
function play() {
$('.newGame').css('visibility', 'hidden');
$('.playgame').css('visibility', 'hidden');
move = setInterval(moveSnake, 200);
getSnakeDir();
}
and remove the
move = setTimeout(moveSnake, 200)
from the moveSnake function and do
function gameover() {
clearInterval(move);
$('.newGame').css('visibility', 'visible');
}

javascript settimeout takes too much time than expected to excute the code

I have tried to make the code works fine in stackoverflow but when I added the javascript code, it has stopped.any way
I have this code:
showCharacters("hey, how are you");
function showCharacters(text) {
var charactersArray = new String(text).split('');
var i;
for (i = 0; i < charactersArray.length; i++) {
setCharacter(i, charactersArray);
}
deleteAll(i - 1);
}
function setCharacter(i, charactersArray) {
setTimeout(function() {
document.getElementById("characters").innerHTML = document.getElementById("characters").innerHTML + charactersArray[i];
}, 1000 * i);
}
function deleteAll(i) {
setTimeout(function() {
var text = document.getElementById("characters").innerHTML;
var charactersArray = new String(text).split('');
var charactersArrayLength = charactersArray.length - 1;
for (var j = charactersArrayLength; j >= 0; j--) {
charactersArray.splice(j, 1);
deleteCharacter(charactersArray.join(""), i + charactersArrayLength - j + 1);
}
}, (i + 1) * 1000);
}
function deleteCharacter(text, i) {
setTimeout(function() {
document.getElementById("characters").innerHTML = text;
}, 1000 * i);
}
#divContainer {
display: flex;
align-items: center;
float: right;
}
#characters {
font-weight: 700;
color: rgb(0, 0, 0);
font-size: 40px;
padding-top: 2px;
white-space: nowrap;
}
<div id="divContainer">
<h1 id="characters">
</h1>
</div>
I made the code to write one character every second and after complete the text it will delete one character every second,the problem is that after complete the text it will wait for a few seconds before starting deleting the characters.I did not do that.
I have followed the time value of settimeout method and everything is fine.
I want it to start deleting characters directly after complete the text.
any help please.
Dont line up app the timeouts in a row do them one after the other.
Here is how you should do it. I speed the time up a bit, but that matters not.
var text = "Add a new timeout as needed."
var div = document.createElement("div");
document.body.appendChild(div);
var textPos = 0;
function textAdd(){
div.textContent += text[textPos++];
if(textPos >= text.length){
setTimeout(clearText,1000);
}else{
setTimeout(textAdd,200);
}
}
function clearText(){
textPos --;
div.textContent = text.substr(0,textPos);
if(textPos === 0){
setTimeout(textAdd,1000);
}else{
setTimeout(clearText,200);
}
}
textAdd();
I stayed close to your code, the fix was actually quite simple, I marked it with THE FIX below.
// Replace spaces with non-breaking spaces so it does not stutter, and use global var
var text = "hey, how are you".replace(/ /g, String.fromCharCode(160));
showCharacters();
function showCharacters() {
var chars = new String(text).split('');
var i;
for (i = 0; i < chars.length; i++) {
setCharacter(i, chars);
}
deleteAll(i - 1);
}
function setCharacter(i, chars) {
setTimeout(function() {
document.getElementById("characters").innerHTML = document.getElementById("characters").innerHTML + chars[i];
}, 200 * i);
}
function deleteAll(i) {
setTimeout(function() {
var chars = new String(text).split('');
var len = chars.length - 1;
for (var j = len; j >= 0; j--) {
chars.splice(j, 1);
deleteCharacter(chars.join(""), i - j + 1); // THE FIX: don't add length here
}
}, (i + 1) * 200);
}
function deleteCharacter(text, i) {
setTimeout(function() {
document.getElementById("characters").innerHTML = text;
}, 200 * i);
}
#divContainer {
display: flex;
align-items: center;
float: right;
}
#characters {
font-weight: 700;
color: rgb(0, 0, 0);
font-size: 40px;
padding-top: 2px;
white-space: nowrap;
}
<div id="divContainer">
<h1 id="characters">
</h1>
</div>

Categories

Resources