Вы должны держать simulating
и drawing
отдельно.
Ниже приведен пример, где я делаю simulation
каждую миллисекунду (1000 раз в секунду). Каждое симуляция отменяет предыдущий запрос для кадра анимации.
Если обновление браузера «галочкой», у него будет drawn
наше обновление (с шагом нашего счетчика).
через 1 секунду я останавливаюсь, и мы должны увидеть приблизительно ваши частоты обновления мониторов, как наш count
.
//counter
var count = 0;
//draw function
function draw() {
count++;
}
//Animation frame handle
var animationFramHandle;
//Run every millisecond
var interval = setInterval(function() {
//Cancel requestAnimationFrame
cancelAnimationFrame(animationFramHandle);
//request new requestAnimationFrame
animationFramHandle = requestAnimationFrame(draw);
}, 1);
//Wait 1 second
setTimeout(function() {
//Stop simulation
clearInterval(interval);
cancelAnimationFrame(animationFramHandle);
console.log("ticks in a second:", count);
}, 1000);
Edit - Почему разделение задач
рисунок на холсте является дорогостоящей операцией, которую вы обычно не хотите работать на каждом кадре, если вы можете избежать ,
В основном требуется только перерисовать, когда что-то меняется.
В моем примере ниже я создать большое количество коробок, моделировать их и сделать их:
//DOM elements
var canvas = document.createElement("canvas");
canvas.width = 400;
canvas.height = 400;
document.body.appendChild(canvas);
var ctx = canvas.getContext("2d");
ctx.fillStyle = "rgba(0,0,0,0.1)";
var drawNode = document.createElement("p");
document.body.appendChild(drawNode);
//Variables
var simulations = 0;
var simulationTime = 0;
var requestAnimationFrameHandle;
//Boxes to simulate and draw
var boxes = [];
while (boxes.length < 10000) {
boxes.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
s: 5
});
}
//Draw function
function draw() {
var t = Date.now();
//Clear
ctx.clearRect(0, 0, canvas.width, canvas.height);
//Draw
for (var bIndex = 0; bIndex < boxes.length; bIndex++) {
var box = boxes[bIndex];
ctx.fillRect(box.x, box.y, box.s, box.s);
}
//Log
drawNode.innerHTML = ("New draw after " + simulations + " simulations<br>Drawing took " + (Date.now() - t) + " ms<br>Simulation time is " + simulationTime + " ms");
simulations = 0;
}
//Simulate function
function simulate(force) {
if (force === void 0) { force = false; }
simulations++;
if (Math.random() * 1000 > 800) {
var t = Date.now();
for (var bIndex = 0; bIndex < boxes.length; bIndex++) {
var box = boxes[bIndex];
box.x = Math.abs(box.x + (Math.random() * 3 - 1)) % canvas.width;
box.y = Math.abs(box.y + (Math.random() * 3 - 1)) % canvas.height;
}
simulationTime = Date.now() - t;
cancelAnimationFrame(requestAnimationFrameHandle);
requestAnimationFrameHandle = requestAnimationFrame(draw);
}
}
setInterval(simulate, 1000/120);
Обратите внимание, как моделировать их в путь быстрее, чем рисовать их.
Как правило, у вас есть только 1000/60 ~ 16
миллисекунд между каждым фреймом, поэтому, если мы сможем сэкономить миллисекунды, то мы с радостью сделаем это и сконцентрируем время вычисления таких кадров на больших операциях (например, или обнаружение столкновения или все, что было бы тяжело в вашей игре).
Таким образом, мы также можем запустить наше моделирование с другой скоростью, чем коэффициент вытягивания, что удобно при работе с асинхронными задачами.
Пожалуйста, взгляните на эту тему: http://stackoverflow.com/questions/19764018/controlling-fps-with-requestanimationframe – mrmnmly
Почему это должно быть 30 кадров в секунду?Трюк с 'requestAnimationFrame' заключается в том, что он всегда дает лучшую частоту кадров любому монитору, поэтому ограничение до 30 кадров в секунду кажется странным. –
@ EmilS.Jørgensen ok спасибо! оказывается, что приведенный выше код в порядке. Он дает 60 кадров в секунду в моей системе, и я думаю, что это нормально для игр. – kofhearts