1

I'm building a browser game similar to Guitar Hero. The way it works is setInterval is set to execute every 16th note depending on the tempo, which is usually 100-150 milliseconds. The function it executes just checks if there's a note that needs to be checked against the user's keypresses.

But I've been reading about how setInterval can suffer from drift and may not be very accurate. For a song that lasts 3-4 minutes and needs 100ms precision (if the timing mechanics are even slightly off, that might be very frustrating for the users), it seems like it may not be the greatest solution.

So is there an alternative that's more precise? T

  • `can suffer from drift` - I've read this statement before and decided to test this claim, and found, at least in firefox, that there is no drift as such, there is jitter – Jaromanda X Aug 08 '17 at 01:52
  • You should query information based on user interaction, not setInterval. – StackSlave Aug 08 '17 at 01:52
  • @PHPglue I do check when a user presses a button to see if it's correct. However, I also need a way to check if a user misses a note. For example, if a user doesn't do anything at all the whole game, the game still needs to check each note at the right time to decrement points. – Andrew Harris Aug 08 '17 at 02:14
  • Do math based on Date. – StackSlave Aug 09 '17 at 01:51

4 Answers4

1

It probably would be a better idea to calculate everything in absolute time. So have a var starttime = Date.now();, and then calculate where every note should be var expected_note_time = starttime+beat_interval*beat_number. You can then add a listener on keypress and then log the exact time the keypress was hit. If abs(time_pressed-expected_note_time) < ALLOWED_MISTAKE_VARIANCE, then add that point to the user's score. Good luck.

PressingOnAlways
  • 11,948
  • 6
  • 32
  • 59
  • I actually do have that exact solution set up for checking for user input. However, another way the game works is even if the user doesn't do anything at all for the whole game, the game still needs to check each note at the right time to decrement points if the user doesn't press anything. – Andrew Harris Aug 08 '17 at 02:18
  • @AndrewHarris refer to this QA - https://stackoverflow.com/questions/29971898/how-to-create-an-accurate-timer-in-javascript . With that, you can use setInterval and "make up" for any jitter or drift. – PressingOnAlways Aug 08 '17 at 02:23
  • Awesome that looks like exactly what I need. Thanks! – Andrew Harris Aug 08 '17 at 02:47
1

Agree, setInterval have some issues, like it doesn't care whether the callback is still running or not and isn't that flexible.

you can implement you own method something like this :

function interval(func, wait, times){
var interv = function(w, t){
    return function(){
        if(typeof t === "undefined" || t-- > 0){
            setTimeout(interv, w);
            try{
                func.call(null);
            }
            catch(e){
                t = 0;
                throw e.toString();
            }
        }
    };
}(wait, times);

setTimeout(interv, wait);
};

this function has an internal function called interv which gets invoked automatically via setTimeout, within interv is a closure that checks the the repetition times, invokes the callback and invokes interv again via setTimeout. In case an exception bubbles up from the callback call the interval calling will stop and the exception will be thrown.

you can use it like this :

interval(function(){
    // Code block goes here
}, 1000, 10);

which execute a piece of code 5 times with an interval or 10 seconds and you can do something in between.

Emad Dehnavi
  • 3,262
  • 4
  • 19
  • 44
0

You could cache the ticks at the start of the song, get the number of ticks since then, see if a note exists at that point.

Return the number of milliseconds since 1970/01/01:

var d = new Date();
var n = d.getTime();

The result of n could be: 1502156888172

From: https://www.w3schools.com/jsref/jsref_gettime.asp

frattaro
  • 3,241
  • 1
  • 16
  • 10
0

and needs 100ms precision

The setInterval() function will drift because of the way javascript is built (event loop) and if you block it with a heavy CPU intensive task, it will delay. However, the drift will be very small (less that a ms) if you do it correctly.

A good way to avoid that would be to use multiple thread, but that is not easily achieved in JavaScript.

Alexandre Senges
  • 1,474
  • 1
  • 13
  • 22