//! The map contains all the items that make up the world. //! //! There are two main structs to look out for, the first being [Map]. This is the interaction point //! for most parts of the program. It contains the actual elements that are drawn on the screen. and //! can be changed by the user. //! The second is [MapData] and it contains the data that can be saved/loaded and distributed. Every //! map item has an internal item that it can be dereferenced to and can be used to construct this //! exact item in the same world elsewhere or at a different time. This is often different from the //! item that is being drawn. An example would be the [PolygonRoom], which contains a triangulated //! version of itself, so it can be drawn without always having to compute the triangles every frame. //! It's data type however [PolygonRoomData] contains only the raw polygon data, not the triangulated //! version, since that is enough to create the same [PolygonRoom] again. pub mod data; pub mod icon; pub mod icon_renderer; pub mod mappable; pub mod room; pub mod wall; pub use data::MapData; pub use icon::*; pub use mappable::Mappable; pub use room::*; pub use wall::*; use crate::transform::Transform; use icon_renderer::IconRenderer; use raylib::drawing::RaylibDrawHandle; use raylib::{RaylibHandle, RaylibThread}; use std::rc::Rc; /// The map containing all map elements that are seen on the screen. pub struct Map { rooms: Vec, walls: Vec, icons: Vec, icon_renderer: Rc, } impl Map { /// Create a new, empty map/world. pub fn new(rl: &mut RaylibHandle, rlt: &RaylibThread) -> Self { Self { rooms: Vec::new(), walls: Vec::new(), icons: Vec::new(), icon_renderer: Rc::new(IconRenderer::new(rl, rlt)), } } /// Add a room to the map. Currently, holes are not supported in the polygon, but this might /// change later. pub fn push_room(&mut self, room_data: RoomData) { self.rooms.push(Room::from_data(room_data)); } /// Add a wall to the world. pub fn push_wall(&mut self, wall_data: WallData) { /* Check for intersections with any wall that was arleady created so the wall ends can be * rendered properly. */ let mut start_intersects = false; let mut end_intersects = false; for wall in &self.walls { if wall.data().contains_collinear(wall_data.start) { start_intersects = true; } if wall.data().contains_collinear(wall_data.end) { end_intersects = true; } // Currently, additional intersections can be ignored, since it is just a yes-no-question if start_intersects && end_intersects { break; } } self.walls .push(Wall::from_data(wall_data, start_intersects, end_intersects)); } /// Add an icon to the world. pub fn push_icon(&mut self, icon: Icon) { self.icons.push(icon); } /// Draw all elements of the map to the screen. This should be called after the background of the /// map has already been drawn. pub fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) { for element in self.elements() { element.draw(rld, transform); } } /// Get the icon-renderer that is currently used to render the icons. pub fn icon_renderer(&self) -> Rc { self.icon_renderer.clone() } /// Retain all map elements that fulfill the given predicate, removing everything else. pub fn retain(&mut self, mut f: F) where F: FnMut(&dyn Mappable) -> bool, { // Call retain on all vectors containing the maps actual types. self.rooms.retain(|p| f(p as &dyn Mappable)); self.walls.retain(|w| f(w as &dyn Mappable)); self.icons.retain(|i| f(i as &dyn Mappable)); } /// Iterator over all elements as objects when an operation needs to go over all elements of the /// map. pub fn elements(&self) -> impl Iterator { self.rooms .iter() .map(|p| p as &dyn Mappable) .chain(self.walls.iter().map(|w| w as &dyn Mappable)) .chain(self.icons.iter().map(|i| i as &dyn Mappable)) } /// Iterator over all elements, but the individual elements can be mutated. It is however /// impossible to add or remove elements in this way. For that, use the dedicated functions. pub fn elements_mut(&mut self) -> impl Iterator { self.rooms .iter_mut() .map(|p| p as &mut dyn Mappable) .chain(self.walls.iter_mut().map(|w| w as &mut dyn Mappable)) .chain(self.icons.iter_mut().map(|i| i as &mut dyn Mappable)) } /// Get the rooms of this map. pub fn rooms(&self) -> &Vec { &self.rooms } /// Get the walls of this map. pub fn walls(&self) -> &Vec { &self.walls } /// Get the icons of this map. pub fn icons(&self) -> &Vec { &self.icons } /// Replace the internal map data with the data provided. (Load and replace) pub fn set_data(&mut self, data: MapData) { // Remove all data. self.icons.clear(); self.rooms.clear(); self.walls.clear(); // Add all data from the map data. self.add_data(data); } /// Add the data provided to the current data on the map. All elements will remain, with the /// additional elements being pushed also. pub fn add_data(&mut self, data: MapData) { for i in data.icons { self.push_icon(Icon::from_data(i, self.icon_renderer.clone())) } for p in data.rooms { self.push_room(p); } for w in data.walls { self.push_wall(w); } } }