Search code examples
javascriptvue.jsincremental

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


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.


Solution

  • 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);
        });
    },