Start a function from a loop but only once - javascript

Okay, so i am making a lobby function for an online 4 player game. Everything is set, and when all 4 players join the lobby, I want to start a countdown of 10 seconds for the players to click on accept match making on client side.(inspired from csgo)
I use ajax to call upon and refresh lobby data from a php file, so live statistics show up of who is in the lobby.
This goes in a loop, and here occurs the problem. I want the countdown function to be called when all 4 players have joined, and to stop it immediately if a player leaves, but as the parent function goes in a loop, (using set interval in javascript), it also repeatedly calls the countdown function.
Tried this, but does not help.
function loadlobbymodule(x){
var spl = x.split(",");
var lid = spl[1];
$.ajax({
url: 'inc/fn/lobbyload.php?lid='+ lid,
success: function(data) {
var spl = data.split(",");
var p1 = spl[0];
var p2 = spl[1];
var p3 = spl[2];
var p4 = spl[3];
var pl = spl[4];
var pleft = 4 - pl;
var p1_i = spl[5];
var p2_i = spl[6];
var p3_i = spl[7];
var p4_i = spl[8];
if(p1!=''){
$('#slot1').html('<img src="../../img/' + p1_i +'" width="100px" height="100px"><Br><br>' + p1);
} else{
$('#slot1').html('');
}
if(p2!=''){
$('#slot2').html('<img src="../../img/' + p2_i +'" width="100px" height="100px"><Br><br>' + p2);
}else{
$('#slot2').html('');
}
if(p3!=''){
$('#slot3').html('<img src="../../img/' + p3_i +'" width="100px" height="100px"><Br><br>' + p3);
}else{
$('#slot3').html('');
}
if(p4!=''){
$('#slot4').html('<img src="../../img/' + p4_i +'" width="100px" height="100px"><br><br>' + p4);
}else{
$('#slot4').html('');
}
$('#slotl').html(pleft + ' players left to join.');
if(pl == 4){
var accept = 1;
} else{
var accept = 0;
}
//alert(accept + ' sent');
accepto(accept);
}
});
}
function accepto(x){
//alert(x + ' reached');
if (x == 1){
if (!timeleft){
timeleft = 10;
var downloadTimer = setInterval(function(){
timeleft--;
$('.h3').html('All players joined. Accept in ' + timeleft + ' seconds');
if(timeleft <= 0)
clearInterval(downloadTimer);
},1000);
}
} else {
$('.h3').html('Waiting for players to join');
}
}setInterval(function(){loadlobbymodule(loll)}, 500);

Make the timer global and keep checking for active players
window.myGlobalTimer = yourTimer()
listening_PlayerThatLeave : ()=>{
clearTimeout(myGlobalTimer)
}
listening_AllPlayersIn : ()=>{
window.myGlobalTimer
}
/* dont keep making a new timeOut everytime , instead use the global var*/
function accepto(x){
//alert(x + ' reached');
if (x == 1){
if (!timeleft){
timeleft = 10;
//here
var downloadTimer = setInterval(function(){
timeleft--;
$('.h3').html('All players joined. Accept in ' + timeleft + ' seconds');
if(timeleft <= 0)
clearInterval(downloadTimer);
},1000);
}
} else {
$('.h3').html('Waiting for players to join');
}
}

Related

Issue linking images to dynamically created jquery elements

So, I'm very new, so apologies if this is a silly question. I have worked out a Trivia Quiz for my learning to code classes I'm taking. I want to display an image on the confirmation screen that shows whether the user was right or wrong. I think the code is correct-ish? I'm not sure what isn't working.
I left out the main Question and answer object for space. Sorry if I didn't format this ideally? I'm still kinda figuring out how things work here.
Here is my code for reference:
//array to help me iterate and insert images
var imgArray = ["question1", "question2", "question3", "question4", "question5", "question6", "question7", "question8", "question9", "question10", "question11", "question12", "question13"];
var currentQuestion = 0;
var win = 0;
var lose = 0;
var unanswered = 0;
var time = 30;
//set up divs to contain our info
var rightDiv = $("<div class='rightAns'></div>");
var timerDiv = $("<div class='countdown'><h3></h3></div>");
var questionDiv = $("<div class='question'><h1></h1></div><br>");
var answerDiv = $("<div class='answers'></div>");
//object keys to return questions in order
var keys = Object.keys(questions);
var key = keys[n];
var n = 0;
//function to setup and restart game
function reset() {
$("#start-button").hide("slow");
$("#start-here").hide("slow");
win = 0;
lose = 0;
unanswered = 0;
n = 0;
key = keys[n];
currentQuestion = 0;
$("#question-block").empty();
var reset = function () {
time = 30;
$(".rightAns").empty();
$(".rightAns").remove();
// $("#image").empty();
$("#time-remaining").append(timerDiv);
$(".countdown h3").html("Time Remaining: " + time);
$("#question-block").append(questionDiv);
$("#question-block").append(answerDiv);
}
reset();
//function to show questions
function showQuestion() {
$(".question h1").html(questions[key].question);
for (var i = 0; i < questions[key].answers.length; i++) {
$(".answers").append("<button class='answer btn btn-danger btn-lg m-1'>" + questions[key].answers[i] + "</button>");
}
$(".answers button").on("click", function () {
var selected = $(this).text();
//if then to check question correctness
if (selected === questions[key].correct) {
clearInterval(counter);
$(timerDiv).remove();
$(questionDiv).remove();
$(".answers button").remove();
$(answerDiv).remove();
$("#correct-answer").append(rightDiv);
$(".rightAns").text("That's Correct!!");
$("#image").html('<img src = ".assets/images/' + imgArray[currentQuestion] + '" width = "400px">');
win++;
currentQuestion++;
} else {
clearInterval(counter);
$(timerDiv).remove();
$(questionDiv).remove();
$(".answers button").remove();
$(answerDiv).remove();
$("#correct-answer").append(rightDiv);
$(".rightAns").text("Nope! The correct answer was: " + questions[key].correct);
$("#image").html('<img src = ".assets/images/' + imgArray[currentQuestion] + '" width = "400px">');
lose++;
currentQuestion++;
}
n++;
key = keys[n];
//checking to see if there are more questions left
if (checkForLast()) {
finalScore();
} else {
setTimeout(countReset, 3 * 1000);
setTimeout(reset, 3 * 1000);
setTimeout(showQuestion, 3 * 1000);
}
});
}
showQuestion();
var counter = setInterval(count, 1000);
//show time remaining for each question
function count() {
time--;
$(".countdown h3").html("Time Remaining: " + time);
if (time < 1) {
clearInterval(counter);
$(timerDiv).remove();
$(questionDiv).remove();
$(".answers button").remove();
$("#correct-answer").append(rightDiv);
$(".rightAns").html("You took too long! The correct answer was: " + questions[key].correct);
unanswered++;
n++;
key = keys[n];
if (checkForLast()) {
finalScore();
} else {
setTimeout(countReset, 3 * 1000);
setTimeout(reset, 3 * 1000);
setTimeout(showQuestion, 3 * 1000);
}
}
}
function checkForLast() {
if (key === undefined) {
return true;
}
return false;
}
//timer for the message after you choose your answer
function countReset() {
counter = setInterval(count, 1000);
}
//showthe final score screen
function finalScore() {
$(".rightAns").remove();
$("#image").empty();
$("#question-block").prepend("<h2>Unanswered: " + unanswered + "</h2>");
$("#question-block").prepend("<h2>Incorrect: " + lose + "</h2>");
$("#question-block").prepend("<h2>Correct: " + win + "</h2>");
$("#start-button").show();
$("#start-here").show();
}
};
//function to start game on button click
$(document).on("click", "#start-button", reset);
});
After tinkering for a bit, I dropped the "." at the beginning of the call and added the .jpg to the section after imgArray[currentQuestion]. That solved it. Thanks for the suggestions.

Why won't this clearInterval work?

I'm making a race where two images move to the right a random number of px's but they won't stop with the clear interval, the alert "stop" works. I'm using a red and green picture with changing z-indexes like a stoplight for the user to start and stop the race.
<script type="text/javascript">
var ship = 0;
var ufo = 0;
function random()
{
var rand = Math.floor((Math.random() * 15) + 1);
var rand2 = Math.floor((Math.random() * 15) + 1);
ship = ship + rand;
ufo = ufo + rand2;
document.getElementById("ufo").style.left = ufo + 'px';
document.getElementById("spaceship").style.left = ship + 'px';
}
function start()
{
if(document.getElementById("red").style.zIndex == 1)
{
document.getElementById("red").style.zIndex = "0";
alert("go");
var timer = setInterval(function() {random()},1000);
}
else
{
document.getElementById("green").style.zIndex = "0";
document.getElementById("red").style.zIndex = "1";
clearInterval(timer);
alert("stop");
}
}
</script>
Because var timer only exists within the if statement. You need to move it outside of the start() function, like this:
var timer;
function start()
{
if(document.getElementById("red").style.zIndex == 1)
{
document.getElementById("red").style.zIndex = "0";
alert("go");
timer = setInterval(function() {random()},1000);
}
else
{
document.getElementById("green").style.zIndex = "0";
document.getElementById("red").style.zIndex = "1";
clearInterval(timer);
alert("stop");
}
}

Failed to start countdown for the second time during operation

I am using the following code and giving a second click to the same start countdown button not clean the first process, so there are two counts at the same time. How do I stop the first process when the second start?
Thank you very much in advance.
function countdown(element, minutes, seconds) {
// Fetch the display element
var el = document.getElementById(element);
// Set the timer
var interval = setInterval(function() {
if(seconds == 0) {
if(minutes == 0) {
(el.innerHTML = "STOP!");
clearInterval(interval);
return;
} else {
minutes--;
seconds = 60;
}
}
if(minutes > 0) {
var minute_text = minutes + (minutes > 1 ? ' minutes' : ' minute');
} else {
var minute_text = '';
}
var second_text = seconds > 1 ? '' : '';
el.innerHTML = minute_text + ' ' + seconds + ' ' + second_text + '';
seconds--;
}, 1000);
}
//Start as many timers as you want
var start1 = document.getElementById('timer1');
var start2 = document.getElementById('timer2');
start1.onclick = function() {
countdown('countdown1', 0, 15);
}
start2.onclick = function() {
countdown('countdown2', 0, 10);
}
//extra button and counter
<div id='countdown1'></div>
<div id='countdown2'></div>
<input id="timer1" type="button" value="Start timer 1" />
<input id="timer2" type="button" value="Start timer 2" />
You could save the interval variable as an attribute of the countdown element. Then, at the beginning of the countdown function, check if the interval attribute has been defined for that element. If so, call clearInterval on it before starting a new interval.
clearInterval(intervalvalue)
will be helpful to .
Working code here

Javascript game - increment fires more than once

I am building simple "Spot the difference" game in jQuery/HTML. There are 5 rounds/stages, each with different pictures and user needs to go through all of them starting from round 1.
I am having this issue with increment firing twice when I am in 2nd round, and then triple times when I am in 3rd round and so on. This cause points to jump up double/triple/... instead of just jump up by 1.
The code is on baby level. I did not make any stuff to refactor it and improve.
I think I don't need to provide HTML for this, as simply looking at logic in JS file should be enough.
For those who prefer pastebin version is here (http://pastebin.com/ACqafZ5G). Full code:
(function(){
var round = 1;
var points = 0;
var pointsTotal = 0;
var pointsDisplay = $(".js-calc");
var pointsTotalDisplay = $(".js-calc-total");
var counterDisplay = $(".js-counter");
var entryPage = $(".entry-page");
var mainMenu = $(".main-menu");
var submitNow = $(".js-now");
var submitResultsFinalBtn = $(".js-submit-results-final");
// rounds-categories
var allRounds = $(".round");
var divRound1 = $(".round1"),
divRound2 = $(".round2"),
divRound3 = $(".round3"),
divRound4 = $(".round4"),
divRound5 = $(".round5");
var allPic = $(".js-pic");
var pic1 = $(".js-pic1"),
pic2 = $(".js-pic2"),
pic3 = $(".js-pic3"),
pic4 = $(".js-pic4"),
picFinish = $(".js-finish");
// on the beginning hide all and leave only entry page
mainMenu.hide();
allRounds.hide();
submitResultsFinalBtn.hide();
// countdown (SEE THE FUNCTION ON THE END)
var myCounter = new Countdown({
seconds: 60, // number of seconds to count down
onUpdateStatus: function(sec){
counterDisplay.html(sec); // display seconds in html
}, // callback for each second
onCounterEnd: function(){
console.log('TIME IS OVER!');
// THIS SHOULD NOT BE HERE, I WOULD PREFER TO MOVE IT SOMEWHERE TO GAME ITSELF
pointsTotalDisplay.html(pointsTotal);
round++; // update to next round
allRounds.hide(); // hide window
mainMenu.show(); // show back again main menu
} // final action
});
var initiateRound = $(".js-initiate");
initiateRound.on("click", function(){ // START GAME
console.log("ROUND " + round + " INITIATED");
points = 0; // reset the points for this round to 0 - not sure this is the way to do it...
console.log(points + " points for this round, " + pointsTotal + " in TOTAL"); // say how many points so far
entryPage.hide();
mainMenu.hide();
allPic.hide();
if( round === 1){
divRound1.show();
pic1.show();
}else if( round === 2){
divRound2.show();
pic2.show();
}else if( round === 3){
divRound3.show();
pic3.show();
}else if( round === 4){
divRound4.show();
pic4.show();
}else if( round === 5){
divRound5.show();
picFinish.show();
initiateRound.hide();
submitNow.hide();
submitResultsFinalBtn.show();
}
counterDisplay.html("60"); //display 60sec on the beginning
myCounter.start(); // and start play time (countdown)
// pointsDisplay.html(points); // display in HTML amount of points for particular round
// if user start collecting points, add them
var mapImage = $('.transparent AREA');
mapImage.each(function(index) {
// When clicked, reveal red circle with missing element
$(this).one("click", function(e) { // YOU CAN CLICK ONLY ONCE!! Using .one() to prevent multiple clicks and eventually scoring more points
e.stopPropagation();
console.log("FIRED");
var theDifference = '#'+$(this).attr('id')+'-diff';
$(theDifference).css('display', 'inline');
if ($(theDifference).data('clicked', true)){ // found circle
// points++;
points += 1;
pointsTotal++;
console.log(points + " points for this round, " + pointsTotal + " in TOTAL");
pointsDisplay.html(points); // display in html amount of points
}
if (points === 6){ // if all points collected (max 6) for this round
myCounter.stop(); // stop countdown
console.log("time stopped, you found all");
setTimeout(function(){ // give him 2sec delay to see last circle marked
allRounds.hide(); // hide window
mainMenu.show(); // show back again main menu
console.log("round " + round + " is finished");
round++; // update to next round
console.log("round " + round + " is activated");
pointsTotalDisplay.html(pointsTotal); // display in HTML total amount of pints
}, 2000);
};
});
});
});
})();
function Countdown(options) {
var timer,
instance = this,
seconds = options.seconds || 10,
updateStatus = options.onUpdateStatus || function () {},
counterEnd = options.onCounterEnd || function () {};
function decrementCounter() {
updateStatus(seconds);
if (seconds === 0) {
counterEnd();
instance.stop();
}
seconds--;
}
this.start = function () {
clearInterval(timer);
timer = 0;
seconds = options.seconds;
timer = setInterval(decrementCounter, 1000);
};
this.stop = function () {
clearInterval(timer);
};
}
Are you sure you're not stacking the $('.transparent AREA') from a round to another ?
This would explain why you score multiple times:
var mapImage = $('.transparent AREA');
mapImage.each(function(index) {
// ...
points++;
// ...
});
Solved!
mapImage.each should be outside of initiateRound

Countdown timer for use in several places at same page

I want to make a countdown timer, that can be used on several places in the same page - so I think it should be a function in some way.
I really want it to be made with jQuery, but I cant quite make it happen with my code. I have e.g. 10 products in a page, that I need to make a countdown timer - when the timer is at 0 I need it to hide the product.
My code is:
$(document).ready(function(){
$(".product").each(function(){
$(function(){
var t1 = new Date()
var t2 = new Date()
var dif = t1.getTime() - t2.getTime()
var Seconds_from_T1_to_T2 = dif / 1000;
var Seconds_Between_Dates = Math.abs(Seconds_from_T1_to_T2);
var count = Seconds_Between_dates;
var elm = $(this).attr('id');
alert(elm);
countdown = setInterval(function(){
$(elm + " .time_left").html(count + " seconds remaining!");
if (count == 0) {
$(this).css('display','none');
}
count--;
}, 1000);
});
});
});
EDIT 1:
$(document).ready(function(){
$(".product").each(function(){
var elm = $(this).attr('id');
$(function(){
var t1 = new Date()
var t2 = new Date()
var dif = t1.getTime() - t2.getTime()
var Seconds_from_T1_to_T2 = dif / 1000;
var Seconds_Between_Dates = Math.abs(Seconds_from_T1_to_T2);
var count = Seconds_Between_dates;
alert(elm);
countdown = setInterval(function(){
$(elm + " .time_left").html(count + " seconds remaining!");
if (count == 0) {
$(this).css('display','none');
}
count--;
}, 1000);
});
});
});
Do you have any solutions to this?
I'd probably use a single interval function that checks all the products. Something like this:
$(function() {
/* set when a product should expire.
hardcoded to 5 seconds from now for demonstration
but this could be different for each product. */
$('.product').each(function() {
$(this).data('expires', (new Date()).getTime() + 5000);
});
var countdown_id = setInterval(function() {
var now = (new Date()).getTime();
$('.product').each(function() {
var expires = $(this).data('expires');
if (expires) {
var seconds_remaining = Math.round((expires-now)/1000);
if (seconds_remaining > 0) {
$('.time-left', this).text(seconds_remaining);
}
else {
$(this).hide();
}
}
});
}, 1000);
});
You could also cancel the interval function when there is nothing left to expire.
Your problem seems to be that this doesn't refer to the current DOM element (from the each), but to window - from setTimeout.
Apart from that, you have an unnecessary domReady wrapper, forgot the # on your id selector, should use cached references and never rely on the timing of setInterval, which can be quite drifting. Use this:
$(document).ready(function(){
$(".product").each(function(){
var end = new Date(/* from something */),
toUpdate = $(".time_left", this);
prod = $(this);
countDown();
function countdown() {
var cur = new Date(),
left = end - cur;
if (left <= 0) {
prod.remove(); // or .hide() or whatever
return;
}
var sec = Math.ceil(left / 1000);
toUpdate.text(sec + " seconds remaining!"); // don't use .html()
setTimeout(countdown, left % 1000);
}
});
});

Categories

Resources