From 2edda205712053616d15c75b9f6340d39ceb04ff Mon Sep 17 00:00:00 2001 From: Marto Date: Mon, 21 Jul 2025 20:51:39 +0200 Subject: [PATCH] road manager fixes, node implementation --- src/road/node.zig | 21 +++++++ src/{ => road}/road-data.zig | 0 src/road/road-manager.zig | 118 ++++++++++++++++++++++++++--------- src/road/road.zig | 2 +- src/structures.zig | 6 ++ 5 files changed, 116 insertions(+), 31 deletions(-) create mode 100644 src/road/node.zig rename src/{ => road}/road-data.zig (100%) diff --git a/src/road/node.zig b/src/road/node.zig new file mode 100644 index 0000000..bb7b17d --- /dev/null +++ b/src/road/node.zig @@ -0,0 +1,21 @@ +const std = @import("std"); +const rl = @import("raylib"); +const road_str = @import("road.zig"); +const road_data = @import("road-data.zig"); +const globals = @import("../globals.zig"); + +pub const Node = struct { + // road_sections: std.ArrayList(road_str.Road), + location: rl.Vector2, + // todo validation + + pub fn init(location: rl.Vector2) Node { + return Node{ + .location = location, + }; + } + + pub fn draw(self: *const Node) void { + rl.drawCircleV(self.location, globals.getScale() * road_data.road_thickness / @sqrt(2), .green); + } +}; diff --git a/src/road-data.zig b/src/road/road-data.zig similarity index 100% rename from src/road-data.zig rename to src/road/road-data.zig diff --git a/src/road/road-manager.zig b/src/road/road-manager.zig index 21bef6e..b004c73 100644 --- a/src/road/road-manager.zig +++ b/src/road/road-manager.zig @@ -1,14 +1,17 @@ const std = @import("std"); const rl = @import("raylib"); const road_str = @import("road.zig"); -const road_data = @import("../road-data.zig"); +const road_data = @import("road-data.zig"); +const node_str = @import("node.zig"); const globals = @import("../globals.zig"); +const str = @import("../structures.zig"); pub const RoadManager = struct { buffer: f32, allocator: std.mem.Allocator, roads: std.ArrayList(road_str.Road), - delete_mode: bool, + nodes: std.ArrayList(node_str.Node), + mode: str.InputMode, selected_road: ?usize, pub fn init(allocator: std.mem.Allocator) RoadManager { @@ -16,13 +19,15 @@ pub const RoadManager = struct { .buffer = road_data.road_thickness * globals.getScale() / 2.0, .allocator = allocator, .roads = std.ArrayList(road_str.Road).init(allocator), - .delete_mode = false, + .nodes = std.ArrayList(node_str.Node).init(allocator), + .mode = str.InputMode.normal, .selected_road = null, }; } pub fn deinit(self: *RoadManager) void { self.roads.deinit(); + self.nodes.deinit(); } fn addRoad(self: *RoadManager, pos: rl.Vector2) !void { @@ -46,54 +51,102 @@ pub const RoadManager = struct { } fn trackRoad(self: *RoadManager, pos: rl.Vector2) void { - if (!self.delete_mode) return; + if (self.mode != str.InputMode.delete) return; - self.setDefaultColour(); - self.selected_road = null; + self.resetTrackedRoad(); - for (self.roads.items) |*road| { + for (0..self.roads.items.len) |i| { // we skip because that road is not complete - if (road.end_point == null) continue; + if (self.roads.items[i].end_point == null) continue; + std.debug.print("tracking pt1\n", .{}); - if (cursorOnRoad(road.start_point, pos, road.end_point)) { - road.*.setColor(true); - // todo pointer or index + if (self.cursorOnRoad(self.roads.items[i].start_point, pos, self.roads.items[i].end_point.?)) { + std.debug.print("tracking pt2", .{}); + self.roads.items[i].setColor(true); + self.selected_road = i; break; } } } - fn cursorOnRoad(start: rl.Vector2, cursor: rl.Vector2, end: rl.Vector2) bool {} + fn cursorOnRoad(self: *const RoadManager, start: rl.Vector2, cursor: rl.Vector2, end: rl.Vector2) bool { + const min_x = @min(start.x, end.x) - self.buffer; + const max_x = @max(start.x, end.x) + self.buffer; + const min_y = @min(start.y, end.y) - self.buffer; + const max_y = @max(start.y, end.y) + self.buffer; + + if (!(cursor.x >= min_x and cursor.x <= max_x and cursor.y >= min_y and cursor.y <= max_y)) return false; + + const sc = rl.Vector2{ .x = start.x - cursor.x, .y = start.y - cursor.y }; + const se = rl.Vector2{ .x = start.x - end.x, .y = start.y - end.y }; + + const prod = @abs(sc.x * se.y - sc.y * se.x); + const road_length = @sqrt((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y)); + const threshold = road_length * self.buffer; + + return prod <= threshold; + } + + fn cancelRoadbuilding(self: *RoadManager) void { + // if we're in process of building a new road cancel it + const last_road = self.roads.getLastOrNull(); + if (last_road != null and last_road.?.end_point == null) + self.removeLastRoad(); + } pub fn inputHandler(self: *RoadManager) !void { const pos = rl.getMousePosition(); - trackRoad(pos); + self.trackRoad(pos); - // mouse inputs - if (rl.isMouseButtonReleased(.left)) { - if (self.delete_mode) { - if (self.selected_road == null) return; - // todo might be a problem in the future swapping modes must clear any unfinished roads! - self.roads.swapRemove(self.selected_road.?); - } else { - try self.addRoad(pos); - } - } else if (rl.isMouseButtonReleased(.right)) { - self.removeLastRoad(); - } + try self.handleMouseInput(); + self.handleKeyboardInput(); + } + + fn handleKeyboardInput(self: *RoadManager) void { // keyboard inputs if (rl.isKeyReleased(.c)) { self.clearRoads(); } else if (rl.isKeyReleased(.d)) { - self.delete_mode = !self.delete_mode; - if (!self.delete_mode) { - self.setDefaultColour(); - self.selected_road = null; - } + self.toggleDeleteMode(); } } + fn handleMouseInput(self: *RoadManager) !void { + // mouse inputs + if (rl.isMouseButtonReleased(.left)) { + try self.handleLeftClick(); + } else if (rl.isMouseButtonReleased(.right)) { + self.removeLastRoad(); + } + } + + fn handleLeftClick(self: *RoadManager) !void { + switch (self.mode) { + .normal => try self.addRoad(rl.getMousePosition()), + .delete => { + if (self.selected_road == null) return; + + _ = self.roads.swapRemove(self.selected_road.?); + self.selected_road = null; + }, + .node => {}, + } + } + + fn toggleDeleteMode(self: *RoadManager) void { + if (self.mode == str.InputMode.delete) { + self.resetTrackedRoad(); + } + + self.cancelRoadbuilding(); + self.mode = switch (self.mode) { + .normal => str.InputMode.delete, + .delete => str.InputMode.normal, + .node => self.mode, + }; + } + pub fn draw(self: *const RoadManager) void { for (self.roads.items) |road| { road.draw(); @@ -110,4 +163,9 @@ pub const RoadManager = struct { road.setColor(false); } } + + fn resetTrackedRoad(self: *RoadManager) void { + self.setDefaultColour(); + self.selected_road = null; + } }; diff --git a/src/road/road.zig b/src/road/road.zig index 6e63fa1..2784b38 100644 --- a/src/road/road.zig +++ b/src/road/road.zig @@ -1,6 +1,6 @@ const rl = @import("raylib"); const globals = @import("../globals.zig"); -const road_data = @import("../road-data.zig"); +const road_data = @import("road-data.zig"); pub const Road = struct { color: rl.Color, diff --git a/src/structures.zig b/src/structures.zig index f169ed2..8c6a988 100644 --- a/src/structures.zig +++ b/src/structures.zig @@ -4,3 +4,9 @@ pub const AreaLocation = enum { bottom_left, bottom_right, }; + +pub const InputMode = enum { + normal, + delete, + node, +};