this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: world generation using axial coord

+115 -53
+19 -16
src/hex.zig
··· 6 6 7 7 pub const Point = struct { x: f32, y: f32 }; 8 8 9 - // Cubic coordinates: q + r + s = 0 constraint 10 - pub const Cubic = struct { 9 + // Axial coordinates: q + r + s = 0 constraint 10 + // s = -q-r 11 + pub const Axial = struct { 11 12 q: i32, 12 13 r: i32, 13 14 s: i32, 14 15 15 - pub fn init(q: i32, r: i32) Cubic { 16 + pub fn init(q: i32, r: i32) Axial { 16 17 return .{ .q = q, .r = r, .s = -q - r }; 17 18 } 18 19 19 - pub fn add(self: Cubic, other: Cubic) Cubic { 20 + pub fn add(self: Axial, other: Axial) Axial { 20 21 return .{ .q = self.q + other.q, .r = self.r + other.r, .s = self.s + other.s }; 21 22 } 22 23 23 - pub fn sub(self: Cubic, other: Cubic) Cubic { 24 + pub fn sub(self: Axial, other: Axial) Axial { 24 25 return .{ .q = self.q - other.q, .r = self.r - other.r, .s = self.s - other.s }; 25 26 } 26 27 27 - pub fn neighbor(self: Cubic, dir: Direction) Cubic { 28 + pub fn neighbor(self: Axial, dir: Direction) Axial { 28 29 return self.add(direction_vectors[@intFromEnum(dir)]); 29 30 } 30 31 31 - pub fn toPixel(self: Cubic, size: f32) Point { 32 + pub fn toPixel(self: Axial, size: f32) Point { 32 33 const q: f32 = @floatFromInt(self.q); 33 34 const r: f32 = @floatFromInt(self.r); 34 35 return .{ ··· 37 38 }; 38 39 } 39 40 40 - pub fn toOffset(self: Cubic) Offset { 41 + // flat-top odd-q 42 + pub fn toOffset(self: Axial) Offset { 41 43 const col = self.q; 42 - const row = self.r + @divFloor(self.q, 2); 44 + const row = self.r + @divFloor(self.q - (self.q & 1), 2); 43 45 return .{ .col = col, .row = row }; 44 46 } 45 47 }; ··· 48 50 col: i32, 49 51 row: i32, 50 52 51 - pub fn toCubic(self: Offset) Cubic { 53 + // flat-top odd-q 54 + pub fn toAxial(self: Offset) Axial { 52 55 const q = self.col; 53 - const r = self.row - @divFloor(self.col, 2); 54 - return Cubic.init(q, r); 56 + const r = self.row - @divFloor(self.col - (self.col & 1), 2); 57 + return Axial.init(q, r); 55 58 } 56 59 }; 57 60 58 - const direction_vectors = [6]Cubic{ 61 + const direction_vectors = [6]Axial{ 59 62 .{ .q = 0, .r = -1, .s = 1 }, // top_left 60 63 .{ .q = 1, .r = -1, .s = 0 }, // top 61 64 .{ .q = 1, .r = 0, .s = -1 }, // top_right ··· 64 67 .{ .q = -1, .r = 0, .s = 1 }, // bottom_left 65 68 }; 66 69 67 - pub const HexCell = struct { inner_radius: f32, outer_radius: f32, height: f32, width: f32, center: Point, cubic: Cubic }; 70 + pub const HexCell = struct { inner_radius: f32, outer_radius: f32, height: f32, width: f32, center: Point, cubic: Axial }; 68 71 pub const Cell = HexCell; 69 72 70 73 pub const HexDirections = enum { top_left, top, top_right, bottom_right, bottom, bottom_left }; ··· 88 91 return Point{ .x = center.x + x_offset, .y = center.y + y_offset }; 89 92 } 90 93 91 - pub fn new_hex(outer_radius: f32, cubic: Cubic) HexCell { 94 + pub fn new_hex(outer_radius: f32, cubic: Axial) HexCell { 92 95 const size = outer_radius; 93 96 const inner = calculate_inner_radius(size); 94 97 const center = cubic.toPixel(size); ··· 98 101 pub fn new_hex_at(outer_radius: f32, center: Point) HexCell { 99 102 const size = outer_radius; 100 103 const inner = calculate_inner_radius(size); 101 - return HexCell{ .inner_radius = inner, .outer_radius = size, .height = sqrt_3 * size, .width = 2 * size, .center = center, .cubic = Cubic.init(0, 0) }; 104 + return HexCell{ .inner_radius = inner, .outer_radius = size, .height = sqrt_3 * size, .width = 2 * size, .center = center, .cubic = Axial.init(0, 0) }; 102 105 } 103 106 104 107 pub fn add_hex(base: HexCell, direction: HexDirections) HexCell {
+55 -36
src/main.zig
··· 2 2 const lib = @import("zig_civ"); 3 3 const rl = @import("raylib"); 4 4 5 + const screen_offset_x: f32 = 400.0; // center of 800px screen 6 + const screen_offset_y: f32 = 225.0; // center of 450px screen 7 + 5 8 fn draw_hex(hex: lib.hex.HexCell) void { 6 9 var corners: [6]lib.hex.Point = undefined; 7 10 for (0..6) |i| { ··· 13 16 const start = corners[i]; 14 17 const end = corners[@mod(i + 1, 6)]; 15 18 16 - std.debug.print("sx: {d} sy: {d} ex:{d} ey:{d}\n", .{ start.x, start.y, end.x, end.y }); 17 - 18 - const start_x: i32 = @intFromFloat(@round(start.x)); 19 - const start_y: i32 = @intFromFloat(@round(start.y)); 20 - const end_x: i32 = @intFromFloat(@round(end.x)); 21 - const end_y: i32 = @intFromFloat(@round(end.y)); 19 + const start_x: i32 = @intFromFloat(@round(start.x + screen_offset_x)); 20 + const start_y: i32 = @intFromFloat(@round(start.y + screen_offset_y)); 21 + const end_x: i32 = @intFromFloat(@round(end.x + screen_offset_x)); 22 + const end_y: i32 = @intFromFloat(@round(end.y + screen_offset_y)); 22 23 23 24 rl.drawLine(start_x, start_y, end_x, end_y, .black); 24 25 } 25 26 } 26 27 27 - pub fn main() anyerror!void { 28 + pub fn main() !void { 29 + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 30 + defer _ = gpa.deinit(); 31 + const allocator = gpa.allocator(); 32 + 33 + // Axial template: 7x7 grid, center at [3][3], indexed [r+3][q+3] 34 + // Hexagon shape for radius 3 35 + //const template = [7][7]u1{ 36 + //// q: -3 -2 -1 0 1 2 3 37 + //.{ 0, 0, 0, 1, 1, 1, 1 }, // r = -3 38 + //.{ 0, 0, 1, 1, 1, 1, 1 }, // r = -2 39 + //.{ 0, 1, 1, 1, 1, 1, 1 }, // r = -1 40 + //.{ 1, 1, 1, 1, 1, 1, 1 }, // r = 0 41 + //.{ 1, 1, 1, 1, 1, 1, 0 }, // r = 1 42 + //.{ 1, 1, 1, 1, 1, 0, 0 }, // r = 2 43 + //.{ 1, 1, 1, 1, 0, 0, 0 }, // r = 3 44 + //}; 45 + 46 + //const template_rombus = [7][7]u1{ 47 + //.{ 1, 1, 1, 1, 1, 1, 1 }, 48 + //.{ 1, 1, 1, 1, 1, 1, 1 }, 49 + //.{ 1, 1, 1, 1, 1, 1, 1 }, 50 + //.{ 1, 1, 1, 1, 1, 1, 1 }, 51 + //.{ 1, 1, 1, 1, 1, 1, 1 }, 52 + //.{ 1, 1, 1, 1, 1, 1, 1 }, 53 + //.{ 1, 1, 1, 1, 1, 1, 1 }, 54 + //}; 55 + 56 + const template_left_triangle = [7][7]u1{ 57 + .{ 1, 1, 1, 1, 1, 1, 1 }, 58 + .{ 1, 1, 1, 1, 1, 1, 0 }, 59 + .{ 1, 1, 1, 1, 1, 0, 0 }, 60 + .{ 1, 1, 1, 1, 0, 0, 0 }, 61 + .{ 1, 1, 1, 0, 0, 0, 0 }, 62 + .{ 1, 1, 0, 0, 0, 0, 0 }, 63 + .{ 1, 0, 0, 0, 0, 0, 0 }, 64 + }; 65 + 66 + const template = template_left_triangle; 67 + 68 + var grid = try lib.world.generateFromTemplate(3, &template, 40.0, allocator); 69 + defer grid.deinit(allocator); 70 + 28 71 // Initialization 29 - //-------------------------------------------------------------------------------------- 30 72 const screenWidth = 800; 31 73 const screenHeight = 450; 32 74 const fps = 60; 33 75 34 76 rl.initWindow(screenWidth, screenHeight, "raylib.hex-zig [core] example - basic window"); 35 - defer rl.closeWindow(); // Close window and OpenGL context 77 + defer rl.closeWindow(); 36 78 37 - rl.setTargetFPS(fps); // Set our game to run at 60 frames-per-second 38 - //-------------------------------------------------------------------------------------- 79 + rl.setTargetFPS(fps); 39 80 40 81 // Main game loop 41 - while (!rl.windowShouldClose()) { // Detect window close button or ESC key 42 - // Update 43 - //---------------------------------------------------------------------------------- 44 - // TODO: Update your variables here 45 - //---------------------------------------------------------------------------------- 46 - const template = [5][8]u1{ 47 - .{ 1, 1, 1, 1, 1, 1, 1, 1 }, 48 - .{ 1, 1, 1, 0, 0, 1, 1, 1 }, 49 - .{ 1, 1, 0, 0, 0, 0, 1, 1 }, 50 - .{ 1, 1, 1, 0, 0, 1, 1, 1 }, 51 - .{ 1, 1, 1, 1, 1, 1, 1, 1 }, 52 - }; 53 - const grid = lib.world.generateWorld(5, 8, &template, 40.0); 54 - 55 - // Draw 56 - //---------------------------------------------------------------------------------- 82 + while (!rl.windowShouldClose()) { 57 83 rl.beginDrawing(); 58 84 defer rl.endDrawing(); 59 85 60 86 rl.clearBackground(.white); 61 87 62 - for (grid) |row| { 63 - for (row) |maybe_cell| { 64 - if (maybe_cell) |cell| { 65 - draw_hex(cell); 66 - } 67 - } 88 + for (grid.items) |cell| { 89 + draw_hex(cell); 68 90 } 69 - 70 - //rl.drawText("Congrats! You created your first window!", 190, 200, 20, .light_gray); 71 - //---------------------------------------------------------------------------------- 72 91 } 73 92 }
+41 -1
src/world.zig
··· 2 2 const hex = @import("hex.zig"); 3 3 const tst = std.testing; 4 4 5 + // Generate hexagon-shaped map with given radius (N rings around center) 6 + // Uses axial coords: |q|<=N, |r|<=N, |q+r|<=N 7 + pub fn generateHexWorld(comptime N: i32, outer_radius: f32, allocator: std.mem.Allocator) !std.ArrayListUnmanaged(hex.Cell) { 8 + var cells = std.ArrayListUnmanaged(hex.Cell){}; 9 + 10 + var q: i32 = -N; 11 + while (q <= N) : (q += 1) { 12 + const r1 = @max(-N, -q - N); 13 + const r2 = @min(N, -q + N); 14 + var r: i32 = r1; 15 + while (r <= r2) : (r += 1) { 16 + try cells.append(allocator, hex.new_hex(outer_radius, hex.Axial.init(q, r))); 17 + } 18 + } 19 + 20 + return cells; 21 + } 22 + 23 + // Template-based generation using axial coords 24 + // Template indexed by [r][q] where r,q range from -N to +N 25 + // Template size is (2*N+1) x (2*N+1), center is at [N][N] 26 + pub fn generateFromTemplate(comptime N: i32, template: *const [2 * N + 1][2 * N + 1]u1, outer_radius: f32, allocator: std.mem.Allocator) !std.ArrayListUnmanaged(hex.Cell) { 27 + var cells = std.ArrayListUnmanaged(hex.Cell){}; 28 + 29 + var q: i32 = -N; 30 + while (q <= N) : (q += 1) { 31 + var r: i32 = -N; 32 + while (r <= N) : (r += 1) { 33 + const ti_r: usize = @intCast(r + N); 34 + const ti_q: usize = @intCast(q + N); 35 + if (template[ti_r][ti_q] == 1) { 36 + try cells.append(allocator, hex.new_hex(outer_radius, hex.Axial.init(q, r))); 37 + } 38 + } 39 + } 40 + 41 + return cells; 42 + } 43 + 44 + // Old template-based generation (offset coords) 5 45 pub fn generateWorld(comptime H: usize, comptime W: usize, template: *const [H][W]u1, outer_radius: f32) [H][W]?hex.Cell { 6 46 var grid: [H][W]?hex.Cell = undefined; 7 47 ··· 9 49 for (0..W) |col| { 10 50 if (template[row][col] == 1) { 11 51 const offset = hex.Offset{ .col = @intCast(col), .row = @intCast(row) }; 12 - grid[row][col] = hex.new_hex(outer_radius, offset.toCubic()); 52 + grid[row][col] = hex.new_hex(outer_radius, offset.toAxial()); 13 53 } else { 14 54 grid[row][col] = null; 15 55 }