Browse Source

Add informative README

Getty Ritter 4 years ago
parent
commit
41c481e23e
1 changed files with 84 additions and 0 deletions
  1. 84 0
      README.md

+ 84 - 0
README.md

@@ -0,0 +1,84 @@
+Many systems defined with [specs](https://crates.io/crates/specs) are relatively mechanical in terms of what they do, and require some redundant structure. For example, a system that moves entities according to their velocity if they have not experiences a collision might look like this:
+
+```rust
+// define a type so we can implement the system for that type
+struct Physics;
+
+// provide the System impl
+impl<'a> specs::System<'a> for Physics {
+    // we need read access to the velocity and collision, and write access to
+    // the entity's position
+    type SystemData = (
+        specs::ReadStorage<'a, Velocity>,
+        specs::ReadStorage<'a, Collision>,
+        specs::WriteStorage<'a, Position>,
+    );
+
+    // we take an instance of systemdata as the argument, which we destruct immediately
+    fn run(&mut self, (velocity, collision, mut position): Self::SystemData) {
+        // but then join on it to find all entities that contain velocity, collision, and position
+        for (vel, col, pos) in (&velocity, &collision, &mut position).join() {
+            // and run something over all of them
+            if !col.has_collision {
+                pos.x += vel.dx;
+                pos.y += vel.dy;
+            }
+        }
+    }
+}
+```
+
+This macro makes defining systems like these easier: the above system can in its entirety be replaced by the macro invocation
+
+```rust
+system!{
+    Physics(vel: Velocity, col: Collision, mut pos: Position) {
+        if !col.has_collision {
+            pos.x += vel.dx;
+            pos.y += vel.dy;
+        }
+    }
+}
+```
+
+The body of the "system" is executed in a loop over all the entities that implement the described components, and the presence or absence of `mut` dictates whether we want to use `WriteStorage` or `ReadStorage`. The end result is a unit struct `Physics` that already has an operationally identical `System` implementation.
+
+Several systems might also require some final cleanup'code: for example, clearing the component storage for a specific component. For example, the following system uses `damage.clear()` after the loop in order to remove the `SufferDamage` component from every entity that has it:
+
+```
+pub struct DamageSystem;
+
+impl<'a> System<'a> for DamageSystem {
+    type SystemData = (
+        WriteStorage<'a, CombatStats>,
+        WriteStorage<'a, SufferDamage>,
+    );
+
+    fn run(&mut self, (mut stats, mut damage): Self::SystemData) {
+        for (mut stats, damage) in (&mut stats, &damage).join() {
+            stats.hp -= damage.amount;
+        }
+        damage.clear();
+    }
+}
+```
+
+The `system!` macro allows for a `finally` block that executes after the loop, in which the same bound names refer to the storage for the component rather than the component itself, which means the above system can be written as:
+
+```rust
+system! {
+    DamageSystem (mut stats: CombatStats, mut damage: SufferDamage) {
+        // damage has type SufferDamage
+        stats.hp -= damage.amount;
+    } finally {
+        // damage has type WriteStorage<SufferDamage>
+        damage.clear();
+    }
+}
+```
+
+## TODO:
+
+- [ ] Read/write access to resources
+- [ ] Setup blocks in addition to finally blocks
+- [ ] Systems