mla Posted April 12, 2018 Share Posted April 12, 2018 My game is build for 6 players. Each player loads the game in a browser is assigned a unique room that displays a personal card and is represented by an avatar. The game works well, the images all load, however for some reason as more players access the game, some images may disappear. The player is actually still logged into the game and can even play the game, however their avatar image may have disappeared or their personal card may have disappeared. There is no consistency to which image may vanish and it doesn't always happen, but in most cases it does. Would anyone know why this may be? Thanks! Quote Link to comment Share on other sites More sharing options...
PsichiX Posted April 13, 2018 Share Posted April 13, 2018 low quality question - you should provide info about engine you use, maybe implementation you've done so far. Quote Link to comment Share on other sites More sharing options...
mla Posted May 2, 2018 Author Share Posted May 2, 2018 It's a node.js game built using canvas, html5 and socket.io with express. The game works, but the players seem to drop at times. Example, player 6 signs in and then we lose player 2. When a player joins the game, the player is broadcasted to all players and then I redraw all logged players. socket.on('new player', function(data, callback) { ... //broadcasting player to all players in gameID socket.broadcast.to(roomID).emit('setPosition', {id: newPlayer.id, x: newPlayer.getX, y: newPlayer.getY, imgFile: newPlayer.getImgFile, name: newPlayer.name}); //show all logged players in the gameID for (var i = 0; i < players.length; i++) { io.sockets.in(roomID).emit('setPosition', {id: players[i].id, x: players[i].getX, y: players[i].getY, imgFile: players[i].getImgFile, name: players[i].name}); } }); //Drawing of the players socket.on('setPosition', function(data){ context.clearRect(0, 0, canvas.width, canvas.height); var img = new Image(); function redraw() { context.drawImage(img, data.x, data.y, 85, 201); context.font = '12pt Arial'; context.fillStyle = 'white'; context.textAlign="center"; var rectHeight = 50; var rectWidth = 100; var rectX = data.x; var rectY = data.y+200; context.fillText(data.name, rectX+(rectWidth/2),rectY+(rectHeight/2)); requestAnimFrame(redraw); } img.src = data.imgFile; requestAnimFrame(redraw); }); socket.on('disconnect', function(data) { console.log("Disconnected to server socket" + socket.id); if (!socket.nickname) {return;} nicknames.splice(nicknames.indexOf(socket.nickname),1); var removePlayer = playerById(socket.id); players.splice(players.indexOf(removePlayer), 1); for (var i = 0; i < players.length; i++) { io.sockets.in(roomID).emit('setPosition', {id: players[i].id, x: players[i].getX, y: players[i].getY, imgFile: players[i].getImgFile, name: players[i].name}); } io.sockets.in(roomID).emit('logout message', {msg: data, nick: socket.nickname}); }); Quote Link to comment Share on other sites More sharing options...
b10b Posted May 3, 2018 Share Posted May 3, 2018 Server-side: Why send "ImgFile" on every update? Is "playerById()" method accurate? Client-side: "context" is cleared every update (per player), only last entry will survive. That could explain the erratic results? Quote Link to comment Share on other sites More sharing options...
mla Posted May 3, 2018 Author Share Posted May 3, 2018 ImgFile is the actual spirit file for the avatar. Each player has a different avatar when they access the game, placed on specified x and y coordinates. Here is the playerById() function. // Find player by ID function playerById(id) { var i; for (i = 0; i < players.length; i++) { if (players[i].id == id) return players[i]; }; return false; }; My logic for the clear context is as follows: New player connects to the game and is broadcasted to all connected players Clear the canvas and draw all connected players, so the new player can see all players who connected before him Quote Link to comment Share on other sites More sharing options...
b10b Posted May 3, 2018 Share Posted May 3, 2018 @mla From the code supplied, it appears to be clearing the context every time a setPosition message is received. And because you are sending multiple setPositions (one for each player during that disconnect) the issue you describe would be explained - i.e. only the last received player will show, but "who" was last will vary based on latency etc. But please don't patch this, redesign it - your message usage is flawed (you're shoehorning functionality into a message intended for something else). SetPosition should probably only set the position of a single player, not all of them in rapid succession, and not to include all of their static data every time too. SetPositions (plural) with an array of positions might be an improved approach, reduce messaging demands and allow for improved message handlers that will encourage you to decouple messaging from gameloop or rendering loop. Similarly there is likely no need to send ImgFile every time SetPosition occurs? Send it once when a new player connects, with a dedicated message, reference it later. Otherwise the size of your packets could get significant, and latency will increase. As a general rule, only send the smallest packet to describe the singular change needed to synchronise client and server. More bam,bam,bam rather than blahblahblah. And lastly, learn additional Javascript methods ... things like array.filter etc ... it will make everything easier. Quote Link to comment Share on other sites More sharing options...
mla Posted May 4, 2018 Author Share Posted May 4, 2018 Thanks @b10b. Everything is pretty clear. One question - my avatars are not moving or doing anything. They simply represent a player in a specific x,y location. What does move are chain-links that are attached to each avatar. These chain-links only appear after the Host starts the game. Meanwhile, players appear as avatars in a waiting room. Given the players are not moving, do you feel a game loop to show players is still required or do you feel it's only required for the chain-links? Thanks. Quote Link to comment Share on other sites More sharing options...
b10b Posted May 4, 2018 Share Posted May 4, 2018 @mla hard to give you solid advice on that without knowing a lot more. Generally I favour using a gameloop / tick for interactive applications as there's usually something happening on a heartbeat? Within the loop I'd visit the render method(s) and return-early if there's nothing to do. The data model can usually be asynchronously updated independently without interference. Sometimes it works better to buffer the async requests until the gameloop visits that section of the model, and then process / consolidate them all at that time. But no definitive rules, and my experience may relate to a different style of game than yours. Quote Link to comment Share on other sites More sharing options...
mla Posted May 14, 2018 Author Share Posted May 14, 2018 I have re-coded the game and now the players connect and disconnect correctly. I save the disconnected player details in an array before the disconnect to allow him/her to comeback. The issue I seem to now face, is why my avatars are flickering on screen. They work great, but the image flickers. I have an interval to loop through the players{} and draw them out. My assumption is that the requestAnimFrame function is needed here. In Server: //show all logged players setInterval(function(){ io.sockets.emit('state', PLAYER_LIST); } },1000/25); In Client: socket.on('state', function(players){ context.clearRect(0, 0, canvas.width, canvas.height); context.font = '12pt Arial'; context.fillStyle = 'white'; context.textAlign="center"; for (var id in players) { var player = players[id]; var rectHeight = 50; var rectWidth = 100; var rectX = player.getX; var rectY = player.getY+200; context.fillText(player.name, rectX+(rectWidth/2),rectY+(rectHeight/2)); var img = new Image(); img.onload = function () { context.drawImage(img, x, y, 85, 201); } img.src = imgFile; } }); Quote Link to comment Share on other sites More sharing options...
b10b Posted May 14, 2018 Share Posted May 14, 2018 Just in case I wasn't very clear, I was suggesting a gameloop / tick on the client (view). Server side can usually be limited to emitting changes. One concern with your code (as presented above) is the img.onload is async, so who knows when it will occur - it may (theoretically) occur after the next context clearRect, or even the next? What's the goal with img and imgFile because it looks wasteful to me? Quote Link to comment Share on other sites More sharing options...
mla Posted May 15, 2018 Author Share Posted May 15, 2018 Each person who joins the game, is represented by a specific avatar that is placed on the screen at specific x, y coordinates. I am attaching the screen shot that will hopefully provide a better explanation. The game works, just that the images are flickering. Quote Link to comment Share on other sites More sharing options...
b10b Posted May 15, 2018 Share Posted May 15, 2018 Righto, so if imgFile is already loaded, no need for the new Image for each player (and the async onload that is likely causing the glitch). Just use ImgFile in the context.drawImage command (synchronously): context.fillText(player.name, rectX+(rectWidth/2),rectY+(rectHeight/2)); context.drawImage(imgFile, x, y, 85, 201); Unsure what's populating x, y? Game looks interesting! Quote Link to comment Share on other sites More sharing options...
mla Posted May 16, 2018 Author Share Posted May 16, 2018 Worked like a charm!! Pre-loaded images, created gameloop on client and no flickering. Gameloop updates and draws images perfectly! Great help!! Thanks!! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.