What's the difference between these two loops?

So, I’m trying to draw a tile set on the screen.
When I use a for loop, the tileset draws the lines correctly:
(ignore the tile on the middle, that’s a different draw)

This function is inside a Tile struct.

    fn draw_set(tile: Tile, width: usize, height: usize) void {
        var quad = tile;
        for (0..width) |x| {
            for (0..height) |z| {
                quad.position = Vector3{
                    .x = @as(f32, @floatFromInt(x)) - (@as(f32, @floatFromInt(width)) / 2), // Centering the grid
                    .y = 0.0,
                    .z = @as(f32, @floatFromInt(z)) - (@as(f32, @floatFromInt(height)) / 2), // Centering the gridPreformatted text
                };
                Tile.draw(Tile.verts(quad.position, 2), tile.color, rl.Color.gold);
            }
        }
    }

For Loop:

but when I try to use while loop, I get this:

    fn draw_set(tile: Tile, width: i32, height: i32) void {
        var x: i32 = 0;
        var z: i32 = 0;
        var quad = tile;
        while (x <= width) : (x += 1) {
            while (z <= height) : (z += 1) {
                quad.position = Vector3{
                    .x = @as(f32, @floatFromInt(x)) - (@as(f32, @floatFromInt(width)) / 2), // Centering the grid
                    .y = 0.0,
                    .z = @as(f32, @floatFromInt(z)) - (@as(f32, @floatFromInt(height)) / 2), // Centering the grid
                };
                Tile.draw(Tile.verts(quad.position, 2), tile.color, rl.Color.gold);
            }
        }
}

While Loop:

I’m perfectly fine to use the for loop, but I just don’t understand, why it’s not working with the while loop, as I think they are doing the same.

I don’t think that the problem is here, but here is the draw() function:

    fn draw(vertices: [4]Vector3, color: rl.Color, color_line: rl.Color) void {
        rl.drawTriangleStrip3D(&vertices, color);
        rl.drawLine3D(vertices[0], vertices[1], color_line);
        rl.drawLine3D(vertices[0], vertices[2], color_line);
        rl.drawLine3D(vertices[2], vertices[3], color_line);
        rl.drawLine3D(vertices[3], vertices[1], color_line);
    }

To get the same results, while conditions must be < (not <=) .

4 Likes

And you want to reset z = 0 inside the while loop over x.

6 Likes

Interesting, because your recommendation works with and without the change of the condition inside the while (< or <=)
But I still don’t understand, why zeroing out the z over x helps?
Why it drew the tiles and the line wasn’t?
Shouldn’t it draw the tiles only one row then?
Because the drawing of the tile and the surrounding lines over them are in the same draw() function.
What also interesting, if the for loop function is not inside this struct, it’s not making 8 rows and 8 columns, but 7. Isn’t for loop’s range exclusive at the end?

Since the second for loop is inside the first, each time the first for loop repeats it loops over the range 0 up to height again. By contrast the while loop code will run the inner loop only once. After the first run of the outer loop, z will already be equal to or greater than height, and the inner loop will just be skipped. Setting z to zero before running the inner loop fixes this problem.

2 Likes

Alternatively, you could move the declaration of z inside the outer loop. The scopes of both x and z would then more closely resemble the for loop version.

2 Likes

I suspect this is something to do with your Tile.verts() function. If you don’t mind sharing that it might help figure out why the tiles are drawing like that in the while loop.

Just a guess before you share but I think the tiles we see are overlapping making it seem like 8 independent rectangles but its actually 8 rectangles that are getting one tile taller every loop.

Here’s the verts() function:

    fn verts(position: Vector3, size: f32) [4]Vector3 {
        return .{
            Vector3.init(position.x * (size / 2), 0, position.z * (-size / 2)),
            Vector3.init(position.x * (-size / 2), 0, position.z * (-size / 2)),
            Vector3.init(position.x * (size / 2), 0, position.z * (size / 2)),
            Vector3.init(position.x * (-size / 2), 0, position.z * (size / 2)),
        };
    }

I guess you are right, that they are getting taller and taller.