diff --git a/Cargo.lock b/Cargo.lock index 4a9b248..22c4188 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,19 +25,13 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.58" +version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" dependencies = [ "wasm-bindgen", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "log" version = "0.4.17" @@ -48,10 +42,16 @@ dependencies = [ ] [[package]] -name = "proc-macro2" -version = "1.0.40" +name = "once_cell" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "proc-macro2" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b" dependencies = [ "unicode-ident", ] @@ -84,9 +84,9 @@ checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" [[package]] name = "wasm-bindgen" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -94,13 +94,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", "syn", @@ -109,9 +109,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -119,9 +119,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" dependencies = [ "proc-macro2", "quote", @@ -132,15 +132,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" +checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" [[package]] name = "web-sys" -version = "0.3.58" +version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 43e849b..5ad4dfd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,4 +22,5 @@ features = [ 'HtmlCanvasElement', 'HtmlImageElement', 'Window', + 'Performance', ] diff --git a/src/engine/character.rs b/src/engine/character.rs index 798f01f..24da52c 100644 --- a/src/engine/character.rs +++ b/src/engine/character.rs @@ -1,11 +1,11 @@ //! This module helps us dealing with characters. -use std::time::{Duration, Instant}; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; use crate::engine::bbox::Bbox; use crate::engine::controls::{Action, Controls}; use crate::engine::event::{Event, Keyboard}; -use crate::engine::math::{clamp, duration_as_f64}; +use crate::engine::math::{clamp, duration_as_f64, duration_as_frame}; use crate::engine::physics; use crate::engine::scene::Updatable; use crate::engine::texture::Texture; @@ -70,7 +70,7 @@ pub struct Character { max_jump: usize, /// The timer of the character's animation. - animation_timer: Duration, + animation_timer: SystemTime, /// Whether the character is walking or not. walking: bool, @@ -89,7 +89,7 @@ impl Character { side: Side::Right, jump_counter: 1, max_jump: 1, - animation_timer: Duration::from_millis(0), + animation_timer: UNIX_EPOCH, can_jump: true, walking: false, } @@ -147,7 +147,7 @@ impl Character { } impl Updatable for Character { - fn update(&mut self, duration: &Duration, keyboard: &Keyboard) { + fn update(&mut self, now: SystemTime, duration: Duration, keyboard: &Keyboard) { let mut force = Vector::new(0.0, 0.0); if let Some(ref controls) = self.controls { @@ -156,13 +156,13 @@ impl Updatable for Character { if let Some(side) = Side::from_force(force) { if !self.walking { - self.animation_timer = Duration::from_millis(0); + self.animation_timer = now; } self.walking = true; self.side = side; } else { if self.walking { - self.animation_timer = Duration::from_millis(0); + self.animation_timer = now; } self.walking = false; } @@ -218,8 +218,8 @@ impl Drawable for Character { Texture::Rusty } - fn texture_rect(&self) -> Bbox { - let frame = 0.0; // duration_as_frame(&Instant::now().duration_since(self.animation_timer), 4); + fn texture_rect(&self, now: SystemTime) -> Bbox { + let frame = duration_as_frame(now.duration_since(self.animation_timer).unwrap(), 4) as f64; let offset = if self.walking { 64.0 } else { 0.0 }; Bbox::new(self.side.offset() as f64 + offset, frame * 32.0, 32.0, 32.0) } diff --git a/src/engine/map.rs b/src/engine/map.rs index 8457366..46f0b89 100644 --- a/src/engine/map.rs +++ b/src/engine/map.rs @@ -1,5 +1,7 @@ //! This module contains everything related to maps. +use std::time::SystemTime; + use crate::engine::bbox::Bbox; use crate::engine::math::{clamp, Matrix}; use crate::engine::texture::Texture; @@ -233,9 +235,9 @@ impl Drawable for PositionedTile { Texture::Overworld } - fn texture_rect(&self) -> Bbox { + fn texture_rect(&self, _now: SystemTime) -> Bbox { let offset = self.graphic.offset(); - Bbox::new(offset.0 as f64, offset.0 as f64, SPRITE_SIZE, SPRITE_SIZE) + Bbox::new(offset.0 as f64, offset.1 as f64, SPRITE_SIZE, SPRITE_SIZE) } fn position(&self) -> Vector { diff --git a/src/engine/math.rs b/src/engine/math.rs index c579a7f..5a5e244 100644 --- a/src/engine/math.rs +++ b/src/engine/math.rs @@ -1,7 +1,14 @@ //! This module contains useful math tools. use std::ops::{Index, IndexMut}; -use std::time::Duration; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +pub fn now(performance: &web_sys::Performance) -> SystemTime { + let now = performance.now(); + let secs = (now as u64) / 1_000; + let nanos = (((now as u64) % 1_000) as u32) * 1_000_000; + UNIX_EPOCH + Duration::new(secs, nanos) +} /// Clamp a number between two boundaries. pub fn clamp(number: f64, min: f64, max: f64) -> f64 { @@ -15,14 +22,14 @@ pub fn clamp(number: f64, min: f64, max: f64) -> f64 { } /// Converts a duration into an animation frame number. -pub fn duration_as_frame(duration: &Duration, total: usize) -> i32 { +pub fn duration_as_frame(duration: Duration, total: usize) -> i32 { let secs = duration_as_f64(duration); (secs * 10.0) as i32 % total as i32 } /// Converts a duration into its number of seconds. -pub fn duration_as_f64(duration: &Duration) -> f64 { +pub fn duration_as_f64(duration: Duration) -> f64 { duration.as_secs() as f64 + duration.subsec_nanos() as f64 / 1_000_000_000.0 } diff --git a/src/engine/mod.rs b/src/engine/mod.rs index a9686ac..93dd638 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -13,7 +13,7 @@ pub mod vector; use std::cell::RefCell; use std::rc::Rc; -use std::time::Duration; +use std::time::{Duration, SystemTime}; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; @@ -23,6 +23,7 @@ use crate::engine::character::Character; use crate::engine::controls::Controls; use crate::engine::event::{Key, Keyboard}; use crate::engine::map::Map; +use crate::engine::math::now; use crate::engine::scene::{Scene, State}; use crate::engine::texture::{Texture, TextureManager}; use crate::engine::vector::Vector; @@ -55,6 +56,9 @@ pub struct Engine { /// /// We keep a reference so that we can easily render things. pub context: Rc, + + /// The performance object. + pub performance: Rc, } impl Engine { @@ -62,6 +66,7 @@ impl Engine { pub fn new() -> Result { let window = unwrap!(web_sys::window()); let document = unwrap!(window.document()); + let performance = unwrap!(window.performance()); let canvas = unwrap!(document.get_element_by_id("canvas")); let canvas: web_sys::HtmlCanvasElement = canvas.dyn_into::()?; @@ -77,16 +82,18 @@ impl Engine { let character = Character::with_controls(Controls::default_keyboard()); scene.add(character); - let inner = InnerEngine::new(&document, scene)?; + let inner = InnerEngine::new(&document, &performance, scene)?; let window = Rc::new(window); let document = Rc::new(document); + let performance = Rc::new(performance); let context = Rc::new(context); Ok(Engine { inner: Rc::new(RefCell::new(inner)), window, document, + performance, context, }) } @@ -140,10 +147,12 @@ impl Engine { } // Manage the physics - let duration = Duration::from_millis(60); + let now = now(&self.performance); + let duration = unwrap!(now.duration_since(inner.after_loop).ok()); + inner.after_loop = now; let keyboard = inner.keyboard.clone(); - if inner.scene.update(&duration, &keyboard) == State::Finished { + if inner.scene.update(now, duration, &keyboard) == State::Finished { // running = false; } @@ -155,7 +164,7 @@ impl Engine { let inner = self.inner.borrow(); let image = inner.textures.get(drawable.texture()); - let source = drawable.texture_rect(); + let source = drawable.texture_rect(inner.after_loop); let mut dest = source.clone(); dest.position = drawable.position(); @@ -203,6 +212,9 @@ pub struct InnerEngine { /// The scene of the engine. pub scene: Scene, + /// The time when the loop is done. + pub after_loop: SystemTime, + /// The keyboard. pub keyboard: Keyboard, @@ -212,9 +224,14 @@ pub struct InnerEngine { impl InnerEngine { /// Initializes the engine. - pub fn new(document: &web_sys::Document, scene: Scene) -> Result { + pub fn new( + document: &web_sys::Document, + performance: &web_sys::Performance, + scene: Scene, + ) -> Result { Ok(InnerEngine { scene, + after_loop: now(&performance), keyboard: Keyboard::new(document)?, textures: TextureManager::new()?, }) @@ -227,7 +244,7 @@ pub trait Drawable { fn texture(&self) -> Texture; /// Returns the coordinates to use on the texture. - fn texture_rect(&self) -> Bbox; + fn texture_rect(&self, now: SystemTime) -> Bbox; /// Returns the position on which the drawable should be drawn. fn position(&self) -> Vector; diff --git a/src/engine/scene.rs b/src/engine/scene.rs index 0d567ec..28ebfbd 100644 --- a/src/engine/scene.rs +++ b/src/engine/scene.rs @@ -1,6 +1,6 @@ //! This module contains the scene struct which holds everything needed during a game. -use std::time::Duration; +use std::time::{Duration, SystemTime}; use crate::engine::character::Character; use crate::engine::event::{Event, Keyboard}; @@ -84,7 +84,7 @@ impl Scene { // } /// Updates the whole scene. - pub fn update(&mut self, duration: &Duration, keyboard: &Keyboard) -> State { + pub fn update(&mut self, now: SystemTime, duration: Duration, keyboard: &Keyboard) -> State { let mut state = State::Finished; for c in &mut self.characters { @@ -96,7 +96,7 @@ impl Scene { // Compute the offset between position and bbox let offset = old.position - c.position; - c.update(duration, keyboard); + c.update(now, duration, keyboard); if let Some((axis, position, damage)) = self.map.collides_bbox(old, c.bbox()) { c.position = position - offset; @@ -144,7 +144,7 @@ impl Scene { /// 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, duration: &Duration, keyboard: &Keyboard); + fn update(&mut self, now: SystemTime, duration: Duration, keyboard: &Keyboard); /// Called when an event arrives. fn manage_event(&mut self, event: &Event);