Browse Source

Chapter 7 is now wasm friendly.

Herbert Wolverson 4 years ago
parent
commit
0b1fecc903

+ 2 - 0
Cargo.lock

@@ -221,6 +221,8 @@ dependencies = [
  "rltk 0.3.1 (git+https://github.com/thebracket/rltk_rs)",
  "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]

+ 22 - 20
book/src/chapter_7.md

@@ -52,7 +52,7 @@ extern crate specs;
 use specs::prelude::*;
 use super::{Viewshed, Monster, Name, Map, Position};
 extern crate rltk;
-use rltk::{Point};
+use rltk::{Point, console};
 
 pub struct MonsterAI {}
 
@@ -70,7 +70,7 @@ impl<'a> System<'a> for MonsterAI {
 
         for (mut viewshed,_monster,name,mut pos) in (&mut viewshed, &monster, &name, &mut position).join() {
             if viewshed.visible_tiles.contains(&*player_pos) {
-                println!("{} shouts insults", name.name);
+                console::log(&format!("{} shouts insults", name.name));
                 let path = rltk::a_star_search(
                     map.xy_idx(pos.x, pos.y) as i32, 
                     map.xy_idx(player_pos.x, player_pos.y) as i32, 
@@ -196,18 +196,20 @@ impl<'a> System<'a> for MapIndexingSystem {
 }
 ```
 
-This tells the map to setup blocking from the terrain, and then iterates all entities with a `BlocksTile` component, and applies them to the blocked list. We need to register it with the dispatcher; in `main.rs`:
+This tells the map to setup blocking from the terrain, and then iterates all entities with a `BlocksTile` component, and applies them to the blocked list. We need to register it with `run_systems`; in `main.rs`:
 
 ```rust
-let mut gs = State {
-    ecs: World::new(),
-    systems : DispatcherBuilder::new()
-        .with(MapIndexingSystem{}, "map_indexing_system", &[])
-        .with(VisibilitySystem{}, "visibility_system", &[])
-        .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-        .build(),
-    runstate : RunState::Running
-};
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        self.ecs.maintain();
+    }
+}
 ```
 
 We didn't specify any dependencies, we're relying upon Specs to figure out if it can run concurrently with anything. We do however add it to the dependency list for `MonsterAI` - the AI relies on its results, so it has to be done.
@@ -218,7 +220,7 @@ If you `cargo run` now, monsters no longer end up on top of each other - but the
 let distance = rltk::DistanceAlg::Pythagoras.distance2d(Point::new(pos.x, pos.y), *player_pos);
 if distance < 1.5 {
     // Attack goes here
-    println!("{} shouts insults", name.name);
+    console::log(&format!("{} shouts insults", name.name));
     return;
 }
 ```
@@ -408,7 +410,7 @@ for (_player, pos, viewshed) in (&mut players, &mut positions, &mut viewsheds).j
             None => {}
             Some(t) => {
                 // Attack it
-                println!("From Hell's Heart, I stab thee!");
+                console::log(&format!("From Hell's Heart, I stab thee!"));
                 return; // So we don't move after attacking
             }
         }
@@ -478,9 +480,9 @@ impl<'a> System<'a> for MeleeCombatSystem {
                     let damage = i32::max(0, stats.power - target_stats.defense);
 
                     if damage == 0 {
-                        println!("{} is unable to hurt {}", &name.name, &target_name.name);
+                        console::log(&format!("{} is unable to hurt {}", &name.name, &target_name.name));
                     } else {
-                        println!("{} hits {}, for {} hp.", &name.name, &target_name.name, damage);
+                        console::log(&format!("{} hits {}, for {} hp.", &name.name, &target_name.name, damage));
                         inflict_damage.insert(wants_melee.target, SufferDamage{ amount: damage }).expect("Unable to do damage");
                     }
                 }
@@ -686,18 +688,18 @@ fn tick(&mut self, ctx : &mut Rltk) {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::AwaitingInput;
             }
             RunState::AwaitingInput => {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::AwaitingInput;
             }
         }
@@ -728,7 +730,7 @@ In `player.rs` we simply replace all `Paused` with `AwaitingInput`, and `Running
 
 Lastly, we modify `monster_ai_system` to only run if the state is `MonsterTurn` (snippet):
 
-```
+```rust
 impl<'a> System<'a> for MonsterAI {
 #[allow(clippy::type_complexity)]
 type SystemData = ( WriteExpect<'a, Map>,

+ 4 - 0
chapter-07-damage/Cargo.toml

@@ -10,3 +10,7 @@ edition = "2018"
 rltk = { git = "https://github.com/thebracket/rltk_rs" }
 specs = "0.15.0"
 specs-derive = "0.4.0"
+
+[target.'cfg(any(target_arch = "wasm32"))'.dependencies]
+web-sys = { version = "0.3", features=["console"] }
+wasm-bindgen = "0.2"

+ 2 - 1
chapter-07-damage/src/damage_system.rs

@@ -1,6 +1,7 @@
 extern crate specs;
 use specs::prelude::*;
 use super::{CombatStats, SufferDamage, Player};
+use rltk::console;
 
 pub struct DamageSystem {}
 
@@ -31,7 +32,7 @@ pub fn delete_the_dead(ecs : &mut World) {
                 let player = players.get(entity);
                 match player {
                     None => dead.push(entity),
-                    Some(_) => println!("You are dead")
+                    Some(_) => console::log(&format!("You are dead"))
                 }
             }
         }

+ 23 - 13
chapter-07-damage/src/main.rs

@@ -23,12 +23,29 @@ use melee_combat_system::MeleeCombatSystem;
 mod damage_system;
 use damage_system::DamageSystem;
 
+rltk::add_wasm_support!();
+
 #[derive(PartialEq, Copy, Clone)]
 pub enum RunState { AwaitingInput, PreRun, PlayerTurn, MonsterTurn }
 
 pub struct State {
-    pub ecs: World,
-    pub systems: Dispatcher<'static, 'static>
+    pub ecs: World
+}
+
+impl State {
+    fn run_systems(&mut self) {
+        let mut mapindex = MapIndexingSystem{};
+        mapindex.run_now(&self.ecs);
+        let mut vis = VisibilitySystem{};
+        vis.run_now(&self.ecs);
+        let mut mob = MonsterAI{};
+        mob.run_now(&self.ecs);
+        let mut melee = MeleeCombatSystem{};
+        melee.run_now(&self.ecs);
+        let mut damage = DamageSystem{};
+        damage.run_now(&self.ecs);
+        self.ecs.maintain();
+    }
 }
 
 impl GameState for State {
@@ -42,18 +59,18 @@ impl GameState for State {
         
         match newrunstate {
             RunState::PreRun => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::AwaitingInput;
             }
             RunState::AwaitingInput => {
                 newrunstate = player_input(self, ctx);
             }
             RunState::PlayerTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::MonsterTurn;
             }
             RunState::MonsterTurn => {
-                self.systems.dispatch(&self.ecs);
+                self.run_systems();
                 newrunstate = RunState::AwaitingInput;
             }
         }
@@ -78,16 +95,9 @@ impl GameState for State {
 }
 
 fn main() {
-    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "../resources");
+    let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
     let mut gs = State {
         ecs: World::new(),
-        systems : DispatcherBuilder::new()
-            .with(MapIndexingSystem{}, "map_indexing_system", &[])
-            .with(VisibilitySystem{}, "visibility_system", &[])
-            .with(MonsterAI{}, "monster_ai", &["visibility_system", "map_indexing_system"])
-            .with(MeleeCombatSystem{}, "melee_combat", &["monster_ai"])
-            .with(DamageSystem{}, "damage", &["melee_combat"])
-            .build(),
     };
     gs.ecs.register::<Position>();
     gs.ecs.register::<Renderable>();

+ 3 - 2
chapter-07-damage/src/melee_combat_system.rs

@@ -1,6 +1,7 @@
 extern crate specs;
 use specs::prelude::*;
 use super::{CombatStats, WantsToMelee, Name, SufferDamage};
+use rltk::console;
 
 pub struct MeleeCombatSystem {}
 
@@ -24,9 +25,9 @@ impl<'a> System<'a> for MeleeCombatSystem {
                     let damage = i32::max(0, stats.power - target_stats.defense);
 
                     if damage == 0 {
-                        println!("{} is unable to hurt {}", &name.name, &target_name.name);
+                        console::log(&format!("{} is unable to hurt {}", &name.name, &target_name.name));
                     } else {
-                        println!("{} hits {}, for {} hp.", &name.name, &target_name.name, damage);
+                        console::log(&format!("{} hits {}, for {} hp.", &name.name, &target_name.name, damage));
                         inflict_damage.insert(wants_melee.target, SufferDamage{ amount: damage }).expect("Unable to do damage");
                     }
                 }

+ 1 - 0
wasmbuild.bat

@@ -6,6 +6,7 @@ CALL :Stage chapter-03-walkmap
 CALL :Stage chapter-04-newmap
 CALL :Stage chapter-05-fov
 CALL :Stage chapter-06-monsters
+CALL :Stage chapter-07-damage
 
 REM Publish or perish
 cd book\book\wasm