summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/context.zig54
-rw-r--r--src/main.zig31
-rw-r--r--src/root.zig159
3 files changed, 244 insertions, 0 deletions
diff --git a/src/context.zig b/src/context.zig
new file mode 100644
index 0000000..f3e88f2
--- /dev/null
+++ b/src/context.zig
@@ -0,0 +1,54 @@
+const std = @import("std");
+const rl = @cImport(@cInclude("raylib.h"));
+const root = @import("root.zig");
+
+pub var camera: rl.Camera2D = undefined;
+pub var grid: []root.MyRect = undefined;
+
+pub const Grid = struct {
+ buffer: std.MultiArrayList(root.Hex),
+ cursor: usize,
+ size: usize,
+ const Self = @This();
+
+ const GridError = error{
+ OutOfBounds,
+ };
+
+ //TODO think about what size really means
+ pub fn init(
+ allocator: std.mem.Allocator,
+ size: usize,
+ ) !Grid {
+ var buffer: std.MultiArrayList(root.Hex) = .{};
+ try buffer.ensureTotalCapacity(allocator, size * size);
+ return .{
+ .buffer = buffer,
+ .cursor = 0,
+ .size = size,
+ };
+ }
+
+ // should only be used when standing up the buffer, afterwards should use q, r indexing
+ pub fn initPush(self: *Self, hex: root.Hex) GridError!void {
+ if (self.cursor >= self.size * 2) {
+ return GridError.OutOfBounds;
+ }
+ self.buffer.insertAssumeCapacity(self.cursor, hex);
+ }
+
+ pub fn set(self: *Self, hex: root.Hex) GridError!void {
+ const idx = hex.qr[1] * self.size + hex.qr[0];
+ if (idx >= self.size * 2) {
+ return GridError.OutOfBounds;
+ }
+
+ self.buffer.set(idx, hex);
+ }
+};
+pub var hex_grid: Grid = undefined;
+pub var hovered_coords: root.HexCoord = root.HexCoord{ .q = 0, .r = 0 };
+pub var hovered_handle: ?usize = null;
+
+var Gpa = std.heap.GeneralPurposeAllocator(.{}){};
+pub var gpa: std.mem.Allocator = Gpa.allocator();
diff --git a/src/main.zig b/src/main.zig
new file mode 100644
index 0000000..a3cfd2f
--- /dev/null
+++ b/src/main.zig
@@ -0,0 +1,31 @@
+const std = @import("std");
+const rl = @cImport(@cInclude("raylib.h"));
+const root = @import("root.zig");
+const context = @import("context.zig");
+
+pub fn main() !void {
+ const win_width = 960;
+ const win_height = 540;
+ rl.InitWindow(win_width, win_height, "shipit");
+
+ rl.SetTargetFPS(60);
+ defer rl.CloseWindow();
+
+ // Game State Initialization
+ try root.setup();
+ //
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!rl.WindowShouldClose()) {
+ try root.update();
+ try root.draw();
+ }
+}
+
+test "simple test" {
+ var list = std.ArrayList(i32).init(std.testing.allocator);
+ defer list.deinit(); // try commenting this out and see if zig detects the memory leak!
+ try list.append(42);
+ try std.testing.expectEqual(@as(i32, 42), list.pop());
+}
diff --git a/src/root.zig b/src/root.zig
new file mode 100644
index 0000000..286c0c2
--- /dev/null
+++ b/src/root.zig
@@ -0,0 +1,159 @@
+const std = @import("std");
+const rl = @cImport(@cInclude("raylib.h"));
+const context = @import("context.zig");
+
+const grid_size: usize = 21;
+const grid_central_row = grid_size / 2 + 1;
+
+pub const MyRect = struct {
+ rect: rl.Rectangle,
+ color: rl.Color,
+};
+
+const hex_radius: f32 = 100.0;
+const hex_rotation = 30.0;
+
+pub const HexCoord = struct {
+ q: i32,
+ r: i32,
+ pub inline fn fracS(q: f32, r: f32) f32 {
+ return -q - r;
+ }
+
+ pub inline fn index(self: HexCoord) usize {
+ return self.r / grid_size + self.q % grid_size;
+ }
+
+ pub inline fn qrToWorld(q: i32, r: i32) rl.Vector2 {
+ return .{
+ .x = hex_radius * (@sqrt(3.0) * @as(f32, @floatFromInt(q)) + @sqrt(3.0) / 2.0 * @as(f32, @floatFromInt(r))),
+ .y = hex_radius * (3.0 / 2.0 * @as(f32, @floatFromInt(r))),
+ };
+ }
+ pub inline fn worldToQr(point: rl.Vector2) HexCoord {
+ const q = (@sqrt(3.0) / 3.0 * point.x - 1.0 / 3.0 * point.y) / hex_radius;
+ const r = (2.0 / 3.0 * point.y) / hex_radius;
+
+ return axialRound(.{ .x = q, .y = r });
+ }
+ pub inline fn axialRound(frac: rl.Vector2) HexCoord {
+ return cubeRound(rl.Vector3{ .x = frac.x, .y = frac.y, .z = fracS(frac.x, frac.y) });
+ }
+
+ pub inline fn cubeRound(frac: rl.Vector3) HexCoord {
+ var q = @round(frac.x);
+ var r = @round(frac.y);
+ var s = @round(frac.z);
+
+ const q_diff = @abs(q - frac.x);
+ const r_diff = @abs(r - frac.y);
+ const s_diff = @abs(s - frac.z);
+
+ if (q_diff > r_diff and q_diff > s_diff) {
+ q = -r - s;
+ } else if (r_diff > s_diff) {
+ r = -q - s;
+ } else {
+ s = -q - r;
+ }
+
+ return .{
+ .q = @as(i32, @intFromFloat(q)),
+ .r = @as(i32, @intFromFloat(r)),
+ };
+ }
+};
+
+pub const Hex = struct {
+ // todo perhaps worth having a sentiental value somewhere to state if a hex is alive or perhaps make the list optinals?
+ color: rl.Color,
+};
+
+pub fn setup() !void {
+ const target = HexCoord.qrToWorld(grid_central_row, grid_central_row);
+ context.camera = rl.Camera2D{ .target = target, .offset = rl.Vector2{ .x = 0, .y = 0 }, .rotation = 0, .zoom = 1 };
+ context.hex_grid = try context.Grid.init(context.gpa, grid_size);
+
+ // TODO think what it means to populate a hex grid
+ for (0..grid_size) |_| {
+ for (0..grid_size) |_| {
+ try context.hex_grid.initPush(Hex{
+ // TODO real colors
+ .color = rl.DARKGREEN,
+ });
+ }
+ }
+}
+
+pub fn update() !void {
+ //----------------------------------------------------------------------------------
+
+ const mouse_pos = rl.GetMousePosition();
+ const mouse_world_pos = rl.GetScreenToWorld2D(mouse_pos, context.camera);
+
+ context.hovered_coords = HexCoord.worldToQr(mouse_world_pos);
+
+ const zoom_scale = context.camera.zoom;
+ if (rl.IsKeyDown(rl.KEY_D)) {
+ context.camera.target.x += 2 / zoom_scale;
+ }
+ if (rl.IsKeyDown(rl.KEY_A)) {
+ context.camera.target.x -= 2 / zoom_scale;
+ }
+ if (rl.IsKeyDown(rl.KEY_W)) {
+ context.camera.target.y -= 2 / zoom_scale;
+ }
+ if (rl.IsKeyDown(rl.KEY_S)) {
+ context.camera.target.y += 2 / zoom_scale;
+ }
+
+ if (rl.IsMouseButtonDown(rl.MOUSE_BUTTON_MIDDLE)) {
+ const delta = rl.GetMouseDelta();
+ context.camera.target.x -= delta.x / zoom_scale;
+ context.camera.target.y -= delta.y / zoom_scale;
+ }
+
+ const wm = rl.GetMouseWheelMove();
+ if (wm != 0.0) {
+ context.camera.zoom += wm * 0.05;
+
+ context.camera.target = mouse_world_pos;
+ context.camera.offset = mouse_pos;
+
+ if (context.camera.zoom > 3.0) context.camera.zoom = 3.0;
+ if (context.camera.zoom < 0.1) context.camera.zoom = 0.1;
+ }
+}
+pub fn draw() !void {
+ rl.BeginDrawing();
+
+ rl.ClearBackground(rl.SKYBLUE);
+
+ rl.BeginMode2D(context.camera);
+ const slice = context.hex_grid.buffer.slice();
+ const colors = slice.items(.color);
+ for (0..grid_size) |r| {
+ var start: usize = 0;
+ var end: usize = 0;
+ if (r < grid_central_row) {
+ start = grid_central_row - r;
+ end = grid_size;
+ } else {
+ start = 0;
+ end = grid_size - (r - grid_central_row);
+ }
+ for (start..end) |q| {
+ const idx = r * grid_size + q;
+ const center = HexCoord.qrToWorld(@intCast(q), @intCast(r));
+ rl.DrawPoly(center, 6, hex_radius, hex_rotation, colors[idx]);
+ rl.DrawPolyLines(center, 6, hex_radius, hex_rotation, rl.BLACK);
+ }
+ }
+
+ const center = HexCoord.qrToWorld(@intCast(context.hovered_coords.q), @intCast(context.hovered_coords.r));
+ rl.DrawPolyLines(center, 6, hex_radius, hex_rotation, rl.WHITE);
+
+ rl.EndMode2D();
+
+ rl.EndDrawing();
+}