Why is this javascript function executing more times per second than it's supposed to

I am working on a sort of clicker game where the user is able to buy upgrades. One such upgrade involves the user earning a certain amount of in-game currency per second, in this case 0.1. Unfortunately if the user decides to buy more than one of this upgrade it appears to rise exponentially. I feel like this might be because the setInterval() function is stacking each time, so that the first time it is 0.1 then the next its 0.1 + 0.2 so 0.3, then 0.3 + 0.2 + 0.1 so 0.6 and so on.

upgradePerSec1.onclick = function() {
  if (presents >= cost1) {
    presents -= cost1;
    upgrade1Amount += 1;
    totalPresentsSpent += cost1;
    cost1 = Math.ceil(cost1Base *= 1.03 ** upgrade1Amount);
    perSec += 0.1;
    displayScore.innerHTML = format(presents) + " Presents delivered.";
    cost1Disp.innerHTML = "<hr>Cost: " + format(cost1);
    title.innerHTML = format(presents) + " Presents";
    perSecDisp.innerHTML = formatPerSec(perSec) + " presents /s";
    totalPresentsSpentDisp.innerHTML = format(totalPresentsSpent) + " Total presents spent";
    setInterval(increment1, 1000);
  } else {
    alert("You don't have enough presents! Still need: " + format(cost1 - presents));
  }
}

function increment1() {
  presents += perSec;
  totalPresents += perSec;
  displayScore.innerHTML = format(presents) + " Presents delivered.";
  totalPresentsDisp.innerHTML = format(totalPresents) + " Total presents delivered";
  title.innerHTML = format(presents) + " Presents";
}

Here is some clarification for this code:

  • upgradePerSec1 = HTML button element
  • cost1 = the cost of this upgrade
  • perSec = variable to store the amount of "presents" per second
  • displayScore = an HTML label element
  • cost1Disp = an HTML label element
  • title = the browser tab title
  • format() = a function to format large numbers by adding in commas
  • totalPresents = the total presents without taking away costs (used for a statistics section)

I have tried replacing the perSec variable with just the number(obviously did not work) I have tried making the timing also rise but could not get the correct timing. Ive also searched many places on the web and could not find any helpful results. I saw one on stack overlfow but it did not apply to me.

>Solution :

You’re right, the setInterval calls are stacking. To fix the issue, you should make sure you only call setInterval() once (e.g. by adding an if statement before that line checking if perSec === 0).

e.g.

upgradePerSec1.onclick = function() {
  if (presents >= cost1) {
    presents -= cost1;
    upgrade1Amount += 1;
    totalPresentsSpent += cost1;
    cost1 = Math.ceil(cost1Base *= 1.03 ** upgrade1Amount);
    perSec += 0.1;
    displayScore.innerHTML = format(presents) + " Presents delivered.";
    cost1Disp.innerHTML = "<hr>Cost: " + format(cost1);
    title.innerHTML = format(presents) + " Presents";
    perSecDisp.innerHTML = formatPerSec(perSec) + " presents /s";
    totalPresentsSpentDisp.innerHTML = format(totalPresentsSpent) + " Total presents spent";
    if (perSec === 0) {
      setInterval(increment1, 1000);
    }
  } else {
    alert("You don't have enough presents! Still need: " + format(cost1 - presents));
  }
}

function increment1() {
  presents += perSec;
  totalPresents += perSec;
  displayScore.innerHTML = format(presents) + " Presents delivered.";
  totalPresentsDisp.innerHTML = format(totalPresents) + " Total presents delivered";
  title.innerHTML = format(presents) + " Presents";
}

Leave a Reply