skip to Main Content

I am trying to make a game loop in javascript where an event happens every x amount of time, and that time gets shorter with each loop.

This is the code I’ve tried using:


const begin = document.getElementById("startbtn")

begin.onclick = start;

//Game loop

function start() {

    console.log("test");

    let i = 1000;

    while (i>0) {
        loop(i);
        i = i - 100;
        }

    function loop(i){
        setTimeout(function(){
            console.log("adsafsd");
        }, 5 * i);
    }

}

But it just repeats at the same interval, and finishes in about 5 seconds after 10 loops.
I imagined that the setTimeout in the loop function would get shorter, since it takes 5 times the i variable, which is subtracted by 100 every loop.

3

Answers


  1. You could use async/await and wrap setTimeout into a promise to make the code more manageable:

    let game;
    
    const timeout = (delay = 0) => new Promise(resolve => setTimeout(resolve, delay));
    
    const restart = () => stop() + start(game = {running: true});
    
    const stop = () => game && delete game.running;
    
    async function start(game) {
    
        console.log('game started');
        
        let delay = 500; // start delay
    
        while (delay > 0) { 
           await timeout(delay); 
           if(!game.running){
             break;
           }
           console.log(`delay ${delay}`);
           delay -= 50; // your interval decrement
        }
    
    }
    button{
      background: lightgray;
      border:none;
      border-radius:50%;
      padding: 10px 20px;
      cursor:pointer;
    }
    button:hover{
      background:#ddd;
      box-shadow: 0 0 10px rgba(0,0,0,.2);
    }
    <button onclick="restart()">Start</button> <button onclick="stop()">Stop</button>
    Login or Signup to reply.
  2. If you don’t want to swap to async like the other (really good) answer:

    Your current code creates all timeouts almost simultaneously, each with a delay that’s decreasing by 100ms with each iteration. However, setTimeout works asynchronously, so it doesn’t wait for the previous timeout to finish before setting up the next one, which means all timeouts are setup virtually at the same time. Therefore, they end almost together, just with minor delays relative to each other.

    You should set up each next timeout after the previous one has finished. You could accomplish this by using recursion in your loop function:

    const begin = document.getElementById("startbtn");
    
    begin.onclick = start;
    
    function start() {
        console.log("test");
        loop(1000);
    }
    
    function loop(i) {
        setTimeout(function() {
            console.log("Looping...");
            if (i > 100) {
                loop(i - 100);
            }
        }, 5 * i);
    }
    
    Login or Signup to reply.
  3. Using your example:

    const begin = document.getElementById("startbtn");
    
    begin.onclick = start;
    
    // Game loop
    function start() {
        console.log("test");
    
        let delay = 1000;
    
        function loop() {
            setTimeout(function () {
                console.log("adsafsd");
                delay -= 100;
                if (delay > 0) {
                    loop();
                }
            }, delay);
        }
    
        loop();
    }
    

    But I think the best model for this question will be:

    const begin = document.getElementById("startbtn");
    
    begin.onclick = start;
    
    const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
    
    // Game loop
    async function start() {
        console.log('game started');
    
        for (let delay = 1000; delay > 0; delay -= 100) {
            await sleep(delay);
            console.log("adsafsd");
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search