Jump to content

Images disappearing


mla
 Share

Recommended Posts

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!

Link to comment
Share on other sites

  • 3 weeks later...

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});
	});

 

Link to comment
Share on other sites

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

 

 

Link to comment
Share on other sites

@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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

@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.

Link to comment
Share on other sites

  • 2 weeks later...

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;
    }
});

 

Link to comment
Share on other sites

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? 

Link to comment
Share on other sites

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. 

 

sample.fw.png

Link to comment
Share on other sites

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!

Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...