aboutsummaryrefslogtreecommitdiff
path: root/src/client/map/mod.rs
diff options
context:
space:
mode:
authorArne Dußin2021-01-27 14:01:50 +0100
committerArne Dußin2021-02-02 22:16:15 +0100
commitf92e9f6f07b1e3834c2ca58ce3510734819d08e4 (patch)
tree20e3d3afce342a56ae98f6c20491482ccd2b5c6b /src/client/map/mod.rs
parentc60a6d07efb120724b308e29e8e70f27c87c952d (diff)
downloadgraf_karto-f92e9f6f07b1e3834c2ca58ce3510734819d08e4.tar.gz
graf_karto-f92e9f6f07b1e3834c2ca58ce3510734819d08e4.zip
Rework graf karto to fit the client/server structure
Diffstat (limited to 'src/client/map/mod.rs')
-rw-r--r--src/client/map/mod.rs206
1 files changed, 206 insertions, 0 deletions
diff --git a/src/client/map/mod.rs b/src/client/map/mod.rs
new file mode 100644
index 0000000..eaab72f
--- /dev/null
+++ b/src/client/map/mod.rs
@@ -0,0 +1,206 @@
+//! The map is a visual interpretation of all the items that make up the world.
+//!
+//! It's the main structure that the client uses to interact with the world, since
+//! the world contains all the
+
+pub mod icon_mark;
+pub mod icon_texture_manager;
+pub mod mappable;
+pub mod room_mark;
+pub mod wall_mark;
+
+pub use icon_mark::*;
+pub use mappable::Mappable;
+pub use room_mark::*;
+pub use wall_mark::*;
+
+use crate::client::Transform;
+use crate::stable_vec::StableVec;
+use crate::world::{Room, Wall, World};
+use icon_texture_manager::IconTextureManager;
+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: StableVec<RoomMark>,
+ walls: StableVec<WallMark>,
+ icons: StableVec<IconMark>,
+ used_ids: StableVec<()>,
+ icon_renderer: Rc<IconTextureManager>,
+}
+
+impl Map {
+ /// Create a new, empty map/world.
+ pub fn new(rl: &mut RaylibHandle, rlt: &RaylibThread) -> Self {
+ Self {
+ rooms: StableVec::new(),
+ walls: StableVec::new(),
+ icons: StableVec::new(),
+ used_ids: StableVec::new(),
+ icon_renderer: Rc::new(IconTextureManager::new(rl, rlt)),
+ }
+ }
+
+ pub fn add_room(&mut self, id: usize, room: Room) -> bool {
+ if self.used_ids.try_insert(id, ()).is_ok() {
+ self.rooms
+ .try_insert(id, RoomMark::from_room(room))
+ .unwrap();
+ true
+ } else {
+ error!("Unable to add room. Id already in use.");
+ false
+ }
+ }
+
+ /// Add a wall with a specific id. May fail if there already is an entity with that id.
+ pub fn add_wall(&mut self, id: usize, wall: Wall) -> bool {
+ if self.used_ids.try_insert(id, ()).is_ok() {
+ /* 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.iter() {
+ if wall.shape().contains_collinear(wall.shape().start) {
+ start_intersects = true;
+ }
+ if wall.shape().contains_collinear(wall.shape().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
+ .try_insert(
+ id,
+ WallMark::from_wall(wall, start_intersects, end_intersects),
+ )
+ .unwrap();
+ true
+ } else {
+ error!("Unable to add wall. Id already in use.");
+ false
+ }
+ }
+
+ /// Add an icon with a specific id. May fail if there already is an entity with that id.
+ pub fn add_icon(&mut self, id: usize, icon: IconMark) -> bool {
+ if self.used_ids.try_insert(id, ()).is_ok() {
+ self.icons.try_insert(id, icon).unwrap();
+ true
+ } else {
+ error!("Unable to add icon. Id already in use.");
+ false
+ }
+ }
+
+ /// 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<IconTextureManager> {
+ self.icon_renderer.clone()
+ }
+
+ /// Remove item with the id, if it exists. Returns `true` if an item existed, `false` otherwise.
+ pub fn remove(&mut self, id: usize) -> bool {
+ if self.used_ids.remove(id).is_none() {
+ return false;
+ }
+
+ if self.rooms.remove(id).is_some()
+ || self.walls.remove(id).is_some()
+ || self.icons.remove(id).is_some()
+ {
+ true
+ } else {
+ panic!(
+ "Id {} was still registered, eventhough there was no such entity.",
+ id
+ );
+ }
+ }
+
+ /// Iterator over all elements as objects when an operation needs to go over all elements of the
+ /// map.
+ pub fn elements(&self) -> impl Iterator<Item = (usize, &dyn Mappable)> {
+ self.rooms
+ .iter()
+ .map(|(id, p)| (*id, p as &dyn Mappable))
+ .chain(self.walls.iter().map(|(id, w)| (*id, w as &dyn Mappable)))
+ .chain(self.icons.iter().map(|(id, i)| (*id, 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<Item = (usize, &mut dyn Mappable)> {
+ self.rooms
+ .id_iter_mut()
+ .map(|(id, p)| (id, p as &mut dyn Mappable))
+ .chain(
+ self.walls
+ .id_iter_mut()
+ .map(|(id, w)| (id, w as &mut dyn Mappable)),
+ )
+ .chain(
+ self.icons
+ .id_iter_mut()
+ .map(|(id, i)| (id, i as &mut dyn Mappable)),
+ )
+ }
+
+ /// Get the rooms of this map.
+ pub fn rooms(&self) -> &StableVec<RoomMark> {
+ &self.rooms
+ }
+
+ /// Get the walls of this map.
+ pub fn walls(&self) -> &StableVec<WallMark> {
+ &self.walls
+ }
+
+ /// Get the icons of this map.
+ pub fn icons(&self) -> &StableVec<IconMark> {
+ &self.icons
+ }
+
+ /// Replace the internal map data with the data of the world provided.
+ /// (Load and replace)
+ pub fn set_data(&mut self, world: World) {
+ // Remove all data.
+ self.icons.clear();
+ self.rooms.clear();
+ self.walls.clear();
+
+ // Add all data from the map data.
+ self.add_data(world);
+ }
+
+ /// Add the data provided to the current data on the map. All elements will
+ /// remain, with the additional elements being pushed also. This must be
+ /// used with caution, since the ids of the items will remain unchanged, and
+ /// items with the same id will therefore be ignored and not added.
+ pub fn add_data(&mut self, world: World) {
+ for (id, i) in world.icons().iter() {
+ self.add_icon(*id, IconMark::from_icon(*i, self.icon_renderer.clone()));
+ }
+ for (id, r) in world.rooms().iter() {
+ self.add_room(*id, r.clone());
+ }
+ for (id, w) in world.walls().iter() {
+ self.add_wall(*id, w.clone());
+ }
+ }
+}