How to kill setInterval() inside Vue Js instance - javascript
I have a problem with a countdown function I've created for an idiotic fight game I'm developing as an assignment.
I have the following method:
/* Countdown timer before fight */
startTimer() {
this.countDownPanel = true;
if (this.countDownNumbers > 0) {
this.countDown = setInterval(() => {
this.countDownNumbers--;
}, 1000);
this.textDownsizer = setInterval(() => {
this.countDownTextSize--;
}, 10);
}
},
And the following watcher that stops the countdown:
/* Countdown Watcher */
countDownNumbers() {
this.countDownTextSize = 100;
if (this.countDownNumbers < 0) {
clearInterval(this.textDownsizer);
this.textDownsizer = null;
clearInterval(this.countDown);
this.countDown = null;
this.countDownPanel = false;
}
}
},
The problem is that even after I use the clearInterval() through the Vue DevTools I can see the timer still running until countDownNumbers reaches 0. But the case is that it happens a while after the actual numbers on the screen are down to 0. And when I reset the game, running the same instance, the countdown goes nuts and causes a memory leak. Is there a better way of doing it?
Here's the complete Js code:
new Vue({
el: '#app',
data: {
gameStatus: 'disclaimer', //Status of the app, it can be (so far) 'disclaimer', 'startScreen', 'playStage', 'looseScreen', 'wonScreen', 'menuScreen'
backgroundAudio: new Array(), //Array of current playing background sounds
blurFilter: true, //Blur shown at the start of the app
audioTracks: ["sound/battle.mp3", "sound/dungeon.wav", "sound/echo.ogg"], //List of file in the folder 'sound'
playList: new Array(), //Array with a collection of Audio objects that are playable
/*
The health points function in an inverse way. The subject dies when it reaches 100
The health bar div width % is calculated subtracting the current health of the avatar of 100.
*/
healthHuman: 0,
healthComputer: 0,
muted: false, //Obviously determines if the audio is activated or not
humanStatus: true, //Defines if the human player is dead or alive
computerStatus: true, //Defines if the computer player is dead or alive
/* Collection of string that are outputed when a avatar dies */
humanDiesPhrases: [
"You've just been killed and that's why you're seeing your own life flash in front of you.",
"It's almost as if your soul has taken over your body in a frantic attempt to preserve the memory of what you love.",
"The problem is that when your soul leaves your body, it's physically incapable of going back in and if it doesn't try to go back in and make the same decision, it could start experiencing the same things all over again.",
"That was sad and gruesome and an almost poetic way. Anyway, you're dead. The rats are anxious to eat your remains.",
"Looks like the monster will be eating something besides rats today",
"Woow! That must have hurted! Dude! Are you okay? Dude? Dude... Ohh, you're dead. Sorry about that",
"Your death looks like an abstract painting. To me, not for you. For you that must have hurted like hell.",
"Yep! Looks like you're dead. Can I have your sowrd?",
"You died! Was killed to be more exact. Now your opponent drags you to one of many dark pits inside the dungeon.",
"Oh my god, how can you suck in such idiotic game? I know that the game is lame, but you just raised the bar fella.",
"You're not very good at this are you? Have you ever considered trying gardening?"
],
computerDiesPhrases: [
"You've just killed it! Or should I say him? Or her? You didn't ask, did you? How considerate of you.",
"GG mah boy, keep it like this and I'm sure you're going places. Maybe...",
"Wow that was 2 minutes less of your life, how does it feel? You're not having those back... Are you still reading?",
"Oh my, my... Why such violence? Have you considered petting it? Maybe it was just saying hello. Weirdo.",
"Well, it's dead. Now what? Are you going to eat it? Of course not silly, this is just a game. Back to being productive",
"AM I being nosy or you should be doind something else instead? I mean, killing virtual monsters?",
"Good kill dude! But, have you considered that it maybe was the last of its kind? That's disturbing.",
"You've just killed the creature! Good for you girl!",
"Wait! Have you considered trying to... Forget it, it's dead already",
"Oh man! (or woman!). That was gruesome. Wait a minute, have you just farted? Ewww! Ohh sorry, that one was mine.",
"Why did you do that? Such violence. Well you killed it, just like that. That's aliens haven't made contact with us yet...Savage!"
],
humanParts: [
"groin", "left eye", "upper lip", "right ear", "left leg", "tiny finger", "balls", "right knee", "face", "head", "lung", "chest", "chin", "middle finger", "you know where", "neck", "nose", "foot", "ribs", "teeth",
],
monsterParts: [
"center most tentacle", "foremost tooth", "tiny tentacle", "lady parts", "boy parts", "gum", "ass", "iris", "eyeball", "feelings", "wise tooth"
],
fightingMovements: [
"bite", "slapped", "punched", "kicked", "headbutted", "scratched", "hit", "punctured", "fingered", "poundded", "bashed"
],
countDownNumbers: 5, //Countdown counter =)
countDown: '', //Stores the main countdown
countDownTextSize: 100, //Obvious
textDownsizer: '', //Stores the timer responsible to downsize the font of the countdown
logger: new Array(), //Array responsible for storing all messages that will be shown to the player
countDownPanel: false, //Determines if the countdown is to be shown or not
},
computed: {
/* Unset the blur when the disclaimer modal goes away */
flipBlur() {
if (this.gameStatus != 'disclaimer') {
return this.blurFilter = false;
} else {
return true;
}
},
},
watch: {
//Wacth the gameStatus and make changes accordingly
gameStatus() {
//Background Audio Controler
//Tracks
echoSound = this.playList['echo'];
battleSound = this.playList['battle'];
dungeonSound = this.playList['dungeon'];
//Game status DJ
if (this.gameStatus == 'startScreen') {
this.loopPlay(echoSound);
this.loopPlay(dungeonSound);
} else if (this.gameStatus == 'playStage') {
//Add battle song to the background
this.loopPlay(battleSound);
battleSound.volume = 0.25;
//Trigger the coundown
this.startTimer();
}
},
muted() {
if (this.muted == true) {
this.backgroundAudio.forEach(element => {
element.pause();
});
} else {
this.backgroundAudio.forEach(element => {
element.play();
});
}
},
/* Health checkers // Killer */
healthHuman() {
if (this.healthHuman >= 100) {
this.healthHuman = 100;
this.humanStatus = false;
this.humanDied();
}
},
healthComputer() {
if (this.healthComputer >= 100) {
this.healthComputer = 100;
this.computerStatus = false;
this.computerDied();
}
},
/* Logger Wachter - Maintain only the last 3 elements of the logger */
logger() {
if (this.logger.length > 3) {
this.logger.pop();
}
},
/* Countdown Watcher */
countDownNumbers() {
this.countDownTextSize = 100;
if (this.countDownNumbers < 0) {
clearInterval(this.textDownsizer);
this.textDownsizer = null;
clearInterval(this.countDown);
this.countDown = null;
this.countDownPanel = false;
}
}
},
beforeDestroy() {
clearInterval(this.textDownsizer);
},
created: function () {
this.buildPlayList();
},
methods: {
/* Background soundtracks and sound effects */
loopPlay(audioTrack) {
if (audioTrack) {
audioTrack.play();
audioTrack.loop = true;
this.backgroundAudio.push(audioTrack);
}
},
buildPlayList() {
this.audioTracks.forEach(element => {
trackName = element.substring(element.indexOf('/') + 1);
trackName = trackName.substring(0, trackName.indexOf('.'));
this.playList[trackName] = new Audio(element);
});
},
/*
HP monitoring and controller
These two functions return the css property 'width' of the health bars.
*/
heartMonitorHuman() {
return {
width: this.healthHuman + '%'
}
},
heartMonitorComputer() {
return {
width: this.healthComputer + '%'
}
},
/* Generates random hit points */
hitGenerator() {
var hit = Math.round(Math.random() * 20);
return hit;
},
/* Controlls the timer before the fight */
counterFontSize() {
return {
'fontSize': this.countDownTextSize + 'vw'
}
},
/* Hits the human */
hitHuman() {
if (this.healthHuman < 100) {
var willHitPoints = Math.floor(this.hitGenerator() * 1.1); //Gives the monster 10% more attack power on average
this.healthHuman += willHitPoints;
this.logHandler('You got ' + this.randomFightingMoves() + ' on the ' + this.humanHitDesc() + ' and lost ' + willHitPoints + ' HP');
} else {
this.humanDied();
}
},
/* Hits the computer */
hitComputer() {
if (this.healthComputer < 100 && this.countDownNumbers <= 0) {
var willHitPoints = this.hitGenerator();
this.healthComputer += willHitPoints;
this.logHandler('You ' + this.randomFightingMoves() + ' the monster\'s ' + this.monsterHitDesc() + ' and it lost ' + willHitPoints + ' HP');
//Hits the human player back
this.hitHuman();
} else {
this.computerDied();
}
},
/* Shows phrases regarding the avatar's deaths */
humanDied() {
if (this.humanStatus == false) {
var deathMessage = Math.round(Math.random() * 10);
this.logHandler(this.humanDiesPhrases[deathMessage]);
this.logHandler("You died!");
setTimeout(() => {
this.resetGame();
}, 3000);
}
},
computerDied() {
if (this.computerStatus == false) {
var deathMessage = Math.round(Math.random() * 10);
this.logHandler(this.computerDiesPhrases[deathMessage]);
this.logHandler("You win?");
setTimeout(() => {
this.resetGame();
}, 3000);
}
},
/* Generates a random key to be used with a dictionary of log messages */
keyGen() {
return '_' + Math.random().toString(36).substr(2, 9);
},
/* Creates a dictionary with all log messages generated by the app */
logHandler(msg) {
var newLog = {
id: this.keyGen(),
message: msg,
};
this.logger.unshift(newLog);
},
/* Random hits generators */
humanHitDesc() {
randomNumber = Math.floor(Math.random() * 20);
return this.humanParts[randomNumber];
},
monsterHitDesc() {
randomNumber = Math.floor(Math.random() * 10);
return this.monsterParts[randomNumber];
},
randomFightingMoves() {
randomNumber = Math.floor(Math.random() * 10);
return this.fightingMovements[randomNumber];
},
resetGame() {
this.logger = [];
this.healthHuman = 0;
this.humanStatus = true;
this.healthComputer = 0;
this.computerStatus = true;
this.countDownNumbers = 5;
this.startTimer();
},
/* Countdown timer before fight */
startTimer() {
this.countDownPanel = true;
if (this.countDownNumbers > 0) {
this.countDown = setInterval(() => {
this.countDownNumbers--;
}, 1000);
this.textDownsizer = setInterval(() => {
this.countDownTextSize--;
}, 10);
}
},
}
});
The GitHub repo is: https://github.com/Saiuke/MonsterSlayer
Here's a screen capture of the game:
edited: sorry for the mistake. its fixed now.
Have you tried changing if (this.countDownNumbers < 0) to if (this.countDownNumbers === 0)? That might work. If that does not work then why not just make a simple countdown like this:
let num = 10;
let timer = setInterval(function(){
num = num - 1;
console.log(num);
if(num <= 0){
clearInterval(timer);
}
},1000);
The main issue is that startTimer() does not stop any existing timers before starting new ones. And since startTimer() is indirectly invoked by the user (i.e., humanDied() -> resetGame() -> startTimer(), computerDied() -> resetGame() -> startTimer(), or gameStatus change -> startTimer()), multiple timers can be started unpredictably.
The solution is to stop any existing timers before starting new ones, and to move the expiration logic from the countdownTimer watcher into startTimer():
export default {
watch: {
countDownNumbers() {
this.countDownTextSize = 100;
// XXX: DON'T DO THIS HERE
// if (this.countDownNumbers < 0) {
// clearInterval(this.textDownsizer);
// this.textDownsizer = null;
// clearInterval(this.countDown);
// this.countDown = null;
// this.countDownPanel = false;
// }
}
},
methods: {
startTimer() {
clearInterval(this.countDown);
this.countDown = null;
clearInterval(this.textDownsizer);
this.textDownsizer = null;
if (this.countDownNumbers > 0) {
this.countDown = setInterval(() => {
this.countDownNumbers--;
if (countDownNumbers <= 0) {
this.countDownPanel = false;
}
}, 1000);
this.textDownsizer = setInterval(() => {
this.countDownTextSize--;
}, 10);
}
}
}
}
you can do by this way it is so easy. this code is compatible with Vue-Js 3.
...... youe code......
,mounted() {
this.intervalId = setInterval(this.callStatusFn, 200)
console.log("intervalId "+ this.intervalId)
},
unmounted() {
clearInterval(this.intervalId)
}
Related
How does phone tracking work in the Just Dance?
The Just Dance Now app uses the phone's accelerometer, then the coordinates are sent to your platform and the game compares the coordinates with those recorded in files and gives you an answer as to how well you performed the movement: perfect, super, good, ok or bad. I tried to do the same, I wrote a code that at a certain time records my coordinates that are transmitted via the websocket - in a JSON file. Here is my code: var playerCurrentPosition = { x: 0, y: 0 } var ws = *WebSocket* ws.onmessage = (data) => { data = JSON.parse(data.data); if (data.function == `playerPosition`) { playerCurrentPosition.x = Math.abs(Math.floor(data.positin.x)); playerCurrentPosition.y = Math.abs(Math.floor(data.position.y)); } } videoplayer.onplay = function () { startCheckMoves() } videoplayer.play() var recordedMoves = { "moballyougottachn_intro_hi": { "x": 12, "y": 1 } } var moves = [{ "time": 1500, "duration": 1000, "name": "moballyougottachn_intro_hi" }] var movesc = 0; function recordMoves() { setInterval(() => { if (moves[movesc]) { if (moves[movesc].time + moves[movesc].duration <= videoplayer.currentTime * 1000) { if (!recordedMoves[moves[movesc].name]) { recordedMoves[moves[movesc].name] = { x: playerCurrentPosition.x, y: playerCurrentPosition.y } } movesc++; } } else { clearInterval(this) } }) } function startCheckMoves() { setInterval(() => { if (moves[movesc]) { if (recordedMoves[moves[movesc].name]) { if (moves[movesc].time + moves[movesc].duration <= videoplayer.currentTime * 1000) { console.clear() if (_GetTheDifference(playerCurrentPosition.x, recordedMoves[moves[movesc].name].x, 3)) { console.log("PERFECT") } else if (_GetTheDifference(playerCurrentPosition.x, recordedMoves[moves[movesc].name].x, 4)) { console.log("SUPER") } else if (_GetTheDifference(playerCurrentPosition.x, recordedMoves[moves[movesc].name].x, 5)) { console.log("GOOD") } else if (_GetTheDifference(playerCurrentPosition.x, recordedMoves[moves[movesc].name].x, 6)) { console.log("OK") } function _GetTheDifference(num, num2, elp) { return Math.abs(num - num2) < elp; } movesc++; } } } else { clearInterval(this) } }) } Then, when I test the recorded coordinates and repeat the same movements - my code says that I repeated it incorrectly, I also see that the coordinates are much different from the recorded ones, although the time of checking and the time of recording the movement are the same. In the application files, I tried to find how the comparison system and the coordinate determination system work, but the library is used there jdScoring.so which I can't use in any way. How can I try to record and compare coordinates correctly? I haven't been able to find an answer for several months, I hope at least for some help on this forum, thank you all in advance.
Dynamically creating oscillators causes memory issues in p5 Sound
Within my code (the code below is a very shortened version), I am creating oscillators (https://p5js.org/reference/#/p5.Oscillator) in draw. Eventually the audio starts crackling and being all weird, and I assume this is because the oscillators aren't being garbage collected? When looking at the Memory tab in Inspect Element, it continously goes up, and the audio goes crackly eventually. I tried to dereference the oscillators using the two functions in my disconnect variable/function. This sets the oscillator to null after a specific amount of time I hope. I wasn't sure how to set a reference argument to null. Maybe the p5 sound library still keeps references for them? function createOsc(grid) { let osc = new p5.Oscillator(); if (grids[grid].type == 1) { osc.setType("triangle"); } else if (grids[grid].type == 2) { osc.setType("sawtooth"); } else if (grids[grid].type == 3) { osc.setType("square"); } return osc; } function createEnv(grid) { let env = new p5.Envelope(); env.set(grids[grid].ADSR.attack, grids[grid].vol, grids[grid].ADSR.decay, grids[grid].ADSR.sustain * grids[grid].vol, grids[grid].ADSR.release, 0); return env; } let disconnect = { list: [], osc: function(osc, time) { this.list.push([osc, time, 0]); }, update: function() { for (i = 0; i < this.list.length; i++) { this.list[i][2] += 1 / 60.0; if (this.list[i][2] >= this.list[i][1]) { this.list[i][0].a.disconnect(); this.list[i][0].a = null; this.list.splice(i, 1); i += -1; } } } } function draw() { let osc = createOsc(0); let env = createEnv(0); osc.start(); osc.freq(420); env.triggerAttack(osc); env.triggerRelease(osc, env.aTime + env.dTime); osc.stop(env.aTime + env.dTime + env.rTime); disconnect.osc({a: osc}, env.aTime + env.dTime + env.rTime); } I attempted to use the PolySynth (https://p5js.org/reference/#/p5.PolySynth) object, but I couldn't figure out how to change the waveforms or anything due to lack of clear documentation. Edit: This new standalone code produces the same crackling audio after a while. I am also now using Millis() as suggested. Same issue with memory constantly increasing. let disconnect = { list: [], osc: function(osc, time) { this.list.push([osc, time, millis()]); }, update: function() { for (i = 0; i < this.list.length; i++) { if (millis() - this.list[i][2] >= this.list[i][1]) { this.list[i][0].a.disconnect(); this.list[i][0].a = null; this.list.splice(i, 1); i += -1; } } } } function createOsc() { let osc = new p5.Oscillator(); osc.setType("triangle"); return osc; } function createEnv() { let env = new p5.Envelope(); env.set(0.1, 1, 0.1, 0.8, 0.1, 0); return env; } function setup() { frameRate(60); } function draw() { disconnect.update(); print(disconnect.list.length); if (frameCount % 2 == 0) { let osc = createOsc(); let env = createEnv(); osc.start(); osc.freq(420); env.triggerAttack(osc); env.triggerRelease(osc, 0.2); osc.stop(0.3); disconnect.osc({a: osc}, 300); } }
Set up a pause/resume-able timer in javascript
Is there a way to create a "timer"(or stopwatch) class, that the timers created using this class can be paused and resumed on triggering an event, e.g. clicking a button? I tried to create the class and create timer objects using it, but the timer cannot be paused once it starts. My attempt on creating this class: class countdown { constructor(min, sec) { this.mins = min; this.secs = sec; this.handler = 0; } static setTimer(x,minfield,secfield) { this.handler = setTimeout(() => { if (x.mins == 0 && x.secs == 0) { clearTimeout(); } else { if (x.secs == 0) { x.mins -= 1; x.secs = 59; } else { x.secs -= 1; } } this.updateTimer(x,minfield,secfield); this.setTimer(x,minfield,secfield) }, 1000) } static updateTimer(x,minfield, secfield){ document.getElementById(minfield).innerHTML = x.mins; document.getElementById(secfield).innerHTML = x.secs; } static stopTimer(x,minfield,secfield) { // document.getElementById(minfield).innerHTML = x.mins; // document.getElementById(secfield).innerHTML = x.secs; clearTimeout(x.handler); } } Usage: let countdown1 = new countdown(15,0); let countdown_act = false; document.getElementById('button').addEventListener( 'click', () => { if (!countdown_act) { countdown.setTimer(countdown1, 'ctdwn-mins', 'ctdwn-secs'); countdown_act = true; } else { countdown.stopTimer(countdown1, 'ctdwn-mins', 'ctdwn-secs'); countdown_act = false; } console.log(countdown_act); } ) The countdown_act flag is used for indicating the state of the timer.
There's no need for any of your methods to be static. Also, it's much simpler and easier to use if you just record seconds and then calculate minutes when you need the output. As a standard, capitalize the name of classes. Finally, you're probably looking for setInterval, not timeout. Think of a real-world timer. You can set it, start it, pause it, and stop it. Stopping a timer is really just restarting it and pausing it, and it's set upon creation, so let's make a Timer with start, pause, set and stop or reset. This still behaves the same way as yours in the background by using a 1s timeout, but it's a lot cleaner and easier for someone reading your code to understand: class Timer { constructor(seconds, callback) { this.originalTime = seconds; this.remainingTime = seconds; this.timeout = null; this.callback = callback; // This is what the timer does when it ends } start() { this.timeout = setInterval(() => { this.remainingTime -= 1; // Remove a second from the timer if(this.remainingTime === 0) { this.callback(); // Run the callback function this.stop(); // Stop the timer to prevent it from counting into the negatives } }, 1000); } pause() { clearInterval(this.timeout); } stop() { this.pause(); this.remainingTime = this.originalTime; // Reset the time } setTime(seconds) { this.originalTime = seconds; // Set a new time this.stop(); // Have to restart the timer to account for the new time } get remaining() { return { seconds: this.remainingTime % 60, minutes: Math.floor(this.remainingTime / 60) } } }
Javascript pausing timer woes... Can't calculate it
I've built a series of timers that are designed to be started, paused and resumed on cue. Numbers update dynamically on my page when the timer ticks up. The issue I'm having is figuring out how to get the timer to start from where it left off before I paused it. I can get it to restart from scratch, but I unsure how to take the paused Date.now() value, and work it into the formula to display the correct value. It will be something stupid that I just cant figure out. function ticking2(num) { //IF TIMER IS PAUSED CANCEL THE ANIMATION FRAME if (timerObjArray[num].paused == true) { timerObjArray[num].restartTime = Date.now(); cancelAnimationFrame(id); } else if (timerObjArray[num].paused == false) { timerObjArray[num].initialTime = Date.now() if (timerObjArray[num].restartTime != 0) { //THIS IS THE LINE WHERE I AM HAVING TROUBLE timerObjArray[num].milli = ((timerObjArray[num].initialTime - timerObjArray[num].initialDate) - (timerObjArray[num].initialTime - timerObjArray[num].restartTime)) / 1000; } else { timerObjArray[num].milli = ((timerObjArray[num].initialTime - timerObjArray[num].initialDate ) / 1000); } //THIS FUNCTION TAKES THE MS VALUE AND CONVERTS IT TO HH:MM:SS convert(num, timerObjArray[num].milli * 1000); id = requestAnimationFrame(function() { ticking2(num); }); } } Thanks for the help.
I don't have enough information so, I made a simple implementation. You can look at this to help determine what you're missing. You're welcome to use it. Timer fiddle Utility: var timer = (function() { let _timers = {}; let pub = { start : function(id) { if(!_timers[id]) _timers[id] = {on:true, intervals:[{start:new Date()}] }; else if(_timers[id].on) throw 'timer is already started: ' + id; else { _timers[id].on = true; _timers[id].intervals.push({start:new Date()}); } }, stop : function(id) { if(!_timers[id]) throw 'timer does not exist, cannot be stopped: ' + id; else if(!_timers[id].on) throw 'timer is already stopped: ' + id; else { _timers[id].on = false; let interval = _timers[id].intervals[_timers[id].intervals.length -1]; interval.stop = new Date(); interval.total = interval.stop - interval.start; } }, read : function(id) { if(!_timers[id]) throw 'timer does not exist, cannot be read: ' + id; let total = 0; for(let i=0; i<_timers[id].intervals.length; i++) { if(_timers[id].intervals[i].total) total += _timers[id].intervals[i].total; else total += (new Date()) - _timers[id].intervals[i].start; } return { intervals:_timers[id].intervals, total: total }; }, delete: function(id) { if(!_timers[id]) throw 'timer does not exist, cannot be deleted: ' + id; delete _timers[id]; } }; return pub; })(); Example usage: $('.start').on('click', function(){ timer.start(123); }); $('.stop').on('click', function(){ timer.stop(123); }); $('.clear').on('click', function(){ timer.delete(123); $('input').val(''); }); setInterval(function(){ let result = null; try//obviously not a great pattern { result = timer.read(123); } catch(ex){} if(result) { $('input').val(result.total); } }, 35);
Totally destroy an instance
I am making a game with rounds that last either 100 minutes OR the time required for totalItemAmount to reach 500. If "addPlayer" gets triggered when the game has ended, I want to push that player to next round. I want to be able to destroy it/create new ones flawlessly. First game always runs well. Following games go wrong. To sum it up, I feel like the first game ran isn't being properly destroyed after it ends. Obviously, my code is much much larger than what you see down here, but let me ask you, is there any problem with my structure? function Game(duration, playersForThisRound) { console.log('NEW GAME') this.playersForNextRound = []; this.id = Math.random(); this.finished = 0; this.players = {}; this.duration = 100; this.totalItemAmount = 0; this.endTimeout = setTimeout(() => { this.end(this); return }, this.duration * 60 * 1000); if (playersForThisRound && playersForThisRound.length > 0) { Object.keys(this.playersForNextRound).forEach(function(key) { this.addPlayer(this, key.player, key.items) }); } return } Game.prototype.addPlayer = function(game, player) { if (this.finished || this.totalItemAmount >= 500) { var playerIsInNextRound = 0; Object.keys(this.playersForNextRound).forEach(function(key) { if (key.id == player.id) { playerIsInNextRound = 1 key.items.push(items) } }) if (!playerIsInNextRound) this.playersForNextRound.push({ "id": player.id, "player": player, "items": items }); if (game.totalItemAmount >= 500) { clearTimeout(game.endTimeout) this.end(this); } return } if (!game.players[player.id]) { game.players[player.id] = new Player(game, player, items); game.players[player.id].addItems(game, items, function(added) { game.jackpot += added; Object.keys(game.players).forEach(function(player) { game.players[player].chance = game.players[player].getChance(game.jackpot) }); }) } Game.prototype.end = function(game) { game.finished = 1; clearTimeout(game.endTimeout) setTimeout(() => { game = new Game(10, this.playersForNextRound); }, 1000 * 60 * 10); } //To start first game var game = new Game(); module.exports = game; Now in another file: let game = require("./lib/games/roundbased.js"); let test = setInterval(() => { for (var i = 0; i < 100; i++) { game.addPlayer(game, { id: '12345' + i, nick: "player" + i },