3
\$\begingroup\$

I'm making a small voxel-based multiplayer WebGL game with a Node.JS server which handles player positions and sends terrain chunk data to the clients. This is an example of how I'm currently sending the chunks:

var viewDistance = 6;

for (var x = playerPosX - viewDistance; x < playerPosX + viewDistance; x++)
for (var z = playerPosZ - viewDistance; z < playerPosZ + viewDistance; z++)
for (var y = playerPosY - viewDistance; y < playerPosY + viewDistance; y++) {
    client.send( getChunk(x, y, z) );
}

This simply loads and sends the chunks within the view distance, however I'm looking for a way to prioritize sending the chunks nearest to the player first. Obviously it's no good loading chunks that are far away before loading the one the player is standing on.

Assuming playerPosX, playerPosZ and playerPosY store the positions of the player and client.send( getChunk(x, y, z) ) will send the chunk, does any one have any ideas how I would do this? Thanks.

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

I would do something like this:

    var vd = 6; //view distance
    var v = vd*2+1; //length of cube of chunks we want to send
    var s = new Array(v*v*v); //used to store which chunks we have sent
    for(var i=0; i<s.length; ++i) { s[i] = false; }
    for(var i=0; i<=vd; i++){ //start at center and move out layer by layer
        for(var x=-i; x<=i; x++){ //get all chunks inside current layer
            for(var y=-i; y<=i; y++){
                for(var z=-i; z<=i; z++){
                    if(!s[(x+vd)+(y+vd)*v+(z+vd)*v*v]){ //exclude already sent chunks
                        client.send( getChunk(x+plX, y+plY, z+plZ)); //send chunk
                        s[(x+vd)+(y+vd)*v+(z+vd)*v*v]=true; //mark chunk as sent
                    }
                }                   
            }               
        }
    }

I may have made a mistake somewhere since I've never used JavaScript before, but I think the comments should make it clear what I mean.

This assumes your player doesn't move off of the current chunk while while the loop is in progress, if that's possible you would need to either restart the loop or use some other method for storing which chunks you have already sent to the client.

\$\endgroup\$
3
\$\begingroup\$

enter image description here

Split the loading into sections (the white chunk is the one you are standing on). The above image shows the x and y axes, with the z axis left to your imagination.

Begin by sending the white chunk (playerPosX, playerPosY, playerPosZ). After that start moving outward along each axis, in both directions (+x, -x, +y, -y, +z, -z). Going outward, along each coloured section (+x, -x, +y, -y):

Distance 1: send 2 x 2 chunks
Distance 2: send 4 x 4 chunks
Distance 3: send 6 x 6 chunks

Along the +z section:

Distance 1: send 3 x 3 chunks
Distance 2: send 5 x 5 chunks
Distance 3: send 7 x 7 chunks

-z section:

Distance 1: send 1 x 1 chunks
Distance 2: send 3 x 3 chunks
Distance 3: send 5 x 5 chunks

As (pseudo) code:

sendChunk(playerPosX, playerPosY, playerPosZ);

for (var i = 1; i < distance; i++) {
    //Green
    for (var y = 0; y < i * 2; y++) {
        for (var z = 0; z < i * 2; z++) {
            sendChunck(playerPosX - i, 
                       playerPosY + (i - 1) - y,
                       playerPosZ + (i - 1) - z);
        }
    }

    //Do the same for yellow, blue, red, with different axes
    //Do (almost) the same along +z and -z
}

You could also further improve the solution by starting from the center of each "layer" you send, using the exact same technique of sectioning. The image above could represent a 7 x 7 layer being sent.

The resulting code won't be very concise, but you will only be iterating through each chunk a single time, making it of time complexity O(n).

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .