about summary refs log tree commit diff
path: root/src/game.rs
diff options
context:
space:
mode:
authorGriffin Smith <root@gws.fyi>2019-07-09T00·58-0400
committerGriffin Smith <root@gws.fyi>2019-07-09T00·58-0400
commit5af2429ecb5742383cf0798ce23682d316bdb24d (patch)
tree0fba959d9a5bce5c749c8529b3f2ea7b557c5767 /src/game.rs
parent20f1ccb4600b88ac01768e912e6d5837534ca852 (diff)
Implement a global map of entities
Implement a global map of entities, which allows referencing by either
position or ID and updating the positions of existent entities, and put
the character in there.
Diffstat (limited to 'src/game.rs')
-rw-r--r--src/game.rs78
1 files changed, 62 insertions, 16 deletions
diff --git a/src/game.rs b/src/game.rs
index daa5fa575f68..90d94dc5f220 100644
--- a/src/game.rs
+++ b/src/game.rs
@@ -1,10 +1,14 @@
 use crate::display::{self, Viewport};
 use crate::entities::Character;
+use crate::entities::Entity;
 use crate::messages::message;
 use crate::settings::Settings;
 use crate::types::command::Command;
-use crate::types::Positioned;
-use crate::types::{BoundingBox, Dimensions, Position};
+use crate::types::entity_map::EntityID;
+use crate::types::entity_map::EntityMap;
+use crate::types::{
+    BoundingBox, Collision, Dimensions, Position, Positioned, PositionedMut,
+};
 use rand::rngs::SmallRng;
 use rand::SeedableRng;
 use std::io::{self, StdinLock, StdoutLock, Write};
@@ -16,6 +20,20 @@ type Stdout<'a> = RawTerminal<StdoutLock<'a>>;
 
 type Rng = SmallRng;
 
+type AnEntity<'a> = Box<dyn Entity>;
+
+impl<'a> Positioned for AnEntity<'a> {
+    fn position(&self) -> Position {
+        (**self).position()
+    }
+}
+
+impl<'a> PositionedMut for AnEntity<'a> {
+    fn set_position(&mut self, pos: Position) {
+        (**self).set_position(pos)
+    }
+}
+
 /// The full state of a running Game
 pub struct Game<'a> {
     settings: Settings,
@@ -25,8 +43,11 @@ pub struct Game<'a> {
     /// An iterator on keypresses from the user
     keys: Keys<StdinLock<'a>>,
 
-    /// The player character
-    character: Character,
+    /// The map of all the entities in the game
+    entities: EntityMap<AnEntity<'a>>,
+
+    /// The entity ID of the player character
+    character_entity_id: EntityID,
 
     /// The messages that have been said to the user, in forward time order
     messages: Vec<String>,
@@ -51,6 +72,7 @@ impl<'a> Game<'a> {
             Some(seed) => SmallRng::seed_from_u64(seed),
             None => SmallRng::from_entropy(),
         };
+        let mut entities: EntityMap<AnEntity<'a>> = EntityMap::new();
         Game {
             settings,
             rng,
@@ -61,19 +83,34 @@ impl<'a> Game<'a> {
                 stdout,
             ),
             keys: stdin.keys(),
-            character: Character::new(),
+            character_entity_id: entities.insert(Box::new(Character::new())),
             messages: Vec::new(),
+            entities,
         }
     }
 
-    /// Returns true if there's a collision in the game at the given Position
-    fn collision_at(&self, pos: Position) -> bool {
-        !pos.within(self.viewport.inner)
+    /// Returns a collision, if any, at the given Position in the game
+    fn collision_at(&self, pos: Position) -> Option<Collision> {
+        if !pos.within(self.viewport.inner) {
+            Some(Collision::Stop)
+        } else {
+            None
+        }
+    }
+
+    fn character(&self) -> &Character {
+        debug!("ents: {:?} cid: {:?}", self.entities.ids().map(|id| *id).collect::<Vec<u32>>(), self.character_entity_id);
+        (*self.entities.get(self.character_entity_id).unwrap())
+            .downcast_ref()
+            .unwrap()
     }
 
     /// Draw all the game entities to the screen
     fn draw_entities(&mut self) -> io::Result<()> {
-        self.viewport.draw(&self.character)
+        for entity in self.entities.entities() {
+            self.viewport.draw(entity)?;
+        }
+        Ok(())
     }
 
     /// Get a message from the global map based on the rng in this game
@@ -104,7 +141,6 @@ impl<'a> Game<'a> {
         self.viewport.init()?;
         self.draw_entities()?;
         self.say("global.welcome")?;
-        self.say("somethign else")?;
         self.flush()?;
         loop {
             let mut old_position = None;
@@ -116,10 +152,18 @@ impl<'a> Game<'a> {
                 }
 
                 Some(Move(direction)) => {
-                    let new_pos = self.character.position + direction;
-                    if !self.collision_at(new_pos) {
-                        old_position = Some(self.character.position);
-                        self.character.position = new_pos;
+                    use Collision::*;
+                    let new_pos = self.character().position + direction;
+                    match self.collision_at(new_pos) {
+                        None => {
+                            old_position = Some(self.character().position);
+                            self.entities.update_position(
+                                self.character_entity_id,
+                                new_pos,
+                            );
+                        }
+                        Some(Combat) => unimplemented!(),
+                        Some(Stop) => (),
                     }
                 }
 
@@ -131,12 +175,14 @@ impl<'a> Game<'a> {
             match old_position {
                 Some(old_pos) => {
                     self.viewport.clear(old_pos)?;
-                    self.viewport.draw(&self.character)?;
+                    self.viewport.draw(
+                        // TODO this clone feels unnecessary.
+                        &self.character().clone())?;
                 }
                 None => (),
             }
             self.flush()?;
-            debug!("{:?}", self.character);
+            debug!("{:?}", self.character());
         }
         Ok(())
     }