2
\$\begingroup\$

I'm writing a minecraft clone in C++ and need some assisting with the chunk generation. Because I only want to load chunks that are near the player, I have to load and unload chunks based on the distance to the player.

Of course the naive approach would be:

glm::vec2 playerChunkPos = VoxelWorld::getChunkPosition(*playerPosition);
for(int x = -chunkRadius; x <= chunkRadius; x++){
    for(int y = -chunkRadius; y <= chunkRadius; y++){
        glm::vec2 chunkPos = playerChunkPos + glm::vec2(x, y);
        //Generate Chunk
    }
}

But the problem with this is, that it doesn't start nearest to the player. To fix that I'd like to generate in "circles", more like "boxes" around the player.

Here is a simple illustration of what I mean: (The Center is the player position)

EDIT: Just saw that I skipped 1 iteration, whoops...

How would you reach that kind of iteration or anything similliar? I couldn't get anything to work.. All coordinates are signed and can have any value! The center/player can also be anywhere!

\$\endgroup\$
5
\$\begingroup\$

First, we need to identify the square consists 4 symmetric sides, each of them of length 2*r.

1 1 1 1 2
4 x x x 2
4 x C x 2
4 x x x 2
4 3 3 3 3

As you can see, the sides are symmetric relative to center, that means we can can take one cell from each side in each iteration, one coordinate always fixed while the other controlled by offset. To make it easier to use for offsets, lets iterate 2*r cells from -r to <r.

for(int offset = -r; offset < r; offset++)
{
   auto pos1 = glm::vec2(c.x + offset, c.y - r);//side 1 
   auto pos2 = glm::vec2(c.x + r     , c.y + offset);//side 2 
   auto pos3 = glm::vec2(c.x - offset, c.y + r); //side 3 
   auto pos4 = glm::vec2(c.x - r     , c.y - offset); //side 4 
}

which leaves us with following ordering(number is step of cycle in which the coordinate was produced):

1 x x x 1    x 2 x x x    x x 3 x x    x x x 4 x
x x x x x    x x x x 2    x x x x x    4 x x x x
x x C x x -> x x C x x -> 3 x C x 3 -> x x C x x
x x x x x    2 x x x x    x x x x x    x x x x 4
1 x x x 1    x x x 2 x    x x 3 x x    x 4 x x x

the only part missing now is the outer loop iterating over chosen radii.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Makes sense! Because I'm a lazy f**k, I copied your code, and adapted it to my needs, but there is a strange diagonal line left! Here is a video of it: youtu.be/A5EsK6DYX-Q?t=14s \$\endgroup\$ – Kiryu144 Jun 24 '17 at 22:55
  • \$\begingroup\$ @Kiryu144 wierd, either last or first cell of 2 opposite sides is skipped? \$\endgroup\$ – wondra Jun 24 '17 at 23:18
  • \$\begingroup\$ Ahh yea, I found out. You have to write offset <= r instead of offset < r, which makes totally sense! Thanks! \$\endgroup\$ – Kiryu144 Jun 24 '17 at 23:22
  • \$\begingroup\$ I just edited your post, but because of that stupid minimum 6 character limit, I had to add that stupid comment. \$\endgroup\$ – Kiryu144 Jun 24 '17 at 23:31
  • \$\begingroup\$ @Kiryu144 the sign of y coordinate of side 2 and 4 were swapped, I think - can you confirm that it work now? (using offset<r, not with offset <=r where you get some cells twice) \$\endgroup\$ – wondra Jun 25 '17 at 0:53
0
\$\begingroup\$

You need to loop through between 0 and the draw distance, each time drawing one line from the square (-r, -r) to (-r, r - 1) . Each time you generate the square at that position. You can get the other lines by using the following formulas:

point1 = (x, y)
point2 = (y, -x)
point3 = (-x, -y)
point4 = (-y, x)

Generate each of these, this way you'll only need 1 loop.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.