road manager fixes, node implementation

This commit is contained in:
Martin Vrhovšek 2025-07-21 20:51:39 +02:00
parent 3fc0687139
commit 2edda20571
5 changed files with 116 additions and 31 deletions

21
src/road/node.zig Normal file
View File

@ -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);
}
};

View File

@ -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;
}
};

View File

@ -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,

View File

@ -4,3 +4,9 @@ pub const AreaLocation = enum {
bottom_left,
bottom_right,
};
pub const InputMode = enum {
normal,
delete,
node,
};