So i have been looking into ways to improve motion smoothness and performance on my canvas animations.
And a quick google on some game development forum suggests using two different loops one for calculating and one for drawing... the example code was shown like this:
function mainLoop() {
// all of your logic goes here, moving positions, checking inputs, etc...
// I guess it's proper to put all drawing to "off screen" canvases here too.
...
setTimeout(mainLoop, 1000 / desiredFPS);
}
function drawingLoop() {
//only drawing commands to the visible canvas goes here
...
requestAnimationFrame(drawingLoop);
}
//when your assets are loaded you just simply make a
//call to each loop to get them started...
mainLoop();
drawingLoop();
Is this actually the best way to do it ?
I currently have all my logic and draw in the same loop. I presumed two different loops would actually slow the frame rate down aswell as the smoothness of it all ?
My current approach is more like this:
function loop() {
calculate(); // calculate everything
draw(); // draw everything
requestAnimationFrame(loop);
}
loop();
Why is it suggested to do two different loops are there any pros and cons doing it that way?
If you want to improve performance and decouple calculations from the actual rendering, you should have a look at WebWorkers on MDN or HTML5 rocks. They are basically sorts of threads, which let you offload some work from the main thread.
But when it comes to perf, you should probably have a look at the perf tools in Chrome, which might help you debunk other non-trivial parts of your code. Have a look at the doc for the CPU profiling
Related
(I'm trying to make a basic space invaders game)I'm very new to coding so this might be a total mess, however, I'm using gameloop(s). One of them is moving the hero, one is moving the missiles, and drawing them. However, I can't seem to split them. I want to split them up so I can change the setTimeout, but it doesn't want to split up.
Tried to split them up by making a gameloop_1();, but that wouldn't move the missiles... sooo... I'm lost
var missiles = [];
function drawMissiles() {
document.getElementById('missiles').innerHTML = ""
for (var i = 0; i < missiles.length; i++) {
document.getElementById('missiles').innerHTML += `<div
class='missile1' style='left:${missiles[i].left}px;
top:${missiles[i].top}px'></div>`;
}
}
function moveMissiles() {
for (var i = 0; i < missiles.length; i++) {
missiles[i].top = missiles[i].top - 15
}
}
function gameLoop() {
setTimeout(gameLoop, 950)
moveMissiles();
drawMissiles();
moveFiende();
drawFiende();
collisionDetection();
}
function gameLoop_1() {
setInterval(gameLoop_1, 100)
moveMissiles();
drawMissiles();
}
gameLoop();
gameLoop_1();
What happens when I split them up, is as I said; The missiles won't then shoot.
Disclaimer:
If you expect an answer for your specific code here, you'll be disappointed, so if you do not intend to start from scratch or something like that, I'm sorry for the whole text.
I think you're misundertanding the purpose of a Game Loop.
There are some things wrong with your code, but I'll stick with the basis of your question, which also happen to be the basis of every game, the Game Loop.
Frames
Let's start with Frames. You probably know what a Frame is. It is like a drawing on the screen of a single moment in time. For example, when you watch a movie, you're actually watching a lot of pictures (frames) being drawn very fast, one after another, which gives the illusion of movement (usually 30 "pictures" per second).
The Game Loop
The Game Loop is the responsible for drawing the frames of the game, one after another, it executes functions, methods, changes variables and based on the results, it finally draws on the screen what is happening on the game.
The Game loop is basically what makes everything in the game possible to happen, it's like what time is for us in real life: without time passing, there would be no past, present or future, we would be stuck in a single frame forever.
The same happens on a game, withou a Game Loop, there would be no iterations, nor changes or frame updates.
Extremely basic game structure
Knowing that, the first thing you must do is always having a "central" game loop, and never split it. Always name other methods as "updates" and call them from the master game loop.
So a most correct structure for your code would be (this is just pseudocode similar to js, not any language in particular):
SpaceInvaders = {
GameLoop(){
UpdatePlayer();
UpdateProjectile();
UpdateEnemies();
setTimeout(GameLoop, 16) // to call the loop each 16ms, thus giving you 60fps
}
UpdatePlayer(){
// do stuff like move the player and fire
}
UpdateProjectile(){
// do stuff like move the projectile and check if it hitted something
}
UpdateEnemies(){
// do stuff like move the enemies
}
}
SpaceInvaders.GameLoop();
If you want to have a more in depth look on Game Loops, please check this amazing article, it helped me a lot when I was starting my first HTML5 canvas game:
https://isaacsukin.com/news/2015/01/detailed-explanation-javascript-game-loops-and-timing
You'll be presented with the hardware compensation problem that comes as consequence of the Game Loop and some other interesting stuff.
Your situation
Now that the Game Loop principle is better explained, let's talk about your specific situation a little more. There are 3 main things that pop into my eye:
First of all, I don't think that it is going to be a good experience to try making a game using only HTML concatenation and CSS, if you really want to do it from scratch all by yourself, I hardly encourage you to try making a game using HTML5 canvas. For me it was a great experience to learn the very basics of game development. As I look back now, tho, I see how my code sucks (used vanilla js, and compensated the hardware by hand on each frame in all moving entities). If you want to see this project done:
https://github.com/diguifi/littlejsworld
Second, you're not working with objects, that's going to make the code very messy in later stages of development and very hard to work with (even if it's just space invaders). What I mean by objectifying your game is, for example: instead of loose methods for "drawMissiles" and "moveMissiles" you should have an object called "Missile" and another called "Player".
The Missiles would have such methods ("draw" and "move", accesible via "Missile.draw()") and the Player would have a list of Missiles (this is just an example, you must use objects for everything in your game, in order to have a well designed project).
And third, seems to me that concatenating divs on innerHtml of an element from the DOM is not a good thing to do, it's very costly, ugly and time consuming.
My suggestions
If you want to make this game as an exercice for learning the basis of game development, I think you should start from scratch using only a canvas element and center your code efforts on the javascript, not messing with html elements to create the game. There are many articles and docs to help you in this task, such as the one I mentioned that talks about game loop.
If your goal is just to make a game, without having to understand basic problems, you should try a game engine, such as:
Godot: a free, easy and lightweight engine to create games, no need to worry about game loop here.
Phaser: code with js, without worrying about game loop management and many other basic stuff.
Unity: code in C# but not so much code is needed
Game Maker Studio: no coding needed, only basic programming logic
Construct 3: same as Game Maker, maybe easier
I'm writing a game in javascript canvas, and I experience lag sometimes. I think this is because I draw pretty much to the canvas.
My background for example isn't static, it moves from the right to the left, so each time, I have to clear the entire canvas. And I'm not clearing with just a color, I'm clearing with an image that moves every cycle of the gameloop.
I think this is an expensive operation and I was thinking if there is something to make this operation less expensive, like for example using double buffering for clearing the background (no idea if you can use double buffering just for clearing the background?).
Or should I use double buffering in the entire game?
(I don't think so because I've read that the browser already does that for you)
Since you experience your lag 'sometimes', and it's not a low frame rate issue, i would rather move my eyes towards the evil garbage collector : whenever it triggers, the application will freeze for up to a few milliseconds, and you'll get a frame miss.
To watch for this, you can use google profiling tools, in TimeLine / Memory / press the record button : you can see that a GC occurred when there's a sudden drop in the memory used.
Beware when using this tool, that it slows down a bit the app, and it creates garbage on its own (!)...
Also, since any function call for example creates a bit of garbage, so you can't have a full flat memory line.
Below i show the diagram of a simple game i made before i optimized memory use,
there's up to 5 GC per second :
And here the diagram of the very same game after memory optimisation : there's something like 1 GC per second. Because of the limitations i mentioned above, it is in fact the best we can get, and the game suffers no frame drop and feels more responsive.
To avoid creating garbage
- never create object, arrays or functions.
- never grow or reduce an array size.
- watch out for hidden object creation : Function.bind or Array.splice are two examples.
You can also :
- Pool (recycle) your objects
- use a particle engine to handle objects that are numerous / short lived.
I made a pooling lib (here) and a particle engine (here) you might use if you're interested.
But maybe first thing to do is to seek where you create objects, and have them created only once. Since js is single-threaded, you can in fact use static objects for quite a few things without any risk.
Just one small expl :
function complicatedComputation(parameters) {
// ...
var x=parameters.x, y = parameters.y, ... ...
}
// you can call creating an object each time :
var res = complicatedComputation ( { x : this.x, y : this.y, ... ... } );
//... or for instance define once a parameter object :
complicatedComputation.parameters = { x :0, y:0, ... ... };
// then when you want to call :
var params = complicatedComputation.parameters;
params.x = this.x ; params.y = this.y; ... ...
var res = complicatedComputation(params);
It has the drawback that previous calls parameters remains, so you don't get undefined if you don't
set them, but previous value, so you might have to change bit your function.
But on the other hand, if you call several times the function with similar parameters, it comes very handy.
Happy memory hunting !
Double buffering is a technique to reduce flickering: You draw to one buffer while another buffer is displayed, and then swap them out in a single operation, so the user doesn't see any of the drawing in a partial state.
However, it does not really help for performance problems at all, as there is still the same amount of drawing. I would not try to use double buffering if you don't have a problem with flickering, as it requires more memory and flickering may be implicitly prevented by the system by similar or other means.
If you think drawing the background is too expensive, there are several things that you could look into:
Do you scale the background image down while drawing? If so, create a downscaled version once and use this for clearing the background, reducing the drawing costs per iteration.
Remember the "dirty" areas and just draw the portions of the background that were obscured. This will add some management overhead but reduce the number of pixels that need to be touched significantly
Make the background the background image of the canvas DOM element and just clear the canvas to transparency in each iteration. If the canvas is very large, you could make this faster by remembering the "dirty" areas and just clearing them.
Are you sure painting the background is the main cause of lag? Do you still have lag when you only repaint the background and do not do much else?
I'm working on a multiple projectile simulator for a college project and I'm wondering how to best setup timing in JavaScript rendering to a HTML5 canvas
I'm using an Euler integrator setup for physics and accuracy is very important for this project. The rendering is very bare bones
My question is how to best setup the timing for all this.
Right now I have:
The physics and other logic running in a function that loops using setTimeout() with a fixed time step
The rendering in another function that loops using a requestAnimationFrame() call (flexible time step)
These two loops run sort of simultaneously (I know JavaScript doesn't really support threads without Web Workers) but I don't want the rendering (currently running at a much higher FPS than needed) to be unnecessarily 'stealing' CPU cycles from the physics simulation, if you see what I mean.
Given that physics accuracy is most important here how would you recommend setting up the timing system? (Maybe using Web Workers would be useful here but I havent seen this used in other engines)
Thanks!
I'd suggest that you don't try to 'multithread' unless you're actually doing it, and even then, I wouldn't necessarily recommend it.
The best way to keep everything in synch is to have a single thread of execution. A single setTimeout loop of about 33ms seems to work ok for my games.
Also, in my experience at least, setTimeout offers a much more aesthetic experience than setInterval or requestAnimationFrame. With setInterval, Javascript tries to hard to 'catch up' when frames are delivered late, which makes animation frames inconsistent. With requestAnimationFrame, frames are skipped to ensure a smooth running game, which actually makes things harder, because your users aren't entirely sure their view is up to date at any given second.
One way would be to set an interval for processing physics, and once per x frames, render everything.
var physicsTime;
var renderFrequency;
var frameCount;
setInterval(function(){updateStuff()},physicsTime);
then in updateStuff()
function updateStuff(){
frameCount ++;
if (frameCount >= renderFrequency){
frameCount -= renderFrequency;
render();
}
physics();
}
I'm making a little game with HTML5 and MooTools and I have performance problems on firefox. I have implemented a counter to determine how often my update method gets called and it returns 64 times per second. The result seems much much slower (like 30 FPS). I think my problem is actually described on this article http://blog.sethladd.com/2011/03/measuring-html5-browser-fps-or-youre.html. I couldn't find out a way to solve this directly, but I think I can optimize the perforance.
I think one big problem in my logic is that I draw every single object on the canvas directly. I have done some games in Java before and I had great performance improvements with manipulating an image (drawing in the memory) and drawing just the final image. This way the browser would have much less requests to draw something and perhaps draw faster.
Is there a way to do this? I have found some libraries for image manipulation in JavaScript, but I would like to do it myself.
I can't show you the full code, because the project is for school and because it is way too big (~1500 lines of code).
http://www.html5rocks.com/en/tutorials/canvas/performance/
Maybe this will help. It shows you how to improve performance by using an offscreen canvas to render your scene.
Right now I've got two game loops in a game I'm making. A draw loop that loops through an array of objects on screen and a logic loop that does game logic. I have the logic loop running about 10 more frames than the draw loop. I have this set up like this because doing game logic may take longer and I don't want it to interfere with the draw loop.
I have the logic loop set up like this:
vs.logicloop = function(){
vs.Gameloop();
//do the updating of object scripts
if(vs.windowActive){
var l = vs.scenegraph.length;
var i = 0;
while(i < l){
vs.scenegraph[i].logicScript();
i++;
}
}
//restart loop
setTimeout(vs.logicloop, 1000/(vs.fps+10));
};
and the draw loop like this:
vs.drawloop = function(){
//clear the screen
vsd.clr();
//goes through everything in the scene
//graph and draws it and runs each object's
//personal draw code
if(vs.windowActive){
var l = vs.scenegraph.length;
var i = 0;
while(i < l){
vs.ctx.save();
vs.scenegraph[i].update();
vs.scenegraph[i].draw();
vs.scenegraph[i].drawScript();
vs.ctx.restore();
i++;
}
}
//restart loop
setTimeout(vs.drawloop, 1000/vs.fps);
};
I'm using setTimeout because I heard that setInterval will cause loops to overlap if one isn't finished yet. Are there any optimizations I can do to really get some speed? Especially optimizing the game loops.
I've heard of some javascript engines getting thousands of objects on screen at once. I can't imagine how they do that, at most mine can get up to 100 objects on screen on a very old computer and about 700 on a reasonably stocked computer. And that's without a lot of game code running in the background and before I've worked out how to do pixel perfect collision detection and physics.
My process is to draw a background color fillRect over the canvas every draw loop, then looping through all the objects and drawing their draw code. Also it doesn't try to draw objects out of view.
This is my first paying job, and I really want to impress. Plus I can keep ownership of the engine once I'm done with the game.
Thanks A Lot
if you use floating values for sprite coordinates, try converting them to integers. that will cost you losing subpixel rendering but you will gain a lot of speed.
don't use images with odd widths. always use widths as powers of 2.
this one is hard to implement in some cases but if your game is suitable, don't clear screen and redraw everything each frame. instead, draw changed parts.
if you have to clear the canvas, don't draw a blank rectangle. try setting the canvas width/height again with the same size. that should reset the pixels faster than rectangle drawing.
rest of the methods i can suggest are not HTML5 canvas dependent but general subjects like using bit shiftings, inverse loops, and operator instead of modulo when possible, precalculations etc.
Oh geez, I could probably write you a full sonnet here if you posted all your code. Here's a quick rundown:
Read Emir's answer. All of those are good except the last one which is very dependent on the situation. Setting canvas.width = canvas.width to clear the canvas can be faster on some browsers but it also clobbers all canvas state (ie the last set fill and font) which can slow things down because setting those properties is actually painfully slow.
Read my articles on Canvas performance: http://simonsarris.com/blog/tag/performance
I have a lot of other tips saved up in a private document that I'm writing a small ebook out of. If you want early access to it I can probably allow that.
Pick up High performance JavaScript by Zakas and read it.
Don't use save() and restore() like you are in the quoted code unless you must. They are just slowing things down.
For the timer see http://paulirish.com/2011/requestanimationframe-for-smart-animating/
Multiple canvases for foreground-background-middleground can definitely help. Caching things on in-memory canvases can definitely help. It all depends on what you're drawing.
A lot of performance problems are due to death by a thousand tiny cuts. For instance:
vs.scenegraph[i].update();
vs.scenegraph[i].draw();
vs.scenegraph[i].drawScript();
To
var scene = vs.scenegraph[i];
scene.update();
scene.draw();
scene.drawScript();
Will help a minute amount. How many opportunities for minute-amount stuff you have I don't know - we'd need to see a lot more code.
I heard that setInterval will cause loops to overlap if one isn't finished yet.
This is false, JavaScript is single threaded. This means that if your first interval is still running when it hits the next step, the next step will be delayed until the first step has finished computing. This also means that you can't rely on setInterval to be accurate if you start doing a lot of computations.
I'd echo much of all has been said by other people. Integer values, use request animation frame, etc. If drawing text be careful how often you set fonts. Also you might find using an object pool can help if you are creating lots of temporary objects per frame.
As a general read on game loops I'd recommend this: http://www.koonsolo.com/news/dewitters-gameloop/