One issue I see is you're using bind
. bind
creates a copy of the function but with a bound context. You appear to call it on each iteration, which will cause memory hogging, which causes the GC to kick in more often, thus lagging. You can simply just drop the use of bind
and write your code without relying on context.
If you need to store state, store it somewhere else, like a single module holding your game state. It's also good to isolate state into one location instead of having it everywhere.
The render loop should just be a render loop. It should not be aware of anything else except a queue of things to do on each turn. On the other hand, the rest of the code shouldn't be aware of a render loop. All they need to do is to register operations to the queue, with only the assumption that the function they register gets executed per frame. This keeps code relatively decoupled with the scheduling mechanism.
In the following, we create a jobQueue
which is just a list of things to do when the loop executes.
// The render loop is only aware of a job queue full of functions
const jobQueue = [];
function renderLoop(elapsed){
requestAnimationFrame(renderLoop);
// Consume tasks in jobQueue
jobQueue.forEach( task => task.call(elapsed / (1000/60)) );
}
// Start the loop
renderLoop();
// All your code needs to do now is register
jobQueue.push(scale => { update some state });
jobQueue.push(scale => { render something });
jobQueue.push(scale => { check keyboard });
Also, it's best if you schedule the next frame prior to doing stuff. That way, anything that causes the loop to lag doesn't lag scheduling the next frame.
Another thing is timing. requestAnimationFrame
's callback accepts 1 argument, a timestamp. Use that instead of Date.now
. Now instead of using delta time (a time value) in your calculation, consider using a scale (a unit-less value). I've answered a similar review here. With delta time, you have to change your calculation to take in a time value. With a scale, you simply calculate output values, then multiply against the scale value. It's like a percentage value.
Lastly, the example above uses forEach
for jobQueue
. It's known to be slow. Feel free to replace it with a regular for
or while
loop.