package main import "base:intrinsics" import rl "vendor:raylib" import "common" import inf "infrastructure" Simulator :: struct { nodes: [dynamic]inf.Node, roads: [dynamic]inf.Road, temp_node_index: Maybe(u32), } init :: proc() -> Simulator { return { nodes = nil, roads = nil, temp_node_index = nil, } } deinit :: proc(self: ^Simulator) { self.temp_node_index = nil delete(self.roads) delete(self.nodes) } handle_input :: proc(self: ^Simulator, pos: rl.Vector2) { handle_keyboard_input(self) handle_mouse_input(self, pos) } @(private="file") handle_keyboard_input :: proc(self: ^Simulator) { if (rl.IsKeyReleased(.C)) { self.temp_node_index = nil clear(&self.roads) clear(&self.nodes) } } @(private="file") handle_mouse_input :: proc(self: ^Simulator, pos: rl.Vector2) { if (rl.IsMouseButtonReleased(.LEFT)) do left_click_event(self, pos) } @(private="file") left_click_event :: proc(self: ^Simulator, pos: rl.Vector2) { cur_node_index := get_selected_node(self, pos) if val, ok := self.temp_node_index.?; ok { road := inf.road_init(get_new_id(self, self.roads[:]), val, cur_node_index) append(&self.roads, road) self.temp_node_index = nil return } self.temp_node_index = cur_node_index } draw :: proc(self: ^Simulator, pos: rl.Vector2) { rl.ClearBackground(common.BACKGROUND_COLOUR) for &road in self.roads { start := road.nodes[0] end := road.nodes[1] rl.DrawLineEx(self.nodes[start].pos, self.nodes[end].pos, common.ROAD_SIZE, common.ROAD_COLOUR) } for &node in self.nodes { rl.DrawCircleV(node.pos, common.NODE_RADIUS, common.NODE_DONE_COLOUR) } // draw temp road if exists if val, ok := self.temp_node_index.?; ok { rl.DrawLineEx(self.nodes[val].pos, pos, common.ROAD_SIZE, common.ROAD_COLOUR) } } // Given position, the function will attempt the return the pointer to the node in near vicinity, // or if unsuccesful manually creating the node based on the position in the list and then returning the pointer to it @(private="file") get_selected_node :: proc(self: ^Simulator, pos: rl.Vector2) -> u32 { for node, index in self.nodes { if (!rl.CheckCollisionPointCircle(pos, node.pos, common.NODE_SNAP_RADIUS * common.NODE_RADIUS)) do continue return u32(index) } node := inf.node_init(get_new_id(self, self.nodes[:]), pos) append(&self.nodes, node) return u32(len(self.nodes) - 1) } @(private="file") get_new_id :: proc(self: ^Simulator, man: []$T) -> u32 where intrinsics.type_field_type(T, "id") == u32 { mlen := len(man) return mlen == 0 ? 0 : man[mlen - 1].id + 1 }