I just started learning javascript, and i already faced some problems. I have a very simple "game" where you move red box with arrow keys and there is black background. I saw some topics about the same question and some of the guys says that make a buffer and other half says that don't do buffer because your browser does it for you. But anyway, I just thought that there is something wrong in my code because it's flickering but it's just so simple that i think it should not.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 600;
var mySprite = {
x: 200,
y: 200,
width: 50,
height: 50,
color: '#c00'
};
var yvel = 0;
var xvel = 0 ;
var moved = false;
var mspeed = 15;
var keysDown = {};
window.addEventListener('keydown', function(e) {
keysDown[e.keyCode] = true;
});
window.addEventListener('keyup', function(e) {
delete keysDown[e.keyCode];
});
function update() {
if (37 in keysDown) {
moved = true;
if(xvel > -mspeed){
xvel -= 0.5;
}
}
if (38 in keysDown) {
moved = true;
if(yvel > -mspeed){
yvel -= 0.5
}
}
if (39 in keysDown) {
moved = true;
if(xvel < mspeed){
xvel += 0.5
}
}
if (40 in keysDown) {
moved = true;
if(yvel < mspeed){
yvel += 0.5
}
}
mySprite.x += xvel;
mySprite.y += yvel;
if(moved == false){
xvel = xvel * 0.95;
yvel = yvel * 0.95;
}
moved = false;
}
function render() {
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = mySprite.color;
ctx.fillRect(mySprite.x, mySprite.y, mySprite.width, mySprite.height);
}
function run() {
update();
render();
}
setInterval(run, 1000/60);
You can try it here:w3school Just copy my code and put it inside tags and change the "MyCanvas" name to "canvas"
The double buffering is in fact allready activated on major browsers. What you need to do is to get in sync with the screen, that's what's provide requestAnimationFrame :
https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame
here's the polyfill for requestAnimationFrame :
requestAnimationFrame (rAF) is not standard yet : every 'vendor' i.e. browser (Chrome, FF, Safari, ...) has its own naming.
A polyfill is a piece of code that will 'install' a function in your environement whatever the vendor. Here you will be able to access requestAnimationFrame using window.requestAnimationFrame and you will not care any more about the vendor.
The || operator acts as a 'scan' : it will stop on the first 'truthy' ( == true) expression and return it without evaluating the remaining ones. So the last function definition, for instance, won't get evaluated if msRequestAnimationFrame is defined.
I have to add that the fallback in case requestAnimationFrame is not found is awfull : setTimeout has a very poor accuracy, but thankfully rAF will be found : it is allready there on Chrome(without prefix), Safari (webkit), IE >9 (ms), Firefox (moz) and Opera (o). )
and after exchanging update and render (way better), your run loop will be :
in any case you are interested, i discussed the javascript game loop here : http://gamealchemist.wordpress.com/2013/03/16/thoughts-on-the-javascript-game-loop/
Why would you need a timer ? the code above will call run again and again, since run ends by a defered call to run : run will be called next time display is available (typically 60 times per seconds). And you can know about the current time with Date.now().
For more insights about the game loop, rAF, and some time handling issues, see my link above.
Here is your code after some refactoring :
(fiddle is here : http://jsbin.com/uvACEVA/2/edit )