Reputation: 3774
I am writing a card game so i need to setup a basic game loop using window.requestAnimationFrame. I need to make the fps set to 30fps and since it is a slow paced card game i just need a simple workable game loop. My game loop is as follows.
function loop(timestamp) {
var progress = timestamp - lastRender
update(progress)
draw()
lastRender = timestamp
window.requestAnimationFrame(loop)
}
var lastRender = 0
window.requestAnimationFrame(loop)
How can i make it so that the fps is set to 30fps? I appreciate any help! Thanks!
Upvotes: 0
Views: 5477
Reputation: 192
FPS stands for Frames Per Second.
1000 / 30 = 30 fps
Try this basic function:
function animate() {
setTimeout(function() {
requestAnimationFrame(animate);
}, 1000 / 30);
}
Upvotes: 1
Reputation: 6366
You should keep simulating
and drawing
separate.
Below is an example where i make a simulation
every millisecond (1000 times in a second). Each simulation cancels the previous' request for an animation frame.
If the browsers refresh has "ticked" it will have drawn
our update (incremented our counter).
after 1 second i stop and we should see approximately your monitors refresh rate as our 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 - Why separation of concerns
Drawing on the canvas is an expensive operation that you normally wouldn't want to run on every frame if you can avoid it.
Basically only call for a redraw when something changes.
In my example below i create a big amount of boxes, simulate them and draw them:
//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);
Notice how simulating them is way faster than drawing them.
As a rule of thumb, you only have 1000/60 ~ 16
milliseconds between each frame, so if we can spare the milliseconds a draw would take, then we would gladly do so and focus such a frames calculation time on bigger operations (like pathfinding or collision detection or whatever would be heavy in your game).
This way we can also run our simulation at another rate than the draw rate, which is handy when working with asynchronous tasks.
Upvotes: 2