Search code examples
javascriptsettimeoutsetintervaltetris

Tetris in Javascript : setInterval setTimeout behavior


I have a problem. I'm trying to do a tetris game in javascript (for learning sake). However, i can't use the setInterval (or setTimeout) function. What I want to do is changing the color of the next case every 2000ms.

HTML CODE :

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <title>PROJET : PROGRAMMATION COTE CLIENT</title>
    <link rel="stylesheet" type="text/css" href="index.css">
</head>
<body>
    <div class="all">
        <div id="A">
            <span id="pos1A"></span>
            <span id="pos2A"></span>
            <span id="pos3A"></span>
            <span id="pos4A"></span>
            <span id="pos5A"></span>
            <span id="pos6A"></span>
            <span id="pos7A"></span>
            <span id="pos8A"></span>
            <span id="pos9A"></span>
            <span id="pos10A"></span>
        </div>
    </div>
    <script src="classes.js"></script>
    <script src="indexjs.js"></script>
    </body>
</html>

CSS CODE :

.all {
    display: flex;
    flex-direction: column;
}
.all > div {
    display: flex;
    flex-direction: row;
}
.all > div > span {
    width: 20px;
    height: 20px;
    border: 1px solid gray;
}

JS CODE :

var array = ['pos1A','pos2A','pos3A','pos4A','pos5A','pos6A','pos7A','pos8A','pos9A','pos10A    '];
function downmove(i) {
    var element = document.getElementById(array[i]);
    element.style.backgroundColor = 'green';
    console.log(element);
}
var i;
for(i=0;i<10;i++) {
    setInterval(downmove(i),2000);
}

I want every block to change color one by one, but actually it colors all the line in a row. It's like my interval doesn't work.

enter image description here


Solution

  • That's because your setInterval call is wrong.

    setInterval and setTimeout both take a Function as a first parameter, while (in your example) you are actually invoking you function immediately (that's why you are seeing the results right away). You should take a look at the documentation, for example at MDN: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval.

    You can either modify your downmove(i) function to return a new function that will be passed to setInterval, or you can use an anonymous function to wrap you downmove call inside the interval like this:

    for (i = 0; i<10; i++) {
        setInterval(
            (function (idx) { downmove(idx); })(i),
            2000
        );
    }
    

    (Please notice that I'm using an IIFE to properly deal with the i variable, this could be avoided by using let i = 0 in the for-loop, but why this is needed is kind of another topic to cover, you can read more about this here: JavaScript closure inside loops – simple practical example).


    There is one more problem with your code - you want to change the colors sequentially, but you implementation (even with the fix) will run every color change instantaneously after the said 2 seconds of time. To fix this, you have to somehow keep the track of previously colored row and increment it every 2 seconds.

    Here's a simple example of fixed implementation:

    let idx = 0;
    
    const intervalID = setInterval(function () {
        if (idx >= 10) {
            // Maximum row reached, break the loop...
            clearInterval(intervalID);
    
            return;
        }
    
        downmove(idx);
    
        idx++;
    }, 2000);
    

    (No need to use for-loop here).