Files
traffic-simulator/src/infrastructure/road_manager.zig

137 lines
4.4 KiB
Zig

const std = @import("std");
const rl = @import("raylib");
const e = @import("../errors.zig");
const st = @import("../common/structures.zig");
const ut = @import("../common/utils.zig");
const Road = @import("road.zig").Road;
const Node = @import("node.zig").Node;
pub const RoadManager = struct {
next_id: usize,
roads: std.ArrayList(*Road),
pub fn init() RoadManager {
return .{
.next_id = 0,
.roads = .empty,
};
}
/// Deinitialises every road (pointer) and then the list itself
pub fn deinit(self: *RoadManager, allocator: std.mem.Allocator) void {
for (self.roads.items) |road| {
road.deinit(allocator);
}
self.roads.deinit(allocator);
}
/// Draws all the roads in the list, sends the information ahead whether the road drawn should be highlighted
pub fn draw(self: *const RoadManager, highlighted_road: ?*Road, display_info: bool) void {
for (self.roads.items) |road| {
const is_highlighted = if (highlighted_road) |h_road| road == h_road else false;
road.draw(is_highlighted, display_info);
}
}
/// Function which creates the road object, its pointer, adds it to the list
/// and then also references that same road to the bounding nodes
pub fn addRoad(self: *RoadManager, allocator: std.mem.Allocator, start: *Node, end: *Node) !void {
const road_ptr = try allocator.create(Road);
road_ptr.* = Road.init(self.getNextID(), start, end);
try self.roads.append(allocator, road_ptr);
const ref = self.roads.items[self.roads.items.len - 1];
try start.referenceRoad(allocator, ref);
try end.referenceRoad(allocator, ref);
}
/// Returns the id, and increases it by one; used for generating ID's for new entities
fn getNextID(self: *RoadManager) usize {
const id = self.next_id;
self.next_id += 1;
return id;
}
/// Deinits all the roads, clears them but not deiniting the list itself; also resets the next ID var
pub fn clear(self: *RoadManager, allocator: std.mem.Allocator) void {
for (self.roads.items) |road| {
road.deinit(allocator);
}
self.roads.clearRetainingCapacity();
self.next_id = 0;
}
/// Removes the references of the road, from the nodes that bound that road
///
/// Then it deinitialises the road and removes it from the list
///
/// Will return an error if the road itself is not present in the list
pub fn deleteRoad(self: *RoadManager, allocator: std.mem.Allocator, road_to_delete: *Road) !void {
// unreference the road from its bounding functions
road_to_delete.unreferenceNodes() catch |err| {
std.debug.panic("Failed to unreference the road from its nodes: {}\n", .{err});
};
for (0..self.roads.items.len) |i| {
if (self.roads.items[i] != road_to_delete) continue;
road_to_delete.deinit(allocator);
_ = self.roads.swapRemove(i);
return;
}
return e.Entity.NotFound;
}
/// Returns if pos is pointing at a road, or null if it isn't at any
pub fn getHighlightedRoad(self: *const RoadManager, pos: Vector2) ?*Road {
for (self.roads.items) |road| {
if (road.collides(pos)) return road;
}
return null;
}
};
const Vector2 = @import("raylib").Vector2;
const expect = std.testing.expect;
test "id tracking" {
var gpa: std.heap.DebugAllocator(.{}) = .init;
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var road_man: RoadManager = .init();
defer road_man.deinit(allocator);
const n = 5;
const start: Node = .init(0, .{.x = 0, .y = 0});
const start_ptr = try allocator.create(Node);
start_ptr.* = start;
const end: Node = .init(1, .{.x = 100, .y = 100});
const end_ptr = try allocator.create(Node);
end_ptr.* = end;
defer {
start_ptr.deinit(allocator);
end_ptr.deinit(allocator);
allocator.destroy(start_ptr);
allocator.destroy(end_ptr);
}
for (0..n) |_| {
try road_man.addRoad(allocator, start_ptr, end_ptr);
}
try expect(road_man.next_id == n);
try expect(road_man.roads.items.len == n);
}
// TODO tests
// force resize pointer test
// add, remove road
// destroy road and then verify the nodes do not have a pointer to it