200 lines
5.9 KiB
Rust
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);
|
|
}
|