How would I make these animations animate at different times? - javascript

I'm making a whack-a-mole game and this is what I have so far, I'm aware this is sloppy and probably isn't the easiest/smartest way to do this. What I need to know is how to get my animations to animate at separate times. This current code works to animate 9 different moles coming out of holes but I need them to animate at different times(so none of them will come up at the same time, or within a few milliseconds of eachother) My current code is
<html>
<body>
<style type="text/css">
body, a, a:hover {cursor: url(http://cur.cursors-4u.net/others/oth-5/oth438.cur),
progress;}
</style>
<body background = "http://i52.tinypic.com/34e9ekj.jpg">
<b><center><font size="5"><div id='counter'>0</div></font></center><b>
<b><center><i>Whack-A-Mole</i> - by Steven</center></b>
<div
style="
top: 37;
left: 350;
position: absolute;
z-index: 1;
visibility: show;">
<center><img id='animation0' src ='http://i51.tinypic.com/sxheeo.gif'/></center>
</div>
<div
style="
top: 37;
left: 33;
position: absolute;
z-index: 1;
visibility: show;">
<left><img id='animation1' src ='http://i51.tinypic.com/sxheeo.gif'/></left>
</div>
<div
style="
top: 37;
left: 700;
position: absolute;
z-index: 1;
visibility: show;">
<right><img id='animation2' src ='http://i51.tinypic.com/sxheeo.gif'/></right>
</div>
<div
style="
top: 200;
left: 352;
position: absolute;
z-index: 1;
visibility: show;">
<img id='animation3' src ='http://i51.tinypic.com/sxheeo.gif'/>
</div>
<div
style="
top: 200;
left: 33;
position: absolute;
z-index: 1;
visibility: show;">
<img id='animation4' src ='http://i51.tinypic.com/sxheeo.gif'/>
</div>
<div
style="
top: 200;
left: 700;
position: absolute;
z-index: 1;
visibility: show;">
<img id='animation5' src ='http://i51.tinypic.com/sxheeo.gif'/>
</div>
<div
style="
top: 350;
left: 700;
position: absolute;
z-index: 1;
visibility: show;">
<img id='animation6' src ='http://i51.tinypic.com/sxheeo.gif'/>
</div>
<div
style="
top: 350;
left: 33;
position: absolute;
z-index: 1;
visibility: show;">
<img id='animation7' src ='http://i51.tinypic.com/sxheeo.gif'/>
</div>
<div
style="
top: 350;
left: 352;
position: absolute;
z-index: 1;
visibility: show;">
<img id='animation8' src ='http://i51.tinypic.com/sxheeo.gif'/>
</div>
</body>
<head>
<script type="text/javascript">
var urls;
function animate0(pos) {
pos %= urls.length;
var animation0 = document.getElementById('animation0');
var counter = document.getElementById('counter');
animation0.src = urls[pos];
if (pos == 1) { // only make onclick when have a certain image
animation0.onclick = function() {
counter.innerHTML = parseInt(counter.innerHTML) + 1;
}
}
else {
animation0.onclick = function() {
//do nothing
}
}
setTimeout(function() {
animate0(++pos);
}, (Math.random()*500) + 1000);
}
function animate1(pos) {
pos %= urls.length;
var animation1 = document.getElementById('animation1');
var counter = document.getElementById('counter');
animation1.src = urls[pos];
if (pos == 1) { // only make onclick when have a certain image
animation1.onclick = function() {
counter.innerHTML = parseInt(counter.innerHTML) + 1;
}
}
else {
animation1.onclick = function() {
//do nothing
}
}
setTimeout(function() {
animate1(++pos);
}, (Math.random()*500) + 1000);
}
function animate2(pos) {
pos %= urls.length;
var animation2 = document.getElementById('animation2');
var counter = document.getElementById('counter');
animation2.src = urls[pos];
if (pos == 1) { // only make onclick when have a certain image
animation2.onclick = function() {
counter.innerHTML = parseInt(counter.innerHTML) + 1;
}
}
else {
animation2.onclick = function() {
//do nothing
}
}
setTimeout(function() {
animate2(++pos);
}, (Math.random()*500) + 1000);
}
function animate3(pos) {
pos %= urls.length;
var animation3 = document.getElementById('animation3');
var counter = document.getElementById('counter');
animation3.src = urls[pos];
if (pos == 1) { // only make onclick when have a certain image
animation3.onclick = function() {
counter.innerHTML = parseInt(counter.innerHTML) + 1;
}
}
else {
animation3.onclick = function() {
//do nothing
}
}
setTimeout(function() {
animate3(++pos);
}, (Math.random()*500) + 1000);
}
function animate4(pos) {
pos %= urls.length;
var animation4 = document.getElementById('animation4');
var counter = document.getElementById('counter');
animation4.src = urls[pos];
if (pos == 1) { // only make onclick when have a certain image
animation4.onclick = function() {
counter.innerHTML = parseInt(counter.innerHTML) + 1;
}
}
else {
animation4.onclick = function() {
//do nothing
}
}
setTimeout(function() {
animate4(++pos);
}, (Math.random()*500) + 1000);
}
function animate5(pos) {
pos %= urls.length;
var animation5 = document.getElementById('animation5');
var counter = document.getElementById('counter');
animation5.src = urls[pos];
if (pos == 1) { // only make onclick when have a certain image
animation5.onclick = function() {
counter.innerHTML = parseInt(counter.innerHTML) + 1;
}
}
else {
animation5.onclick = function() {
//do nothing onclick
}
}
setTimeout(function() {
animate5(++pos);
}, (Math.random()*500) + 1000);
}
function animate6(pos) {
pos %= urls.length;
var animation6 = document.getElementById('animation6');
var counter = document.getElementById('counter');
animation6.src = urls[pos];
if (pos == 1) { // only make onclick when have a certain image
animation6.onclick = function() {
counter.innerHTML = parseInt(counter.innerHTML) + 1;
}
}
else {
animation6.onclick = function() {
//do nothing
}
}
setTimeout(function() {
animate6(++pos);
}, (Math.random()*500) + 1000);
}
function animate7(pos) {
pos %= urls.length;
var animation7 = document.getElementById('animation7');
var counter = document.getElementById('counter');
animation7.src = urls[pos];
if (pos == 1) { // only make onclick when have a certain image
animation7.onclick = function() {
counter.innerHTML = parseInt(counter.innerHTML) + 1;
}
}
else {
animation7.onclick = function() {
//do nothing
}
}
setTimeout(function() {
animate7(++pos);
}, (Math.random()*500) + 1000);
}
function animate8(pos) {
pos %= urls.length;
var animation8 = document.getElementById('animation8');
var counter = document.getElementById('counter');
animation8.src = urls[pos];
if (pos == 1) { // only make onclick when have a certain image
animation8.onclick = function() {
counter.innerHTML = parseInt(counter.innerHTML) + 1;
}
}
else {
animation8.onclick = function() {
//do nothing
}
}
setTimeout(function() {
animate8(++pos);
}, (Math.random()*500) + 1000);
}
window.onload = function() { //Frames go below, seperated by commas format= , "URL");
urls = new Array("http://i51.tinypic.com/sxheeo.gif", "http://i56.tinypic.com/2i3tyw.gif");
animate0(0);
animate1(0);
animate2(0);
animate3(0);
animate4(0);
animate5(0);
animate6(0);
animate7(0);
animate8(0);
}
</script>
</head>
</html>

Generate 9 random numbers between 0 and your start time variation. Decide the max distance you want between the animations and scale the random numbers to that time frame. Then, set 9 timers to those times from now so each timer starts an animation.
If you wanted the animations to start over 500 milliseconds, you'd do something like this:
var randomTimes = [9];
for (var i = 0; i < 9; i++) {
randomTimes[i] = Math.floor(Math.random() * 501);
}
Now you have 9 random times spread out over 500 milliseconds and you can use those values with setTimeout to start each animation at a random time.

Copy/pasting a function this way is indeed sloppy!
You need to setup a flag:
var isMole = false;//at first there is no mole
if(!isMole){
//there is no mole, you can show one here
isMole = true;//there is a mole now!
}else{
//there is a mole, we wait.
}
Now set that flag to false when the mole times out or it struck by a hammer!

Related

How to repeat randomised img endlessly on javascript?

I have a function that render random image without repeating, but it stops working when the array of images has come to an end, my goal is to restart function with another random order of images, so function can work infinite. I've read another questions, but didn't find something appropriate to me case.
Here is html part:
<div class="card">
<div class="front" onClick="pickimg();return false;"><img
src="1.jpg" alt=""></div>
<div class="back"><img src="2.jpg" name="randimg"></div>
</div>
Css (just in case):
.card {
width: 200px;
height: 300px;
position: relative;
perspective: 1000px;
cursor: pointer;
margin: 0 50px;
}
.front, .back {
width: 100%;
height: 100%;
position: absolute;
display: flex;
justify-content: center;
align-items: center;
transition: 1s;
backface-visibility: hidden;
border-radius: 10px;
}
.front {
transform: rotateY(360deg);
}
.back {
transform: rotateY(180deg);
}
And JS:
var cards = document.querySelectorAll('.card')
Array.from(cards).forEach(function(card) {
card.addEventListener('click', function() {
Array.from(card.querySelectorAll('.back, .front')).forEach(function(el) {
['back', 'front'].forEach(function(s) {
el.classList.toggle(s)
});
});
});
});
var usedImages = {};
var usedImagesCount = 0;
function pickimg(){
var imagenumber = 3;
var randomnumber = Math.random();
var rand1 = Math.round( (imagenumber-1) * randomnumber) + 1;
images = new Array();
images[0] = "";
images[1] = "3.jpg";
images[2] = "4.jpg";
images[3] = "2.jpg";
var image = images[rand1];
if (!usedImages[rand1]){
document.randimg.src = images[rand1];
usedImages[rand1] = true;
usedImagesCount++;
if (usedImagesCount === images.length){
usedImagesCount = 0;
usedImages = {};
}
} else {
pickimg();
}
}
Thank you for your help.
You could try something like this:
let img = [1,2,3,4,5];
function switchImage () {
for(; ; ){
let x = Math.random() * 10;
if(typeof img[Math.round(x)] !== 'undefined') {
img.splice(x, 1);
break;
}
}
console.log(img);
if (img.length > 0){
setTimeout(() => switchImage (),1000);
}
}
switchImage();
This is a simplified example where every second the function calls itself again and a new image is picked from the image array. The old image is cut out of the array and the function will stop calling itself when every picture is shown.
Try this -
int lastIndex = Math.round(Math.random()*(imagenumber - 1)) + 1;
function pickImg(){
let imagenumber = 3;
int currIndex = Math.round(Math.random()*(imagenumber - 1)) + 1;
images = new Array();
images[0] = "2.jpg";
images[1] = "3.jpg";
images[2] = "4.jpg";
if (lastIndex !== currIndex) {
document.randimg.src = images[currIndex];
lastIndex = currIndex;
}
else {
pickImg();
}
}
If you didn't get any image displayed that means you have to deal with when images[index] returns undefined.
Inshort you need to have index in images always equal to some value.
How about simple like this does this work for you? at least it will not give you same number a row
var imgArr = [1, 2, 3, 4, 5, 6] // imagine this is your img
var lastImgIndex;
function loadImg() {
var RandomIndex = Math.floor((Math.random() * imgArr.length) + 1);
if (lastImgIndex != RandomIndex) {
$('span').text(RandomIndex + ' index of img show');
lastImgIndex = RandomIndex;
} else {
loadImg();
}
}
loadImg();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span></span>

Make all div.obstacles have the same function

I am making a simple game that if the characters touch the "obstacle" which is another div the character that touches it will slow down while they are collided.
I already have a code for this, but it is only working for my .obstacle1 div even if I tried using jquery.each or I'm just missing something.
Here is the code which is working only for .obstacle1
HTML
<div class="field">
<div id="char1" class="characters character1">char1</div>
<div id="char2" class="characters character2">char2</div>
<div id="char3" class="characters character3">char3</div>
<div class="obstacles obstacle1">1</div>
<div class="obstacles obstacle2">2</div>
</div>
CSS
* {
padding: 0;
margin: 0;
}
.field-container {
overflow: scroll;
}
.field {
width: 1550px;
height: 700px;
border: 1px solid red;
position: relative;
}
.characters {
position: absolute;
width: 50px;
height: 50px;
transition: .1s ease-in-out;
}
.character1 {
background-color: blue;
top: 100px;
left: 0;
}
.character2 {
background-color: green;
top: 175px;
left: 0;
}
.character3 {
background-color: red;
top: 250px;
left: 0;
}
.obstacle1 {
height: 50px;
width: 50px;
background-color: lightblue;
position: absolute;
top: 200px;
left: 500px;
}
.obstacle2 {
height: 50px;
width: 50px;
background-color: lightblue;
position: absolute;
top: 120px;
left: 750px;
}
jQuery
$(document).ready(function(){
intervalCharacters = setInterval(function(){
moveChar();
},100);
function moveChar() {
$(".characters").each(function(){
move($(this));
});
}
/*--------------
OBSTACLES
---------------*/
var obstacle1 = $(".obstacles");
var obstacle1CurrentPosX = obstacle1.offset().left;
var obstacle1CurrentPosY = obstacle1.offset().top;
var obstacle1Height = obstacle1.outerHeight();
var obstacle1Width = obstacle1.outerWidth();
var totalY = obstacle1CurrentPosY + obstacle1Height;
var totalX = obstacle1CurrentPosX + obstacle1Width;
function checkIfCollidesChar(thisChar) {
var thisCharPosX = thisChar.offset().left;
var thisCharPosY = thisChar.offset().top;
var thisCharWidth = thisChar.outerWidth();
var thisCharHeight = thisChar.outerHeight();
var totalCharY = thisCharPosY + thisCharHeight;
var totalCharX = thisCharPosX + thisCharWidth;
if (totalY < thisCharPosY || obstacle1CurrentPosY > totalCharY || totalX < thisCharPosX || obstacle1CurrentPosX > totalCharX) {
return false;
console.log("FALSE");
} else {
return true
console.log("TRUE");
}
}
/* -----
move the characters
---- */
var moveFromLeft = 0;
var maxPosition = 1500;
function move(thisChar) {
var _this = thisChar;
var currentPosition = _this.offset().left;
var charSpeed = Math.floor(Math.random() * (10 - 0 + 1)) + 0;
if(checkIfCollidesChar(_this)) {
if(_this.offset().left > maxPosition) {
moveFromLeft = maxPosition;
}else{
moveFromLeft = currentPosition + (charSpeed*.25);
}
}else{
if(_this.offset().left > maxPosition) {
moveFromLeft = maxPosition;
}else{
moveFromLeft = currentPosition + charSpeed;
}
}
_this.css({
"left" : moveFromLeft,
});
if(moveFromLeft > maxPosition) {
checkIfFinish(_this);
_this.css({
"left" : maxPosition+"px",
});
}
_this.html(moveFromLeft);
}
});
Here is my fiddle.
Here's a fiddle with my suggested fix:
https://jsfiddle.net/40evn8pr/
The problem is that you're 'flattening' the obstacles jquery selection to a single value when you're directly asking for its offset/width/height. You should ask every element from the jquery selection what its offset is with an '$.each' loop to have every obstacle work.
$(document).ready(function(){
intervalCharacters = setInterval(function(){
moveChar();
},100);
function moveChar() {
$(".characters").each(function(){
move($(this));
});
}
var position = ["first","second","third"];
var counter = 0;
function checkIfFinish(thisChar) {
var position2 = position[counter];
counter++;
$(".result").append("<br>Position"+position2+ " counter" + counter + " : " + thisChar.attr("id"));
if(counter >= 3) {
clearInterval(interval);
}
}
/*--------------
OBSTACLES
---------------*/
var obstacle1 = $(".obstacles");
function checkIfCollidesChar(thisChar) {
var thisCharPosX = thisChar.offset().left;
var thisCharPosY = thisChar.offset().top;
var thisCharWidth = thisChar.outerWidth();
var thisCharHeight = thisChar.outerHeight();
var totalCharY = thisCharPosY + thisCharHeight;
var totalCharX = thisCharPosX + thisCharWidth;
var isCollision = false;
$.each(obstacle1, function(i, ob) {
var obstacle1CurrentPosX = $(ob).offset().left;
var obstacle1CurrentPosY = $(ob).offset().top;
var obstacle1Height = obstacle1.outerHeight();
var obstacle1Width = obstacle1.outerWidth();
var totalY = obstacle1CurrentPosY + obstacle1Height;
var totalX = obstacle1CurrentPosX + obstacle1Width;
if (!(totalY < thisCharPosY || obstacle1CurrentPosY > totalCharY || totalX < thisCharPosX || obstacle1CurrentPosX > totalCharX)) {
isCollision = true;
}
});
return isCollision;
}
/* -----
move the characters
---- */
var moveFromLeft = 0;
var maxPosition = 1500;
function move(thisChar) {
var _this = thisChar;
var currentPosition = _this.offset().left;
var charSpeed = Math.floor(Math.random() * (10 - 0 + 1)) + 0;
if(checkIfCollidesChar(_this)) {
if(_this.offset().left > maxPosition) {
moveFromLeft = maxPosition;
}else{
moveFromLeft = currentPosition + (charSpeed*.25);
}
}else{
if(_this.offset().left > maxPosition) {
moveFromLeft = maxPosition;
}else{
moveFromLeft = currentPosition + charSpeed;
}
}
_this.css({
"left" : moveFromLeft,
});
if(moveFromLeft > maxPosition) {
checkIfFinish(_this);
_this.css({
"left" : maxPosition+"px",
});
}
_this.html(moveFromLeft);
}
});
I think you are almost good. For your loop, you can use as model the
$(".characters").each(function(){
move($(this));
});
In your case, this would give :
$(".obstacles").each(function(){
var obstacle1 = $(this)
var obstacle1CurrentPosX = obstacle1.offset().left;
var obstacle1CurrentPosY = obstacle1.offset().top;
var obstacle1Height = obstacle1.outerHeight();
var obstacle1Width = obstacle1.outerWidth();
var totalY = obstacle1CurrentPosY + obstacle1Height;
var totalX = obstacle1CurrentPosX + obstacle1Width;
...
});

FadeIn with javascript without jquery

I have this code:
document.getElementById('showRtb').addEventListener('click', function () {
document.getElementById('rtb').style.display="inline-table";
});
document.getElementById('hideRtb').addEventListener('click', function () {
document.getElementById('rtb').style.display="none";
});
but now I want without jquery effect to make FadeIn animation, just with javascript. Without css3 and without jquery. Is that possible?
You can use setInterval(), getComputedStyle(). See also TheAnimationinterface
var rtb = document.getElementById("rtb"),
timer = null;
document.getElementById("showRtb").addEventListener("click", function() {
if (rtb.style.opacity != 1) {
clearTimeout(timer);
rtb.style.display = "inline-table";
timer = setInterval(function() {
rtb.style.opacity = +rtb.style.opacity + .10;
if (+getComputedStyle(rtb).getPropertyValue("opacity") >= 1) {
clearInterval(timer);
}
}, 100)
}
});
document.getElementById("hideRtb").addEventListener("click", function() {
if (rtb.style.opacity != 0) {
clearTimeout(timer);
timer = setInterval(function() {
rtb.style.opacity = +rtb.style.opacity - .10;
if (+getComputedStyle(rtb).getPropertyValue("opacity") <= 0) {
rtb.style.display = "none";
clearInterval(timer);
}
}, 100)
}
});
#rtb {
width: 100px;
height: 100px;
background: olive;
opacity: 0;
display: none;
}
<button id="showRtb">show</button>
<button id="hideRtb">hide</button>
<br>
<div id="rtb"></div>

How to set up "stop" after setInterval() method?

i have image gallery ant i set up setinterval, now i want that it should be stopped after two or tree circle.
This is my html Code:
<div id="slider">
<img src="http://imgsrc.hubblesite.org/hu/gallery/db/spacecraft/24/formats/24_web.jpg">
<img src="http://imgsrc.hubblesite.org/hu/gallery/db/spacecraft/27/formats/27_web.jpg">
<img src="http://imgsrc.hubblesite.org/hu/gallery/db/spacecraft/32/formats/32_web.jpg">
<img src="http://imgsrc.hubblesite.org/hu/gallery/db/spacecraft/33/formats/33_web.jpg">
</div>
css:
#slider {
width: 400px;
height: 300px;
position: relative;
overflow: hidden
}
#slider img {
position: absolute;
top: 0;
left: 0;
opacity: 0;
transition: 0.25s
}
and Javascript:
var pics;
var current = 0; // first next() moves to pics[0], the first image
window.addEventListener("load", function() {
pics = document.querySelectorAll("#slider img");
});
setInterval(function() {
var nextImage = (current + 1) % pics.length;
pics[current].style.opacity = 0;
pics[nextImage].style.opacity = 1;
current = nextImage;
}, 3000);
Here's your answer: Stop setInterval call in JavaScript
Save the interval ID when you create it, keep track of the number of times your slides have rotated, and then cancel the interval.
Use a counter variable to track the number of cycles & clear the timer based on that limit value.
JS Code:
var counter = 0;
var limit = 3 ;
var timer;
timer =setInterval(function () {
if(counter === 3){
clearInterval(timer);
return;
}
counter++;
//do some stuff here after 1 second delay
},1000);
You could use setTimeout instead.
var pics;
var current = 0; // first next() moves to pics[0], the first image
var stop = 3; //define when you want to stop
window.addEventListener("load", function() {
pics = document.querySelectorAll("#slider img");
});
function switchImage()
{
var nextImage = (current + 1) % pics.length;
pics[current].style.opacity = 0;
pics[nextImage].style.opacity = 1;
current = nextImage;
stop--;
if(stop != 0)
setTimeout(switchImage,3000);
}
setTimeout(switchImage,3000);
You can do like this.
var refreshIntervalId = setInterval(function() {
var nextImage = (current + 1) % pics.length;
pics[current].style.opacity = 0;
pics[nextImage].style.opacity = 1;
current = nextImage;
}, 3000);
clearInterval(refreshIntervalId);

Timer function not working correctly when stopped and started multiple times

First of all, you can find an example of my code in JS Fiddle and also below the question.
I'm working on a personal training webapp and basically you can hit play and then you get five minutes to do a series of tasks in a random order. The program creates the sessionTasks array in which are put in a random order tasks for the tasks array in order to fit the five minute limit. Right now the tasks array is just one I created with four tasks and the respective times just for testing.
The problem I ran into is the following: When you click the task so you can move forward to the next task, the next time you play seconds will move faster. The way I found to replicate is:
Click play.
Power through the tasks by clicking the task text very quickly.
Click play again.
Now the seconds should be moving quicker. If not, repeat what you just did. It is irregular but it usually does it in the second try.
I cannot for the life of me understand why it behaves like this. I thought that maybe it was creating more Timers that all used #taskTimer to run but that didn't make sense to me. Is it something wrong with the Timer function? What is wrong in my code?
mainMenu();
var totalSessionTasks, taskIterator, selectedTimeInSecs = 300;
var taskTimer = new Timer("#taskTimer", nextTask);
var globalTimer = new Timer("#globalTimer", function() {
});
var tasks = [
["First task", 0, 30],
["Second task", 0, 15],
["Third task", 0, 10],
["Fourth task", 3, 0]
];
var sessionTasks = [
]
function setUpSession() {
sessionTasks = []
if (tasks.length != 0) {
var sessionTasksSeconds = 0; //the seconds of the session being filled
var sessionTasksSecondsToFill = selectedTimeInSecs; //seconds left in the session to fill
var newTaskSeconds = 0; //seconds of the next task being added to the session
var sessionFull = false;
console.log('Session Empty');
while (sessionFull === false) {
var areThereAnyTaskThatFitInTheSession =
tasks.some(function(item) {
return ((item[1] * 60 + item[2]) <= sessionTasksSecondsToFill) && (item != sessionTasks[sessionTasks.length - 1]);
});
console.log(areThereAnyTaskThatFitInTheSession);
if (areThereAnyTaskThatFitInTheSession) {
do {
var randTaskNum = Math.floor(Math.random() * tasks.length);
} while (((tasks[randTaskNum][1] * 60 + tasks[randTaskNum][2]) > sessionTasksSecondsToFill) || (tasks[randTaskNum] == sessionTasks[sessionTasks.length - 1]))
sessionTasks.push(tasks[randTaskNum]);
newTaskSeconds = (tasks[randTaskNum][1]) * 60 + tasks[randTaskNum][2];
sessionTasksSecondsToFill -= newTaskSeconds;
sessionTasksSeconds += newTaskSeconds;
console.log(tasks[randTaskNum][0] + ": " + newTaskSeconds + "s");
console.log(sessionTasksSeconds)
} else if (sessionTasks.length == 0) {
note("All your tasks are too big for a game of " + selectedTimeInSecs / 60 + " minutes!");
break;
} else {
console.log('Session full');
sessionFull = true;
taskIterator = -1;
totalSessionTasks = sessionTasks.length;
console.log(totalSessionTasks);
globalTimer.set(0, sessionTasksSeconds);
nextTask();
globalTimer.run();
taskTimer.run();
}
}
} else {
note("You don't have have any tasks in your playlists!");
}
}
function nextTask() {
if (taskIterator + 1 < totalSessionTasks) {
taskIterator++;
$("#taskText").text(sessionTasks[taskIterator][0]);
globalTimer.subtract(0, taskTimer.getTotalTimeInSeconds())
taskTimer.set(sessionTasks[taskIterator][1], sessionTasks[taskIterator][2]);
$("#taskCounter").text(taskIterator + 1 + " of " + totalSessionTasks + " tasks");
} else {
mainMenu();
taskTimer.stop();
globalTimer.stop();
note("Thanks for playing!");
}
}
//timer object function
function Timer(element, callback) {
var ac, minutes, seconds, finalTimeInSeconds, displayMinutes, displaySeconds, interval = 1000,
self = this,
timeLeftToNextSecond = 1000;
this.running = false;
this.set = function(inputMinutes, inputSeconds) {
finalTimeInSeconds = inputMinutes * 60 + inputSeconds;
minutes = (Math.floor(finalTimeInSeconds / 60));
seconds = finalTimeInSeconds % 60;
this.print();
}
this.add = function(inputMinutes, inputSeconds) {
finalTimeInSeconds += inputMinutes * 60 + inputSeconds;
finalTimeInSeconds = (finalTimeInSeconds < 0) ? 0 : finalTimeInSeconds;
minutes = (Math.floor(finalTimeInSeconds / 60));
seconds = finalTimeInSeconds % 60;
this.print();
}
this.subtract = function(inputMinutes, inputSeconds) {
finalTimeInSeconds -= inputMinutes * 60 + inputSeconds;
if (finalTimeInSeconds <= 0) {
callback()
}
finalTimeInSeconds = (finalTimeInSeconds < 0) ? 0 : finalTimeInSeconds;
minutes = (Math.floor(finalTimeInSeconds / 60));
seconds = finalTimeInSeconds % 60;
this.print();
}
this.reset = function() {
this.set(0, 0);
}
this.print = function() {
displayMinutes = (minutes.toString().length == 1) ? "0" + minutes : minutes; //ternary operator: adds a zero to the beggining
displaySeconds = (seconds.toString().length == 1) ? "0" + seconds : seconds; //of the number if it has only one caracter.
$(element).text(displayMinutes + ":" + displaySeconds);
}
this.run = function() {
if (this.running == false) {
this.running = true;
var _f = function() {
secondStarted = new Date;
self.subtract(0, 1);
interval = 1000;
}
ac = setInterval(_f, interval);
}
}
this.stop = function() {
if (this.running == true) {
this.running = false;
console.log(this + "(" + element + ") was stopped");
stopped = new Date;
interval = 1000 - (stopped - secondStarted);
clearInterval(ac);
}
}
this.getTotalTimeInSeconds = function() {
return finalTimeInSeconds;
}
this.reset();
}
function note(string) {
alert(string);
}
function mainMenu() {
//EMPTY BODY
$("body").empty();
$("body").append(
//BUTTONS
"<div id='playButton' class='mainButton'><div class='buttonText mainButtonText'>PLAY</div></div>"
);
//BINDS
$("#playButton").bind("click", function(){
playMain();
setUpSession();
});
}
function playMain() {
//EMPTY BODY
$("body").empty();
$("body").append(
//TASK TEXT
"<p class='text' id='taskText'>Lorem ipsum dolor sit amet.</p>",
//TIMERS
"<div id='taskTimerWrap'><p class='text timer' id='taskTimer'>00:00</p><p class='text' id='taskTimerText'>Task Time</p></div>",
"<div id='globalTimerWrap'><p class='text timer' id='globalTimer'>00:00</p><p class='text' id='globalTimerText'>Global Time</p></div>",
//TASK COUNTER
"<div class='text' id='taskCounter'>0/0 tasks completed</div>"
);
//BINDS
$("#taskText").bind("click", nextTask);
}
#taskText {
text-align: center;
display: table;
vertical-align: middle;
height: auto;
width: 100%;
top: 50px;
bottom: 0;
left: 0;
right: 0;
position: absolute;
margin: auto;
font-size: 65px;
cursor: pointer;
}
#taskTimerWrap {
text-align: center;
top: 0;
right: 0;
left: 170px;
margin: 5px;
position: absolute;
-webkit-transition: all 0.5s ease;
}
.timer {
font-size: 64px;
margin: 0;
line-height: 0.88;
}
#taskTimerText {
font-size: 34.4px;
margin: 0;
line-height: 0.65;
}
#globalTimerWrap {
text-align: center;
top: 0;
left: 0;
right: 170px;
margin: 5px;
position: absolute;
}
#globalTimerText {
font-size: 28.5px;
margin: 0;
line-height: 0.78;
transform: scale(1, 1.2);
}
#taskCounter {
text-align: center;
bottom: 0;
right: 0;
left: 0;
width: auto;
position: absolute;
font-size: 30px;
color: #98D8D9;
-webkit-transition: all 0.5s ease;
}
#taskCounter:hover {
color: #F1F2F0
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
In Timer.stop() you change the interval that's used for the next run. Changing the interval variable in _f() isn't going to change the interval used by setInterval().
In this case you will have to use setTimeout() instead:
function Timer(element, callback) {
var ac, minutes, seconds, finalTimeInSeconds, displayMinutes, displaySeconds, timeout = 1000,
self = this,
timeLeftToNextSecond = 1000;
this.running = false;
/* ... */
this.run = function() {
if (this.running == false) {
this.running = true;
var _f = function() {
secondStarted = new Date;
self.subtract(0, 1);
ac = setTimeout(_f, 1000);
}
ac = setTimeout(_f, timeout);
}
}
this.stop = function() {
if (this.running == true) {
this.running = false;
console.log(this + "(" + element + ") was stopped");
stopped = new Date;
timeout = 1000 - (stopped - secondStarted);
clearTimeout(ac);
}
}
/* ... */
}
As I see, you are trying to set the value for variable interval from inside the interval callback function.
var _f = function() {
secondStarted = new Date;
self.subtract(0, 1);
//interval = 1000; REMOVE THIS LINE
}
interval = 1000; //ADD IT HERE
ac = setInterval(_f, interval);
Actually when setInterval is executed, the value for interval is not 1000. It's not updated by _f yet, because that function will run after the setInterval() is executed. And once setInterval() is called with the existing value of interval, changing it later has no impact on the created interval, because the setInterval() function has already set the delay time for the interval created. And the value for interval changes from it's initial value 1000 because of this line :
interval = 1000 - (stopped - secondStarted); //I'm not sure what you are trying to do with this, possibly removing this line will also fix your problem.)
Complete Working Demo:
And here is the JS Fiddle.
mainMenu();
var totalSessionTasks, taskIterator, selectedTimeInSecs = 300;
var taskTimer = new Timer("#taskTimer", nextTask);
var globalTimer = new Timer("#globalTimer", function() {
});
var tasks = [
["First task", 0, 30],
["Second task", 0, 15],
["Third task", 0, 10],
["Fourth task", 3, 0]
];
var sessionTasks = [
]
function setUpSession() {
sessionTasks = []
if (tasks.length != 0) {
var sessionTasksSeconds = 0; //the seconds of the session being filled
var sessionTasksSecondsToFill = selectedTimeInSecs; //seconds left in the session to fill
var newTaskSeconds = 0; //seconds of the next task being added to the session
var sessionFull = false;
console.log('Session Empty');
while (sessionFull === false) {
var areThereAnyTaskThatFitInTheSession =
tasks.some(function(item) {
return ((item[1] * 60 + item[2]) <= sessionTasksSecondsToFill) && (item != sessionTasks[sessionTasks.length - 1]);
});
console.log(areThereAnyTaskThatFitInTheSession);
if (areThereAnyTaskThatFitInTheSession) {
do {
var randTaskNum = Math.floor(Math.random() * tasks.length);
} while (((tasks[randTaskNum][1] * 60 + tasks[randTaskNum][2]) > sessionTasksSecondsToFill) || (tasks[randTaskNum] == sessionTasks[sessionTasks.length - 1]))
sessionTasks.push(tasks[randTaskNum]);
newTaskSeconds = (tasks[randTaskNum][1]) * 60 + tasks[randTaskNum][2];
sessionTasksSecondsToFill -= newTaskSeconds;
sessionTasksSeconds += newTaskSeconds;
console.log(tasks[randTaskNum][0] + ": " + newTaskSeconds + "s");
console.log(sessionTasksSeconds)
} else if (sessionTasks.length == 0) {
note("All your tasks are too big for a game of " + selectedTimeInSecs / 60 + " minutes!");
break;
} else {
console.log('Session full');
sessionFull = true;
taskIterator = -1;
totalSessionTasks = sessionTasks.length;
console.log(totalSessionTasks);
globalTimer.set(0, sessionTasksSeconds);
nextTask();
globalTimer.run();
taskTimer.run();
}
}
} else {
note("You don't have have any tasks in your playlists!");
}
}
function nextTask() {
if (taskIterator + 1 < totalSessionTasks) {
taskIterator++;
$("#taskText").text(sessionTasks[taskIterator][0]);
globalTimer.subtract(0, taskTimer.getTotalTimeInSeconds())
taskTimer.set(sessionTasks[taskIterator][1], sessionTasks[taskIterator][2]);
$("#taskCounter").text(taskIterator + 1 + " of " + totalSessionTasks + " tasks");
} else {
mainMenu();
taskTimer.stop();
globalTimer.stop();
note("Thanks for playing!");
}
}
//timer object function
function Timer(element, callback) {
var ac, minutes, seconds, finalTimeInSeconds, displayMinutes, displaySeconds, interval = 1000,
self = this,
timeLeftToNextSecond = 1000;
this.running = false;
this.set = function(inputMinutes, inputSeconds) {
finalTimeInSeconds = inputMinutes * 60 + inputSeconds;
minutes = (Math.floor(finalTimeInSeconds / 60));
seconds = finalTimeInSeconds % 60;
this.print();
}
this.add = function(inputMinutes, inputSeconds) {
finalTimeInSeconds += inputMinutes * 60 + inputSeconds;
finalTimeInSeconds = (finalTimeInSeconds < 0) ? 0 : finalTimeInSeconds;
minutes = (Math.floor(finalTimeInSeconds / 60));
seconds = finalTimeInSeconds % 60;
this.print();
}
this.subtract = function(inputMinutes, inputSeconds) {
finalTimeInSeconds -= inputMinutes * 60 + inputSeconds;
if (finalTimeInSeconds <= 0) {
callback()
}
finalTimeInSeconds = (finalTimeInSeconds < 0) ? 0 : finalTimeInSeconds;
minutes = (Math.floor(finalTimeInSeconds / 60));
seconds = finalTimeInSeconds % 60;
this.print();
}
this.reset = function() {
this.set(0, 0);
}
this.print = function() {
displayMinutes = (minutes.toString().length == 1) ? "0" + minutes : minutes; //ternary operator: adds a zero to the beggining
displaySeconds = (seconds.toString().length == 1) ? "0" + seconds : seconds; //of the number if it has only one caracter.
$(element).text(displayMinutes + ":" + displaySeconds);
}
this.run = function() {
if (this.running == false) {
this.running = true;
var _f = function() {
secondStarted = new Date;
self.subtract(0, 1);
//interval = 1000; REMOVE THIS LINE
}
interval = 1000; //ADD IT HERE
ac = setInterval(_f, interval);
}
}
this.stop = function() {
if (this.running == true) {
this.running = false;
console.log(this + "(" + element + ") was stopped");
stopped = new Date;
interval = 1000 - (stopped - secondStarted);
clearInterval(ac);
}
}
this.getTotalTimeInSeconds = function() {
return finalTimeInSeconds;
}
this.reset();
}
function note(string) {
alert(string);
}
function mainMenu() {
//EMPTY BODY
$("body").empty();
$("body").append(
//BUTTONS
"<div id='playButton' class='mainButton'><div class='buttonText mainButtonText'>PLAY</div></div>"
);
//BINDS
$("#playButton").bind("click", function(){
playMain();
setUpSession();
});
}
function playMain() {
//EMPTY BODY
$("body").empty();
$("body").append(
//TASK TEXT
"<p class='text' id='taskText'>Lorem ipsum dolor sit amet.</p>",
//TIMERS
"<div id='taskTimerWrap'><p class='text timer' id='taskTimer'>00:00</p><p class='text' id='taskTimerText'>Task Time</p></div>",
"<div id='globalTimerWrap'><p class='text timer' id='globalTimer'>00:00</p><p class='text' id='globalTimerText'>Global Time</p></div>",
//TASK COUNTER
"<div class='text' id='taskCounter'>0/0 tasks completed</div>"
);
//BINDS
$("#taskText").bind("click", nextTask);
}
#taskText {
text-align: center;
display: table;
vertical-align: middle;
height: auto;
width: 100%;
top: 50px;
bottom: 0;
left: 0;
right: 0;
position: absolute;
margin: auto;
font-size: 65px;
cursor: pointer;
}
#taskTimerWrap {
text-align: center;
top: 0;
right: 0;
left: 170px;
margin: 5px;
position: absolute;
-webkit-transition: all 0.5s ease;
}
.timer {
font-size: 64px;
margin: 0;
line-height: 0.88;
}
#taskTimerText {
font-size: 34.4px;
margin: 0;
line-height: 0.65;
}
#globalTimerWrap {
text-align: center;
top: 0;
left: 0;
right: 170px;
margin: 5px;
position: absolute;
}
#globalTimerText {
font-size: 28.5px;
margin: 0;
line-height: 0.78;
transform: scale(1, 1.2);
}
#taskCounter {
text-align: center;
bottom: 0;
right: 0;
left: 0;
width: auto;
position: absolute;
font-size: 30px;
color: #98D8D9;
-webkit-transition: all 0.5s ease;
}
#taskCounter:hover {
color: #F1F2F0
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Here is an update in jsfiddle
The problem is on the variable interval of Timer
This line creates unpredictable interval under Timer.stop():
interval = 1000 - (stopped - secondStarted);
If you would like to shorten the time interval, you can add a play_count property:
...
//timer object function
function Timer(element, callback) {
var ac, minutes, seconds, finalTimeInSeconds, displayMinutes, displaySeconds, interval = 1000,
self = this,
timeLeftToNextSecond = 1000;
this.running = false;
play_count = 0; // play count property
...
this.run = function() {
if (this.running == false) {
this.running = true;
var _f = function() {
secondStarted = new Date;
self.subtract(0, 1);
interval = Math.max(1000 - play_count * 100, 500); // ** <-- shorten time interval
}
ac = setInterval(_f, interval);
}
}
this.stop = function() {
if (this.running == true) {
this.running = false;
console.log(this + "(" + element + ") was stopped");
// stopped = new Date;
// interval = 1000 - (stopped - secondStarted);
play_count++;
clearInterval(ac);
}
}
this.getTotalTimeInSeconds = function() {
return finalTimeInSeconds;
}
this.reset();
}
...

Categories