How would I Increment a number in a way where it shows every step instead of skipping numbers?

76 Views Asked by At

So for example in my code:

numbersGoingUp() {
        const atoms = this.user.resources[0]
        const molecules = this.user.resources[1]
        const atom_gens = this.user.generators[0]
        const molecule_gens = this.user.generators[1]

        if (!this.interval) {
            this.interval = setInterval(() => {
                if (atom_gens.active) {
                    if (atoms.amount >= atoms.max) {
                        return
                    } else {
                        atoms.amount += atom_gens.amount
                    }
                    if (molecule_gens.active) {
                        if (molecules.amount >= molecules.max) {
                            return
                        } else {
                            molecules.amount += molecule_gens.amount
                        }
                    }
                }
            }, 1000);
        }
    },

If the number to increment by were to stay 1 then there would be no issue whatsoever however when I set the number to increment by to a 2 for example it would increment the following way: 2...4...6...8 and so on.

What I want is for the incrementing number to show every step. So even if it's incrementing by 3 every second I want to see: 1...2...3...4...5 and so on.

Sorry if the wording is bad or if it's hard to understand. Any help is appreciated! :D

I have tried setting the interval time to different values and while that does somewhat do what I want but not in a way that would be easy to manage going forward.

3

There are 3 best solutions below

0
On BEST ANSWER

Assuming that your increment amounts for atoms and molecules could be different, which is why it's hard to pick an interval amount to display as you want.

An alternative would be to use requestAnimationFrame (RAF) - which would have the following benefits

  1. Different increment amount
  2. Can be written in such a way that the "progress" won't slow down/stop if the page is no longer in focus (setInterval tends to do that)
  3. Since RAF is synchronised with the display refresh rate it makes for a better update
  4. There's no reason to try and update the displayed values faster than the refresh rate, using RAF will avoid this

I have two proposed answers - the first behaves as your code behaves, i.e. the interval in your code will keep getting called, even once both .amount are greater than there respective .max

In both suggestions,

Math.floor(time * atom_gens.amount)

calculates the number of "atoms" based on how long the "animation" has been running in seconds (including fractional seconds) multiplied by the .amount which I assumed is the increment per second.

Unless your increment is above 60 or so, then both increments should only ever increase by one at a time, and the value is changed in .amount only when there is a change

NOTE: this code does assume that the .amount values start at zero

numbersGoingUp() {
    const atoms = this.user.resources[0];
    const molecules = this.user.resources[1];
    const atom_gens = this.user.generators[0];
    const molecule_gens = this.user.generators[1];

    let start;

    const gen = (ms) => {
        if (atom_gens.active) {
            if (atoms.amount < atoms.max) {
                const time = (ms - start) / 1000;
                const n = Math.min(Math.floor(time * atom_gens.amount), atoms.max);
                if (n !== atoms.amount) {
                    atoms.amount = n;
                }
                if (molecule_gens.active) {
                    if (molecules.amount < molecules.max) {
                        const n = Math.min(Math.floor(time * molecule_gens.amount), molecules.max);
                        if (n !== molecules.amount) {
                            molecules.amount = n;
                        }
                    }
                }
            }
        }
        requestAnimationFrame(gen);
    };
    requestAnimationFrame((ms) => {
        start = ms;
        requestAnimationFrame(gen);
    });
},

The other proposed code will stop calling the gen function once either .amount is greater than or equal to its respective .max

numbersGoingUp() {
    const atoms = this.user.resources[0];
    const molecules = this.user.resources[1];
    const atom_gens = this.user.generators[0];
    const molecule_gens = this.user.generators[1];

    let start;

    const gen = (ms) => {
        if (atom_gens.active) {
            if (atoms.amount >= atoms.max) {
                return;
            }
            const time = (ms - start) / 1000;
            const n = Math.min(Math.floor(time * atom_gens.amount), atoms.max);
            if (n !== atoms.amount) {
                atoms.amount = n;
            }
            if (molecule_gens.active) {
                if (molecules.amount >= molecules.max) {
                    return;
                }
                const n = Math.min(Math.floor(time * molecule_gens.amount), molecules.max);
                if (n !== molecules.amount) {
                    molecules.amount = n;
                }
            }
        }
        requestAnimationFrame(gen);
    };
    requestAnimationFrame((ms) => {
        start = ms;
        requestAnimationFrame(gen);
    });
},
0
On

The way step works is by actually incrementing the counter by the step, which I will be using 2 for this example. If you get the step as 2, the counter is going to be:

2, 4, 6, 8, 10, ...

And this is the default and expected behavior. If you want to make it show every step, make the interval run faster and print every single one:

numbersGoingUp() {
            const atoms = this.user.resources[0]
            const molecules = this.user.resources[1]
            const atom_gens = this.user.generators[0]
            const molecule_gens = this.user.generators[1]

            if (!this.interval) {
                this.interval = setInterval(() => {
                    if (atom_gens.active) {
                        if (atoms.amount >= atoms.max) {
                            return
                        } else {
                            atoms.amount += atom_gens.amount
                        }
                        if (molecule_gens.active) {
                            if (molecules.amount >= molecules.max) {
                                return
                            } else {
                                molecules.amount += molecule_gens.amount
                            }
                        }
                    }
                }, 500); // For running twice as fast, and you can make it scale with your molecules_gens.amount or atom_gens.amount by using 1000 / atom_gens.amount or molecules_gens.amount
            }
        },
0
On

If you are set on keeping your interval / steps where they are at, you could do:

 const timeout = 1000
 setInterval(() => {
     // ...
     amount = atom_gens.amount
     timeSlice = timeout / amount
     for (i = 0; i < amount; i++) {
         setTimeout(() => {
             atoms.amount += 1
         }, timeSlice * i) // e.g. atom_gens.amount = 3: 
                           // 0 -> 1 at 0ms
                           // 1 -> 2 at 333ms
                           // 2 -> 3 at 666ms
     }
 }, timeout);
     

E.g.

 const timeout = 1000
 const output = document.getElementById('output');
 const atoms = { 
     set amount(value) {
         this.value = value
         output.innerHTML = value
     },
     get amount() { 
         return this.value
     }, 
     value: 0
 }
 const atom_gens = { amount: 3 }
 
 setInterval(() => {
     amount = atom_gens.amount
     timeSlice = timeout / amount
     for (i = 0; i < amount; i++) {
         setTimeout(() => {
             atoms.amount += 1
         }, timeSlice * i) // e.g. atom_gens.amount = 3: 
                           // 0 -> 1 at 0ms
                           // 1 -> 2 at 333ms
                           // 2 -> 3 at 666ms
     }
 }, timeout);
<div id="output"></div>