//! This module contains the scene struct which holds everything needed during a game. use std::time::{Duration, SystemTime}; use crate::engine::bbox::Bbox; use crate::engine::character::Character; use crate::engine::input::Action; use crate::engine::input::InputManager; use crate::engine::map::{CollisionTile, GraphicTile, Map, PositionedTile}; use crate::engine::object::Object; use crate::engine::texture::SPRITE_SIZE; use crate::engine::vector::Vector; /// Contains everything needed to play. pub struct Scene { /// The characters contained in the scene. characters: Vec, /// The objects contained in the scene. objects: Vec, /// The map of the scene. map: Map, } /// The type used to represent whether a a scene is running or finished. #[derive(Copy, Clone, PartialEq, Eq)] pub enum State { /// The scene is running. Running, /// The scene is finished. Finished, } impl Scene { /// Creates a scene from a map level. pub fn from_map(map: Map) -> Scene { let object = Object::new(Vector::new(100.0, 300.0)); Scene { characters: vec![], objects: vec![object], map, } } /// Adds a character to the scene. pub fn add(&mut self, character: Character) { let mut character = character; character.position.x = self.map.entrance().1 as f64 * SPRITE_SIZE; character.position.y = self.map.entrance().0 as f64 * SPRITE_SIZE; self.characters.push(character); } /// Adds an object to the scene. pub fn add_object(&mut self, object: Object) { self.objects.push(object); } /// Returns the controlable. pub fn controlable(&self) -> Option<&Character> { for character in &self.characters { if character.controls().is_some() { return Some(&character); } } None } /// Returns the controlable. pub fn controlable_mut(&mut self) -> Option<&mut Character> { for character in &mut self.characters { if character.controls().is_some() { return Some(character); } } None } /// Returns the right view. pub fn view(&self) -> Option { let view = self.controlable()?.view(); let mut center = view.position + view.size / 2.0; let size = view.size; // Clamp center so that the view doesn't show things outside the level. if center.x - size.x / 2.0 < 0.0 { center.x = size.x / 2.0; } if center.y - size.y / 2.0 < 0.0 { center.y = size.y / 2.0; } let right_limit = self.map.cols() as f64 * SPRITE_SIZE; let bottom_limit = self.map.rows() as f64 * SPRITE_SIZE; if center.x + size.x / 2.0 > right_limit { center.x = right_limit - size.x / 2.0; } if center.y + size.y / 2.0 > bottom_limit { center.y = bottom_limit - size.y / 2.0; } Some(Bbox::from_center_and_size(center, size)) } /// Updates the whole scene. pub fn update(&mut self, now: SystemTime, duration: Duration, inputs: &InputManager) -> State { let mut state = State::Running; for c in &mut self.characters { // Don't need to update if the character is dead // if c.is_alive() { if true { let old = c.bbox(); // Compute the offset between position and bbox let offset = old.position - c.position; c.update(now, duration, inputs); if let Some((axis, position, damage)) = self.map.collides_bbox(old, c.bbox()) { c.position = position - offset; if axis.is_x() { c.speed.x = 0.0; } if axis.is_y() { c.speed.y = 0.0; c.ground_collision(); } if damage { c.die(); state = State::Finished; } } else { c.fall_off(); } for object in &self.objects { let positioned = PositionedTile { graphic: GraphicTile(None), collision: CollisionTile::full(), position: object.position, }; if let Some((axis, position)) = positioned.collides(old, c.bbox()) { c.position = position - offset; if axis.is_x() { c.speed.x = 0.0; } if axis.is_y() { c.speed.y = 0.0; c.ground_collision(); } } } } } state } /// Transfers an action to the elements contained in the scene that should receive actions. pub fn manage_action(&mut self, action: Action) { for c in &mut self.characters { c.manage_action(action); } } /// Returns a reference to the characters of the scene. pub fn characters(&self) -> &Vec { &self.characters } /// Returns a reference to the map. pub fn map(&self) -> &Map { &self.map } /// Returns a reference to the objects of the scene. pub fn objects(&self) -> &Vec { &self.objects } } /// Trait that needs to be implemented for everything that can be updatable. pub trait Updatable { /// Updates the thing depending on the duration since last frame. fn update(&mut self, now: SystemTime, duration: Duration, inputs: &InputManager); /// Called when an action arrives. fn manage_action(&mut self, action: Action); }