I'm using socket.io in combination with Express to render a canvas multiplayer game, I wanted to use sprites and pixel art since the beginning, but when my canvas updates my sprite flickers a bit.
Here's the socket.io server code which first adds the connected player to players
dictionary and then checks for movement
emit in order to update players' position on the canvas :
let players = {};
io.on('connection', function (socket) {
players[socket.id] = { x: 300, y: 300};
socket.on('disconnect', function(){
delete players[socket.id];
});
socket.on('movement', function(data) {
let player = players[socket.id] || {};
if (data.left) {
player.x -= 5;
}
if (data.up) {
player.y -= 5;
}
if (data.right) {
player.x += 5;
}
if (data.down) {
player.y += 5;
}
});
});
// Here the server emits\send the "state" of the canvas
// looping passing the dictionary of players
setInterval(function() {
io.emit('state', players);
}, 1000 / 60);
And here's the client, where the problematic code is (imo):
var socket = io();
var width = window.innerWidth;
var height = window.innerHeight;
var movement = {
up: false,
down: false,
left: false,
right: false
}
document.addEventListener('keydown', function(event) {
switch (event.keyCode) {
case 65: // A
movement.left = true;
console.log("A");
break;
case 87: // W
movement.up = true;
console.log("W");
break;
case 68: // D
movement.right = true;
console.log("D");
break;
case 83: // S
movement.down = true;
console.log("S");
break;
}
});
document.addEventListener('keyup', function(event) {
switch (event.keyCode) {
case 65: // A
movement.left = false;
break;
case 87: // W
movement.up = false;
break;
case 68: // D
movement.right = false;
break;
case 83: // S
movement.down = false;
break;
}
});
/* end movements */
let canvas = document.getElementById('canvas');
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext('2d');
socket.on('state', function(players) {
// Clear the canvas so that the previous positions are erased
ctx.clearRect(0, 0, width, height);
// Everytime you update (frame) the state of the canvas draw all players on it
for (let id in players) {
let player = players[id];
// Drawing with fillRect = no flickering
//ctx.fillRect(player.x, player.y, 100, 100);
// Drawing my sprite image = flickering!
let image = new Image();
image.onload = function() {
ctx.mozImageSmoothingEnabled = true;
ctx.webkitImageSmoothingEnabled = true;
ctx.msImageSmoothingEnabled = true;
ctx.imageSmoothingEnabled = true;
ctx.drawImage(image, player.x, player.y);
};
image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAqCAYAAABYzsDTAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAUxJREFUWEftlk0KwjAQhb1CL9EjiD+4cyciint37goiiFAE1y506xkEV56gB/AC4jXcuIq8YmRME5MJqSJUeBT/vnnzOmlSq/3yNes3BDQfNHMthq1cy1H7TV4eK/hbbEmvLiDXWNJxR0BO2ZcKVxzAkU1OptUfvaD340qI07ogfO5Fpo6/Bu92NwJCJ7h6OZcxoAPqPAgcwPN2muceHH47pEIqOPy6T7RwOjXe01LBC6Max7GA5EKS73FF5uQ73phTkA5OC0dRxFtEX4F/ci1juewmPOd02aMA7YRGAjALLsGmmxkETh+3NufO7l0jkfMHcJZluawzyYUDCLA1f07eqktnuEve1ggKu/FzA3bY7e35WqrL54rpRMA2T/9QKhyF1AKmguwu1FOWrhgbSiG6Y5wXUJd3qfBgUZjaDXYTdQX+H15KB7p5t47jAzRfydFOtcn9AAAAAElFTkSuQmCC';
}
});
setInterval(function() {
socket.emit('movement', movement);
}, 1000 / 60);
The thing is that whenever I clean the canvas with ctx.clearRect(0, 0, width, height);
in my loop, I get some flickering, but only when using an image, if I use canvas shapes I get none.
Why is that so?
How do I avoid that flickering? I really need to use sprites and simple shapes are a no-no.
Is there a better way to "loop" in multiplayer using socket.io that I'm missing? (I read about animationframe but I didn't really understand how to implement it with socket.io).
Any little help is appreciated I've been struggling a lot with it.
src
, do it in itsonload
event handler. That should get rid of the flickering. But I am not too clear as if you are drawing data passed from socket or if you are really always drawing this hard-coded b64 image. If the second case, then you are doing it wrong: load your image once, store it in some accessible place, and draw it directly without changing its src ever during your game. – Kaiidonew Image()
, it throws an undefined, so I can't set src of an image object befpre everything else this way... how do I do?... Ouch. Anyway, clearing canvas on load of the image solved the major flickering issues, so thanks for that :) – K3nzie