game/src/engine/scene.rs
2022-08-06 14:14:00 +02:00

200 lines
5.9 KiB
Rust

//! 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<Character>,
/// The objects contained in the scene.
objects: Vec<Object>,
/// 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<Bbox> {
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<Character> {
&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<Object> {
&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);
}