From cbcda28719a2bcedccb0aa5f43c81329691afe7f Mon Sep 17 00:00:00 2001 From: Alex Page Date: Fri, 4 Feb 2022 19:09:59 -0500 Subject: [PATCH] Initial web support --- Cargo.lock | 28 ++++++----- Cargo.toml | 5 +- build.rs | 8 ++-- index.html | 39 ++++++++++++++++ src/components/mod.rs | 2 +- src/components/player.rs | 2 +- src/input/mod.rs | 23 ++++++--- src/input/player.rs | 77 +++++++++++++++++++------------ src/main.rs | 77 +++++++------------------------ src/resources/clock.rs | 2 +- src/resources/flashing_message.rs | 4 +- src/resources/map.rs | 2 +- src/resources/mod.rs | 4 +- src/state.rs | 61 ++++++++++++++++++++++-- src/systems/monster_ai.rs | 22 +++++---- src/systems/time.rs | 3 +- src/systems/whip.rs | 22 +++++---- 17 files changed, 238 insertions(+), 143 deletions(-) create mode 100644 index.html diff --git a/Cargo.lock b/Cargo.lock index 4d6f327..cc017f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -127,7 +127,7 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "bracket-algorithm-traits" version = "0.8.2" -source = "git+https://github.com/amethyst/bracket-lib#5e35a050f5181892155a2eb4641af7445273a6f3" +source = "git+https://github.com/amethyst/bracket-lib#cf8eec60ae17f2534a14f3ae643c871202aed192" dependencies = [ "bracket-geometry", "smallvec", @@ -136,7 +136,7 @@ dependencies = [ [[package]] name = "bracket-color" version = "0.8.2" -source = "git+https://github.com/amethyst/bracket-lib#5e35a050f5181892155a2eb4641af7445273a6f3" +source = "git+https://github.com/amethyst/bracket-lib#cf8eec60ae17f2534a14f3ae643c871202aed192" dependencies = [ "lazy_static", "parking_lot", @@ -145,7 +145,7 @@ dependencies = [ [[package]] name = "bracket-embedding" version = "0.8.0" -source = "git+https://github.com/amethyst/bracket-lib#5e35a050f5181892155a2eb4641af7445273a6f3" +source = "git+https://github.com/amethyst/bracket-lib#cf8eec60ae17f2534a14f3ae643c871202aed192" dependencies = [ "lazy_static", "parking_lot", @@ -154,7 +154,7 @@ dependencies = [ [[package]] name = "bracket-geometry" version = "0.8.3" -source = "git+https://github.com/amethyst/bracket-lib#5e35a050f5181892155a2eb4641af7445273a6f3" +source = "git+https://github.com/amethyst/bracket-lib#cf8eec60ae17f2534a14f3ae643c871202aed192" dependencies = [ "ultraviolet", ] @@ -162,7 +162,7 @@ dependencies = [ [[package]] name = "bracket-lib" version = "0.8.2" -source = "git+https://github.com/amethyst/bracket-lib#5e35a050f5181892155a2eb4641af7445273a6f3" +source = "git+https://github.com/amethyst/bracket-lib#cf8eec60ae17f2534a14f3ae643c871202aed192" dependencies = [ "bracket-algorithm-traits", "bracket-color", @@ -176,7 +176,7 @@ dependencies = [ [[package]] name = "bracket-noise" version = "0.8.2" -source = "git+https://github.com/amethyst/bracket-lib#5e35a050f5181892155a2eb4641af7445273a6f3" +source = "git+https://github.com/amethyst/bracket-lib#cf8eec60ae17f2534a14f3ae643c871202aed192" dependencies = [ "bracket-random", ] @@ -184,7 +184,7 @@ dependencies = [ [[package]] name = "bracket-pathfinding" version = "0.8.4" -source = "git+https://github.com/amethyst/bracket-lib#5e35a050f5181892155a2eb4641af7445273a6f3" +source = "git+https://github.com/amethyst/bracket-lib#cf8eec60ae17f2534a14f3ae643c871202aed192" dependencies = [ "bracket-algorithm-traits", "bracket-geometry", @@ -195,7 +195,7 @@ dependencies = [ [[package]] name = "bracket-random" version = "0.8.3" -source = "git+https://github.com/amethyst/bracket-lib#5e35a050f5181892155a2eb4641af7445273a6f3" +source = "git+https://github.com/amethyst/bracket-lib#cf8eec60ae17f2534a14f3ae643c871202aed192" dependencies = [ "getrandom", "js-sys", @@ -209,7 +209,7 @@ dependencies = [ [[package]] name = "bracket-rex" version = "0.8.0" -source = "git+https://github.com/amethyst/bracket-lib#5e35a050f5181892155a2eb4641af7445273a6f3" +source = "git+https://github.com/amethyst/bracket-lib#cf8eec60ae17f2534a14f3ae643c871202aed192" dependencies = [ "bracket-color", "bracket-embedding", @@ -220,7 +220,7 @@ dependencies = [ [[package]] name = "bracket-terminal" version = "0.8.5" -source = "git+https://github.com/amethyst/bracket-lib#5e35a050f5181892155a2eb4641af7445273a6f3" +source = "git+https://github.com/amethyst/bracket-lib#cf8eec60ae17f2534a14f3ae643c871202aed192" dependencies = [ "anyhow", "bracket-color", @@ -325,9 +325,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90" +checksum = "4cc00842eed744b858222c4c9faf7243aafc6d33f92f96935263ef4d8a41ce21" dependencies = [ "glob", "libc", @@ -513,6 +513,7 @@ dependencies = [ "parking_lot", "stdweb", "thiserror", + "wasm-bindgen", "web-sys", "winapi 0.3.9", ] @@ -1070,12 +1071,15 @@ name = "kroz" version = "0.1.0" dependencies = [ "bracket-lib", + "console_error_panic_hook", "cpal", "fundsp", "hecs", + "instant", "oddio", "specs-derive", "typenum", + "wasm-bindgen", "winres", ] diff --git a/Cargo.toml b/Cargo.toml index 82c7fad..75207ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,10 +9,13 @@ build = "build.rs" bracket-lib = { git = "https://github.com/amethyst/bracket-lib" } hecs = "0.5.1" specs-derive = "0.4.1" -cpal = "0.13" +cpal = { version = "0.13.0", features = ["wasm-bindgen"] } oddio = "0.5" fundsp = "0.1.0" typenum = "1.15.0" +console_error_panic_hook = "0.1.7" +wasm-bindgen = "0.2.79" +instant = "0.1.12" [target.'cfg(windows)'.build-dependencies] winres = "0.1" diff --git a/build.rs b/build.rs index 19416ce..1cb3c6e 100644 --- a/build.rs +++ b/build.rs @@ -1,12 +1,12 @@ -#[cfg(target_os = "windows")] +#[cfg(windows)] extern crate winres; -#[cfg(target_os = "windows")] +#[cfg(windows)] fn main() { let mut res = winres::WindowsResource::new(); res.set_icon("icon.ico"); - res.compile().unwrap(); + let _ = res.compile(); } -#[cfg(not(target_os = "windows"))] +#[cfg(not(windows))] fn main() {} diff --git a/index.html b/index.html new file mode 100644 index 0000000..04ec7e3 --- /dev/null +++ b/index.html @@ -0,0 +1,39 @@ + + + + + + + + + + + diff --git a/src/components/mod.rs b/src/components/mod.rs index 6ad4b9c..ca3a9ce 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,4 +1,4 @@ -use std::time::Instant; +use instant::Instant; pub mod monster; pub mod player; diff --git a/src/components/player.rs b/src/components/player.rs index 1b1e03e..56ab2ea 100644 --- a/src/components/player.rs +++ b/src/components/player.rs @@ -1,4 +1,4 @@ -use std::time::Instant; +use instant::Instant; #[derive(Debug)] pub struct Player { diff --git a/src/input/mod.rs b/src/input/mod.rs index 41b0a65..dae59fc 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -10,6 +10,13 @@ pub fn handle_intent(bterm: &mut BTerm, _world: &mut World, resources: &mut Reso if let Some(flashing_message) = &resources.flashing_message { if let Some(intent) = &flashing_message.intent { match intent { + FlashingMessageIntent::Start => { + if resources.sound_output.is_none() || resources.sound_effects.is_none() { + let sound_output = SoundOutput::new(); + resources.sound_effects = Some(SoundEffects::new(&sound_output)); + resources.sound_output = Some(sound_output); + } + } FlashingMessageIntent::Quit => { if key == VirtualKeyCode::Y { bterm.quit() @@ -70,16 +77,20 @@ pub fn handle(world: &mut World, resources: &mut Resources, bterm: &mut BTerm) { )); } VirtualKeyCode::P => { - resources - .sound_output - .play_sound(resources.sound_effects.pause.clone()); + if let (Some(sound_effects), Some(sound_output)) = + (&mut resources.sound_effects, &mut resources.sound_output) + { + sound_output.play_sound(sound_effects.pause.clone()); + } resources.flashing_message = Some(FlashingMessage::from(" Press any key to resume game. ")); } _ => { - resources - .sound_output - .play_sound(resources.sound_effects.bad_key.clone()); + if let (Some(sound_effects), Some(sound_output)) = + (&mut resources.sound_effects, &mut resources.sound_output) + { + sound_output.play_sound(sound_effects.bad_key.clone()); + } } }, } diff --git a/src/input/player.rs b/src/input/player.rs index df9906b..f845062 100644 --- a/src/input/player.rs +++ b/src/input/player.rs @@ -1,4 +1,5 @@ -use std::time::{Duration, Instant}; +use instant::Instant; +use std::time::Duration; use bracket_lib::prelude::*; use hecs::{Entity, With, Without, World}; @@ -29,10 +30,12 @@ pub fn try_move(delta_x: i32, delta_y: i32, world: &mut World, resources: &mut R if let Ok(monster) = world.get::(monster_entity) { resources.stats.add_score(damage_for_kind(monster.kind)); resources.stats.take_gems(damage_for_kind(monster.kind)); - resources.sound_output.play_sound(sound_effect_for_kind( - monster.kind, - &resources.sound_effects, - )); + if let (Some(sound_effects), Some(sound_output)) = + (&mut resources.sound_effects, &mut resources.sound_output) + { + sound_output + .play_sound(sound_effect_for_kind(monster.kind, sound_effects)); + } to_kill.push(monster_entity); } } @@ -48,15 +51,17 @@ pub fn try_move(delta_x: i32, delta_y: i32, world: &mut World, resources: &mut R systems::time::force_tick(&mut resources.clock); - resources - .sound_output - .play_sound(resources.sound_effects.step.clone()); + if let (Some(sound_effects), Some(sound_output)) = + (&mut resources.sound_effects, &mut resources.sound_output) + { + sound_output.play_sound(sound_effects.step.clone()); + } } - } else { - let static_sound = resources - .sound_effects - .get_new_static_effect(&resources.sound_output); - resources.sound_output.play_sound(static_sound); + } else if let (Some(sound_effects), Some(sound_output)) = + (&mut resources.sound_effects, &mut resources.sound_output) + { + let static_sound = sound_effects.get_new_static_effect(sound_output); + sound_output.play_sound(static_sound); } player.last_moved = now; @@ -75,18 +80,22 @@ fn try_step(point: Point, _world: &World, resources: &mut Resources) -> bool { | crate::tile_data::TileType::Medium | crate::tile_data::TileType::Fast => true, crate::tile_data::TileType::Block | crate::tile_data::TileType::Wall => { - resources - .sound_output - .play_sound(resources.sound_effects.blocked.clone()); + if let (Some(sound_effects), Some(sound_output)) = + (&mut resources.sound_effects, &mut resources.sound_output) + { + sound_output.play_sound(sound_effects.blocked.clone()); + } if resources.stats.score > 2 { resources.stats.take_score(2); } false } crate::tile_data::TileType::Whip => { - resources - .sound_output - .play_sound(resources.sound_effects.grab.clone()); + if let (Some(sound_effects), Some(sound_output)) = + (&mut resources.sound_effects, &mut resources.sound_output) + { + sound_output.play_sound(sound_effects.grab.clone()); + } resources.stats.give_whips(1); resources.stats.add_score(1); resources.map.set_tile_at(point, TileType::Floor); @@ -99,9 +108,11 @@ fn try_step(point: Point, _world: &World, resources: &mut Resources) -> bool { crate::tile_data::TileType::Chest => todo!(), crate::tile_data::TileType::SlowTime => todo!(), crate::tile_data::TileType::Gem => { - resources - .sound_output - .play_sound(resources.sound_effects.grab.clone()); + if let (Some(sound_effects), Some(sound_output)) = + (&mut resources.sound_effects, &mut resources.sound_output) + { + sound_output.play_sound(sound_effects.grab.clone()); + } resources.stats.give_gems(1); resources.stats.add_score(1); resources.map.set_tile_at(point, TileType::Floor); @@ -109,9 +120,11 @@ fn try_step(point: Point, _world: &World, resources: &mut Resources) -> bool { } crate::tile_data::TileType::Invisible => todo!(), crate::tile_data::TileType::Teleport => { - resources - .sound_output - .play_sound(resources.sound_effects.grab.clone()); + if let (Some(sound_effects), Some(sound_output)) = + (&mut resources.sound_effects, &mut resources.sound_output) + { + sound_output.play_sound(sound_effects.grab.clone()); + } resources.stats.give_teleports(1); resources.stats.add_score(1); resources.map.set_tile_at(point, TileType::Floor); @@ -173,11 +186,15 @@ pub fn whip(world: &mut World, resources: &mut Resources) { WantsToWhip { frame: 0, last_frame: Instant::now(), - sound: Some( - resources - .sound_output - .play_sound(resources.sound_effects.whipping.clone()), - ), + sound: { + if let (Some(sound_effects), Some(sound_output)) = + (&mut resources.sound_effects, &mut resources.sound_output) + { + Some(sound_output.play_sound(sound_effects.whipping.clone())) + } else { + None + } + }, }, ); resources.stats.whips -= 1; diff --git a/src/main.rs b/src/main.rs index cd82959..705f45f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,74 +10,29 @@ mod state; pub mod systems; pub mod tile_data; -use std::time::Instant; +use std::panic; use bracket_lib::prelude::*; -use hecs::World; -use resources::{difficulty::SECRET, *}; use state::State; +use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; + +#[wasm_bindgen(start)] +pub fn main_js() -> Result<(), JsValue> { + panic::set_hook(Box::new(console_error_panic_hook::hook)); + let _ = main_common(false); + Ok(()) +} fn main() -> BError { + main_common(true) +} + +fn main_common(initialize_sound: bool) -> BError { let context = BTermBuilder::vga(80, 25) .with_fps_cap(60.0) .with_title("Kroz") - .build()?; + .build() + .unwrap(); - let mut sound_output = SoundOutput::new(); - let sound_effects = SoundEffects::new(&sound_output); - sound_output.play_sound(sound_effects.startup.clone()); - - let starting_level = 0; - let selected_difficulty = SECRET; - - let mut world = World::new(); - - let mut map = Map::from(levels::get_level(starting_level)); - map.spawn_entities(&mut world); - - let resources = Resources { - level_number: starting_level, - show_debug_info: false, - player_input: None, - stats: Stats { - score: 0, - gems: selected_difficulty.starting_gems, - whips: selected_difficulty.starting_whips, - whip_power: selected_difficulty.starting_whip_power, - teleports: selected_difficulty.starting_teleports, - keys: selected_difficulty.starting_keys, - }, - clock: Clock { - last_ticked: Instant::now(), - has_ticked: false, - ticks: 0, - }, - stop_clock: false, - map, - sound_effects, - sound_output, - selected_difficulty: Some(selected_difficulty), - flashing_message: Some(FlashingMessage::from("Press any key to begin this level.")), - should_advance_level: false, - }; - - // let descent_sounds: Vec = (20..100) - // .rev() - // .flat_map(|x| { - // (1..10).rev().flat_map(move |y| { - // vec![Sound { - // sound_type: SoundType::Tone(x * y * y), - // duration: Duration::from_millis((y as f64 / 1.5) as u64), - // }] - // }) - // }) - // .collect(); - - // let descent_effect = gs.sound_system.render_sound_effect(SoundEffect { - // sounds: descent_sounds, - // }); - - // let _ = gs.sound_system.play_sound(descent_effect); - - main_loop(context, State::new(world, resources)) + main_loop(context, State::new(initialize_sound)) } diff --git a/src/resources/clock.rs b/src/resources/clock.rs index 02ca0de..cc6ad6f 100644 --- a/src/resources/clock.rs +++ b/src/resources/clock.rs @@ -1,4 +1,4 @@ -use std::time::Instant; +use instant::Instant; pub struct Clock { pub last_ticked: Instant, diff --git a/src/resources/flashing_message.rs b/src/resources/flashing_message.rs index 6155c72..5c83a20 100644 --- a/src/resources/flashing_message.rs +++ b/src/resources/flashing_message.rs @@ -1,8 +1,10 @@ -use std::time::{Duration, Instant}; +use instant::Instant; +use std::time::Duration; use crate::constants::*; pub enum FlashingMessageIntent { + Start, Quit, Save, Restore, diff --git a/src/resources/map.rs b/src/resources/map.rs index bef1dc5..eb90403 100644 --- a/src/resources/map.rs +++ b/src/resources/map.rs @@ -1,4 +1,4 @@ -use std::time::Instant; +use instant::Instant; use crate::{ components::{monster::*, Monster, Player, Position, Renderable}, diff --git a/src/resources/mod.rs b/src/resources/mod.rs index ab7b5cd..d78d9e9 100644 --- a/src/resources/mod.rs +++ b/src/resources/mod.rs @@ -24,8 +24,8 @@ pub struct Resources { pub stop_clock: bool, pub map: Map, pub selected_difficulty: Option, - pub sound_effects: SoundEffects, - pub sound_output: SoundOutput, + pub sound_effects: Option, + pub sound_output: Option, pub flashing_message: Option, pub should_advance_level: bool, } diff --git a/src/state.rs b/src/state.rs index 101e160..eb78c48 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,5 +1,11 @@ -use crate::resources::flashing_message::FlashingMessage; -use crate::resources::{Map, Resources}; +use instant::Instant; + +use crate::resources::clock::Clock; +use crate::resources::difficulty::*; +use crate::resources::flashing_message::{FlashingMessage, FlashingMessageIntent}; +use crate::resources::sound_effects::SoundEffects; +use crate::resources::stats::Stats; +use crate::resources::{Map, Resources, SoundOutput}; use crate::{graphics, input, levels, systems}; use bracket_lib::prelude::*; use hecs::World; @@ -22,7 +28,56 @@ impl GameState for State { } impl State { - pub fn new(world: World, resources: Resources) -> Self { + pub fn new(initialize_sound: bool) -> Self { + let mut sound_output = if initialize_sound { + Some(SoundOutput::new()) + } else { + None + }; + + let sound_effects = sound_output.as_ref().map(SoundEffects::new); + + if let (Some(so), Some(se)) = (&mut sound_output, &sound_effects) { + so.play_sound(se.startup.clone()); + } + + let starting_level = 0; + let selected_difficulty = SECRET; + + let mut world = World::new(); + + let mut map = Map::from(levels::get_level(starting_level)); + map.spawn_entities(&mut world); + + let resources = Resources { + level_number: starting_level, + show_debug_info: false, + player_input: None, + stats: Stats { + score: 0, + gems: selected_difficulty.starting_gems, + whips: selected_difficulty.starting_whips, + whip_power: selected_difficulty.starting_whip_power, + teleports: selected_difficulty.starting_teleports, + keys: selected_difficulty.starting_keys, + }, + clock: Clock { + last_ticked: Instant::now(), + has_ticked: false, + ticks: 0, + }, + stop_clock: false, + map, + sound_effects, + sound_output, + selected_difficulty: Some(selected_difficulty), + flashing_message: Some(FlashingMessage::new( + "Press any key to begin this level.", + Some(FlashingMessageIntent::Start), + )), + should_advance_level: false, + }; + State { world, resources } } diff --git a/src/systems/monster_ai.rs b/src/systems/monster_ai.rs index 8123234..5a21472 100644 --- a/src/systems/monster_ai.rs +++ b/src/systems/monster_ai.rs @@ -56,10 +56,12 @@ pub fn run(world: &mut World, resources: &mut Resources) { // TODO: Sound resources.map.clear_tile_content_at(Point::from(*position)); resources.stats.take_gems(damage_for_kind(monster.kind)); - resources.sound_output.play_sound(sound_effect_for_kind( - monster.kind, - &resources.sound_effects, - )); + if let (Some(sound_effects), Some(sound_output)) = + (&mut resources.sound_effects, &mut resources.sound_output) + { + sound_output + .play_sound(sound_effect_for_kind(monster.kind, sound_effects)); + } to_kill.push(entity); } } else { @@ -67,10 +69,14 @@ pub fn run(world: &mut World, resources: &mut Resources) { match tile { TileType::Wall => {} TileType::Block => { - resources.sound_output.play_sound(sound_effect_for_kind( - monster.kind, - &resources.sound_effects, - )); + if let (Some(sound_effects), Some(sound_output)) = + (&mut resources.sound_effects, &mut resources.sound_output) + { + sound_output.play_sound(sound_effect_for_kind( + monster.kind, + sound_effects, + )); + } resources.stats.add_score(1); *tile = TileType::Floor; to_kill.push(entity); diff --git a/src/systems/time.rs b/src/systems/time.rs index e924f47..eef50cf 100644 --- a/src/systems/time.rs +++ b/src/systems/time.rs @@ -1,4 +1,5 @@ -use std::time::{Duration, Instant}; +use instant::Instant; +use std::time::Duration; use crate::constants::CLOCK_PERIOD; diff --git a/src/systems/whip.rs b/src/systems/whip.rs index e41d66a..7a4fc83 100644 --- a/src/systems/whip.rs +++ b/src/systems/whip.rs @@ -1,4 +1,5 @@ -use std::time::{Duration, Instant}; +use instant::Instant; +use std::time::Duration; use bracket_lib::prelude::*; use hecs::{Entity, World}; @@ -77,15 +78,16 @@ pub fn run(world: &mut World, resources: &mut Resources) { } if wants_to_whip.frame == 7 { wants_to_whip.sound = None; - resources - .sound_output - .play_sound(resources.sound_effects.whipping_hit_end.clone()); - } else { - wants_to_whip.sound = Some( - resources - .sound_output - .play_sound(resources.sound_effects.whipping_hit.clone()), - ); + if let (Some(sound_effects), Some(sound_output)) = + (&mut resources.sound_effects, &mut resources.sound_output) + { + sound_output.play_sound(sound_effects.whipping_hit_end.clone()); + } + } else if let (Some(sound_effects), Some(sound_output)) = + (&mut resources.sound_effects, &mut resources.sound_output) + { + wants_to_whip.sound = + Some(sound_output.play_sound(sound_effects.whipping_hit.clone())); } } }