0

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

WaLinke
  • 726
  • 2
  • 6
  • 25
  • Reading [the docs](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval) is always useful. You should also drop the `for` loop, if you're going to use `setInterval`, or use `setTimeout` instead, in which case there will be a closure problem with the value of `i` ... – Teemu Aug 08 '17 at 15:47
  • Thanks. I haven't read about closure yet, I was thinking that I didn't need it to this small project. – WaLinke Aug 08 '17 at 16:20

2 Answers2

2

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).

mdziekon
  • 3,531
  • 3
  • 22
  • 32
  • Thanks a lot for your answer. I come from C++ and these are concepts i'm not familiar with. I have to work more on the basics before putting my hands on this project. Thanks a lot for the usefull links and have a nice day. – WaLinke Aug 08 '17 at 16:15
1

This is how you can do it, but I imagine you will have to change it up for your game later on.

var array = ['pos1A','pos2A','pos3A','pos4A','pos5A','pos6A','pos7A','pos8A','pos9A','pos10A    '];

var i = 0,
    interval;
    max_i = 9;

function downmove() {
    var element = document.getElementById(array[i]);
    element.style.backgroundColor = 'green';
    console.log(element);
    i++;

    if (i === max_i) clearInterval(interval);
}

interval = setInterval(downmove, 2000);
Slava Eremenko
  • 2,235
  • 1
  • 11
  • 9
  • 1
    I tried this and it works, but i don't get why you call setInterval(downmove,2000) and not setInterval(downmove(),2000) It works with the first one but it doesn't with the second, it only shows the first block in green. BTW thanks a lot for your answer and your time. – WaLinke Aug 08 '17 at 16:18
  • @WaLinke second one doesn work, because with "downmove()" you call the function and pass the result (which is "null") to the setInterval. Compared to setInterval(downmove, ...) you pass the function itself! – Slava Eremenko Aug 09 '17 at 17:05