2014-09-16 1 views
6

Я бы хотел использовать setInterval для фактических шагов в программе и requestAnimationFrame для рендеринга. Я был под впечатлением, что это будет идеальное сочетание: скорость рендеринга не замедлит фактическую прогрессию, поэтому падение частоты кадров повлияет только на частоту кадров и все еще синхронизируется. Однако у меня были капли в функции setInterval.Использование setInterval с requestAnimationFrame

пример того, что я имею в виду, намеренно погрязнуть тени: http://jsfiddle.net/Ltdz168m/

Уменьшить или увеличить количество заправок, и вы увидите разницу

Казалось бы, что на самом деле requestAnimationFrame не решение для обеспечения отставания, замедляющего JavaScript. Как тогда я бы обновил логическую сторону вещей, что можно сделать со скоростью 60 кадров в секунду, без помех от рендеринга? Необходимы ли WebWorkers?

ответ

17

Проблема в том, что браузер по-прежнему способен выполнять только одну вещь за раз. Итак, если это рендеринг, он не может обновить позицию.

При использовании материалов для поддержки переменных фреймов, вы должны всегда использовать Delta Timing. Это работает примерно так:

requestAnimationFrame(function(e) { 
 
    document.getElementById('status').innerHTML = "Delta time: "+e; 
 
    
 
    // lag randomly 
 
    while(Math.random() > 0.0000001) {} 
 
    
 
    requestAnimationFrame(arguments.callee); 
 
});
<div id="status"></div>

Как вы можете видеть (надеюсь), независимо от частоты кадров, время дельта показаны идет вверх последовательно. Это означает, что вы можете сделать, например, angleFromStart = e/1000*Math.PI*2;, и ваша точка будет находиться на орбите с точностью до 60 об/мин.

var angle=0, 
 
    radian=Math.PI/180; 
 
var canvas=document.getElementById("canvas"), 
 
    context=canvas.getContext("2d"); 
 
context.shadowColor="black"; 
 
context.shadowBlur=100; 
 
requestAnimationFrame(function draw(e) { 
 
    angle = e/1000*Math.PI*2; 
 
    var x=canvas.width/2+Math.cos(angle)*canvas.width/4, 
 
     y=canvas.height/2+Math.sin(angle)*canvas.height/4; 
 
    context.clearRect(0, 0, canvas.width, canvas.height); 
 
    context.beginPath(); 
 
    context.arc(x, y, 5, 0, Math.PI*2); 
 
    context.closePath(); 
 
    for(var i=0; i<255; i++) { 
 
     context.fill(); 
 
    } 
 
    requestAnimationFrame(draw); 
 
});
#canvas { 
 
    border: 1px solid black; 
 
}
<canvas id="canvas"></canvas>

PS: Я люблю новую функцию Stack Snippet!

+0

Я думал об этом, но мальчику было бы много работы. Я полагаю, что это необходимая работа. И я должен согласиться, это аккуратная особенность; бьет jsfiddle ссылки. – 2014-09-16 23:01:36

+0

На самом деле меньше кода для использования Delta Timing, чем использовать 'setInterval';) –

+0

Ну, у меня только что был настроен цикл с расширением .update(), поэтому мне нужно будет пропустить его через это и применить до довольно много математической работы (гораздо больше, чем этот пример). Тем не менее, он должен рассчитывать на синхронизацию. – 2014-09-16 23:04:43