2

I'm trying to make a simon game and I'm almost done but I got an issue. In a simon game, when the simon's giving you the order (which represented by blinking lights and audio for each light) which you need to remember and repeat afterwards, there's a short delay between each blink (with it's audio) to the next one.

So now, my simon is making sounds but it's doing them all at once, with no delay. I tried using setIntarvel and setTimeout but still it played all audios at once.

Since adding the blinking shouldn't be that tough I'm keeping it to the end.

Then I built a timer function:

function timer(delayInMS) {
    var time = new Date();
    var currentTime = time.getTime();
    var nextTime = time.getTime() + delayInMS;
    while (currentTime != nextTime) {
        time = new Date();
        currentTime = time.getTime();
        }
}

And used it inside the function which playing the audios, but it's still doing the same thing - playing it all at once.

This is the function which responsible for the audios:

function playAudio(btnSound) {
    if (btnSound == "c") {
        c.play();
    }
    if (btnSound == "g") {
        g.play();
    }
    if (btnSound == "a") {
        a.play();
    }
    if (btnSound == "d") {
        d.play();
    }
}

And this function responsible for the logic of the game:

var btns = ["c", "g", "a", "d"];
var randomOrder = "";

var playerInputOrder = "";

var timer = 1000;    //For timer()

function randomSimon() {
var randomBtn = btns[Math.floor(Math.random() * 4)];
randomOrder += randomBtn;
for  (i = 0; i <= randomOrder.length - 1; i++) {
    for (s = 0; s <= i; s++) {
        var someText = "";
        someText += randomOrder.charAt(s);
        playAudio(randomOrder.charAt(s));
        document.getElementById('debug').innerHTML = someText; //this is for debugin, should be ignored.
        timer(500);
    }
}

}

And this is the whole script for better reading:

var isGameStarted = false;

var d = new Audio("dSharpNote.wav");
var a = new Audio("aSharpNote.wav");
var g = new Audio("gSharpNote.wav");
var c = new Audio("cNote.wav");

var btns = ["c", "g", "a", "d"];
var randomOrder = "";

var playerInputOrder = "";

var timer = 1000;

function startGame() {
    isGameStarted = true;         //So players won't be able to just press the simon's buttons.
    randomOrder = "";             //A variable to keep the random order given by the simon.
    playerInputOrder = "";        //A variable to keep the random order the player inputs.
    randomSimon();                //Called to give the first button in the order.
}

function randomSimon() {                                       //Adds one random button to the order and saves the order.
    var randomBtn = btns[Math.floor(Math.random() * 4)];       //Adds the random button.
    randomOrder += randomBtn;                                  //Saves the random order.
    for  (i = 0; i <= randomOrder.length - 1; i++) {           //this should play all the audios one by one according the saved order
        for (s = 0; s <= i; s++) {
            var someText = "";
            someText += randomOrder.charAt(s);
            playAudio(randomOrder.charAt(s));
            document.getElementById('debug').innerHTML = someText;         //this is for debugin, should be ignored.
            timer(500);
        }
    }
}

function timer(delayInMS) {
    var time = new Date();
    var currentTime = time.getTime();
    var nextTime = time.getTime() + delayInMS;
    while (currentTime != nextTime) {
        time = new Date();
        currentTime = time.getTime();
    }
}

function playerProgress(btn) {                        //Getting the player's input and checks if it's in the right order.
    if (isGameStarted == true) {
        var btnClicked = btn.id;                      //Gets the id of the button the player clicked.
        playAudio(btnClicked);                        //So this could play it's audio.
        playerInputOrder += btnClicked;
        if (playerInputOrder.length == randomOrder.length) {
            if (playerInputOrder == randomOrder) {
                playerInputOrder = "";
                setTimeout(randomSimon, 1000);
            } else {
                document.getElementById('scoreText').innerHTML = randomOrder + " Game Over!";
                isGameStarted = false;               //Makes the player unable to play the simon's button's audios.
            }
        }
        document.getElementById('debug').innerHTML = playerInputOrder;
    }
}

function playAudio(btnSound) {
    if (btnSound == "c") {
        c.play();
    }
    if (btnSound == "g") {
        g.play();
    }
    if (btnSound == "a") {
        a.play();
    }
    if (btnSound == "d") {
        d.play();
    }
}

function someInterval() {
    var i = 0;
    var anInterval = setInterval(function() {
        i++;
        if (i > 11) {
            clearInterval(anInterval);
            timer *= 2;
        }
    }, timer);
}
HerrGanzorig
  • 51
  • 1
  • 14
Omer
  • 163
  • 1
  • 10
  • Maybe related, [I answered this other question](https://stackoverflow.com/a/46182800/511529) a while ago, which is about sequencing an animation for such a game. – GolezTrol Nov 13 '17 at 15:01
  • eek... don't spin-lock in your game loop... have a time-interval that runs every say 5ms, track the delta-time instead. Or simply use lots of time-outs to progress the game state. spin-locking is never useful, unless your doing embedded programming. – Meirion Hughes Nov 13 '17 at 15:32
  • I read a little about spin-lock on google, and if I understand it right, the spin-lock here is the timer() function? – Omer Nov 14 '17 at 11:40

2 Answers2

1

So you want to have a pause after each playAudio call?

I would still go for timeouts

var sounds = {};
sounds.a = ...;
sounds.b = ...;

function playAudio(sound, callback) {
    if (typeof sounds[sound] === "undefined") {
        throw "sound not available";
    }
    sounds[sound].play();
    if (typeof callback !== "undefined") {
        window.setTimeout(callback, 500);
    }
}

// play a - pause - b - pause c
playAudio("a", function(){
    playAudio("b", function() {
        playAudio("c");
    });
});

if you build the sequence first you can do this dynamic too

var sequence = ["a", "b", "c"];
var pointer = 0;

playAudio(sequene[pointer], function() {
    pointer += 1;
    if (typeof sequence[pointer] !== "undefined") {
        playAudio(sequence[pointer], this); // this will be bound to the function itself
    } else {
        alert("sequence finished");    
    }
});

this is not tested but it should work, let me know if not.

Philipp Wrann
  • 1,751
  • 3
  • 19
  • 29
  • I'll check it out and give an update whether it works or not. May I ask you to explain the 'sequence' code? I think I've got it but not sure – Omer Nov 14 '17 at 11:43
  • The sequence is simply an array of strings (key codes). The pointer gives information about the current index we use (from this array). As long as the pointer exists (it is increased in line 1 of the function body) in the array playAudio will invoke itself again. Once the pointer reached the end of the array (our sequence) it will simply alert "sequence finished". Instead of using this as callback-argument you can also create a named function and pass that function as callback. In the example "this" is used because otherwise i can not reference the anonymous function. – Philipp Wrann Nov 15 '17 at 07:08
1

You can use setTimeout and give it an increasing as you go through the colors:

function randomSimon() {                                       //Adds one random button to the order and saves the order.
    var randomBtn = btns[Math.floor(Math.random() * 4)];       //Adds the random button.
    randomOrder += randomBtn;                                  //Saves the random order.
    for  (i = 0; i <= randomOrder.length - 1; i++) {           //this should play all the audios one by one according the saved order
        for (s = 0; s <= i; s++) {
            var someText = "";
            someText += randomOrder.charAt(s);
  >>>>>>>   setTimeout(function() { playAudio(randomOrder.charAt(s)); },2000*s);
            document.getElementById('debug').innerHTML = someText;         //this is for debugin, should be ignored.

        }
    }
}

This will play first sound instantly, second one after 2s, third after 4s and so on. Hope it helps!


EDIT

There you have a example with a for loop and setTimeout:

for (s = 0; s <= 2; s++) {
  setTimeout(function() { console.log('hello world'); },2000*s);
}

EDIT 2

OK It seems that memory accessing is messing a bit around here. Try to do it like this.

First create a function to do what you want to do after waiting:

var delayedPlay = function(c,delay) {
  setTimeout(
    function() { playAudio(c); },
    delay);
}

Then call it inside the for loop:

function randomSimon() {                                       //Adds one random button to the order and saves the order.
    var randomBtn = btns[Math.floor(Math.random() * 4)];       //Adds the random button.
    randomOrder += randomBtn;                                  //Saves the random order.
    for  (i = 0; i <= randomOrder.length - 1; i++) {           //this should play all the audios one by one according the saved order
        for (s = 0; s <= i; s++) {
            var someText = "";
            someText += randomOrder.charAt(s);
  >>>>>>>   delayedPlay(randomOrder.charAt(s),2000*s);
            document.getElementById('debug').innerHTML = someText;         //this is for debugin, should be ignored.

        }
    }
}
FcoRodr
  • 1,583
  • 7
  • 15
  • Already tried it, doing the same thing, playing all sounds at once – Omer Nov 14 '17 at 11:41
  • @Omer Did you copy the lane exactly as I wrote it? Are you multiplying `2000*s`? I edited with a fiddle example of the `for` loop and `setTimeout`. – FcoRodr Nov 14 '17 at 12:00
  • I did what you said but it isn't achieving what I want. For now I'm just trying it with text instead of sounds because it's more comfortable. I'll try to explain myself as good as I can: what I'm trying to do is similar to a normal 'For' loop which counts from 1 to 10. But I want it to wait a second before printing each number so after it prints '1', it shoud wait a second and then print '2' and so on until it gets to 10. – Omer Nov 14 '17 at 12:41
  • #Omer Please show me the code you are using to try that. – FcoRodr Nov 14 '17 at 12:48
  • Tried what you said, now it's not playing sounds at all – Omer Nov 16 '17 at 08:04