| 
					
				 | 
			
			
				@@ -1,5 +1,7 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#[macro_use] extern crate specs_derive; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#[macro_use] extern crate specs_system_macro; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#[macro_use] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern crate specs_derive; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#[macro_use] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extern crate specs_system_macro; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 use ggez::graphics::Drawable; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 use specs::prelude::*; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -44,36 +46,30 @@ impl Sprite { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /// Convert one of the pre-known sprites to is intended visual appearance 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     fn to_mesh(&self, ctx: &mut ggez::Context) -> ggez::GameResult<ggez::graphics::Mesh> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         match self { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Sprite::Player => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ggez::graphics::Mesh::new_circle( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    ggez::graphics::DrawMode::fill(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    [0.0, 0.0], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    10.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    0.1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    ggez::graphics::WHITE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Sprite::Hostile => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ggez::graphics::Mesh::new_circle( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    ggez::graphics::DrawMode::fill(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    [0.0, 0.0], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    10.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    0.1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    (1.0, 0.0, 0.0).into(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Sprite::Kaboom => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ggez::graphics::Mesh::new_circle( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    ggez::graphics::DrawMode::stroke(1.0), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    [0.0, 0.0], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    20.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    0.1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    (0.0, 1.0, 0.0).into(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Sprite::Player => ggez::graphics::Mesh::new_circle( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ggez::graphics::DrawMode::fill(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                [0.0, 0.0], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                10.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                0.1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ggez::graphics::WHITE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Sprite::Hostile => ggez::graphics::Mesh::new_circle( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ggez::graphics::DrawMode::fill(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                [0.0, 0.0], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                10.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                0.1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                (1.0, 0.0, 0.0).into(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Sprite::Kaboom => ggez::graphics::Mesh::new_circle( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ggez::graphics::DrawMode::stroke(1.0), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                [0.0, 0.0], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                20.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                0.1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                (0.0, 1.0, 0.0).into(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -86,16 +82,6 @@ pub struct Position { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     y: f32, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-impl Position { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /// Lazy collision detection: returns true if the two points are 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /// within 20 units of each other 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    fn close_to(&self, other: &Position) -> bool{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let dx = self.x - other.x; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let dy = self.y - other.y; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        (dx * dx + dy * dy).sqrt() < 20.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /// A component for things which move around the screen at a specific 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /// velocity 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #[derive(Component)] 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -129,7 +115,6 @@ pub struct HP { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // * KeyState impl 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /// A KeyState contains four bools that indicate whether particular 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /// keys are held (the only four keys we care about, the famous 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /// Gamer's Square: W, A, S, and who can forget D?) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -182,7 +167,6 @@ impl KeyState { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             self.d_pressed = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // * systems 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -212,7 +196,11 @@ impl<'a, 't> specs::System<'a> for Draw<'t> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 dest: [pos.x, pos.y].into(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 ..ggez::graphics::DrawParam::default() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            draw.sprite.to_mesh(self.ctx).unwrap().draw(self.ctx, param).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            draw.sprite 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .to_mesh(self.ctx) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .unwrap() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .draw(self.ctx, param) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // find the HP of the player and print it on the screen 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for (hp, _) in (&hp, &controlled).join() { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -229,7 +217,7 @@ impl<'a, 't> specs::System<'a> for Draw<'t> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // based on the current state of the keys. The longer you hold keys, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // the more it'll accelerate, up to some fixed speed (20 units per 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // tick) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-system!{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+system! { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     Control(resource kc: KeyState, _c: Controlled, mut v: Velocity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         const SPEEDUP: f32 = 0.2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if kc.w_pressed { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -249,9 +237,8 @@ system!{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // This applies friction to components, currently by a global amount 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-system!{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+system! { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     Slowdown(mut v: Velocity, _c: Controlled) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         const ROUNDING: f32 = 0.01; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         const FRICTION: f32 = 0.95; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -269,7 +256,7 @@ system!{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // This moves components around and handles wrapping them 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-system!{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+system! { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     Move(mut pos: Position, v: Velocity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         pos.x += v.dx; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         pos.y += v.dy; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -286,49 +273,39 @@ system!{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// This naively handles collision detection in a shitty way that 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// would never scale for anything real 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-system_impl!{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+system_impl! { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     Collision( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         en: Entity, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        resource mut world: ncollide2d::world::CollisionWorld<f32, CollisionData>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         mut pos: Position, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        hp: HP, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        col: Collidable, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         mut lifetime: Lifetime, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         mut drawn: Drawn, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         mut damage: AppliesDamage, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let mut seen = std::collections::HashMap::new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // just compare every entity to every other one 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for (e1, p1, _) in (&en, &pos, &hp).join() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            for (e2, p2, _) in (&en, &pos, &hp).join() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // don't collide with ourselves, that's stupid 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if e1 == e2 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        use nalgebra::Isometry2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (p, c) in (&mut pos, &col).join() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            world.get_mut(c.handle).expect("Unable to find collision object") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .set_position(Isometry2::translation(p.x / 10.0, p.y / 10.0)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        world.update(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (c1, c2, _, man) in world.contact_pairs(true) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if let Some(m) = man.deepest_contact() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                let a = m.contact.world1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                let ping = en.create(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                lifetime.insert(ping, Lifetime { lifetime: 10 }).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                drawn.insert(ping, Drawn { sprite: Sprite::Kaboom }).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                pos.insert(ping, Position {x: a.x * 10.0, y: a.y * 10.0}).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if let Some(e1) = world.collision_object(c1).unwrap().data().for_entity { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    damage.insert(en.create(), AppliesDamage { target: e1 }).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // if they're close and we haven't already looked at 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // this one (which we might have!) then add it to the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // set of collisions 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if p1.close_to(p2) && !seen.contains_key(&(e1, e2)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    seen.insert((e1, e2), p1.clone()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if let Some(e2) = world.collision_object(c2).unwrap().data().for_entity { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    damage.insert(en.create(), AppliesDamage { target: e2 }).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // now, for each collision 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for ((e1, e2), p) in seen { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // create the kaboom graphic! it'll only last 10 ticks, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // such is the nature of kabooms. (this should probably be 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // split apart into another system, but whatevs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            let ping = en.create(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            lifetime.insert(ping, Lifetime { lifetime: 10 }).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            drawn.insert(ping, Drawn { sprite: Sprite::Kaboom }).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            pos.insert(ping, p).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // and create the damage events 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            let ev1 = en.create(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            damage.insert(ev1, AppliesDamage { target: e1 }).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            let ev2 = en.create(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            damage.insert(ev2, AppliesDamage { target: e2 }).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -355,16 +332,25 @@ system_impl! { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for dmg in (&dmg).join() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if let Some(target) = hp.get_mut(dmg.target) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                target.hp -= 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 if target.hp == 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     en.delete(dmg.target).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                target.hp -= 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         dmg.clear(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+pub struct CollisionData { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for_entity: Option<specs::Entity>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#[derive(Component)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+pub struct Collidable { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handle: ncollide2d::pipeline::CollisionObjectSlabHandle, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // * game definition 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /// A game just needs a specs world! All our state is in there 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -374,6 +360,11 @@ struct MyGame { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 impl MyGame { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     fn setup() -> MyGame { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        use nalgebra::Isometry2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        use ncollide2d::pipeline::{CollisionGroups, GeometricQueryType}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        use ncollide2d::shape::{Ball, ShapeHandle}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        use ncollide2d::world::CollisionWorld; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // this is the first step in making apple pie from scratch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         let mut world = specs::World::new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // register some component types 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -384,17 +375,41 @@ impl MyGame { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         world.register::<HP>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         world.register::<Lifetime>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         world.register::<AppliesDamage>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        world.register::<Collidable>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // create our blank key state 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         world.insert(KeyState::new()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // create a collision world 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut collision_world = CollisionWorld::<f32, CollisionData>::new(0.02); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut group = CollisionGroups::new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        group.set_membership(&[0]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        group.set_whitelist(&[0]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let contacts_query = GeometricQueryType::Contacts(0.0, 0.0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // create a player 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        world.create_entity() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            .with(Drawn { sprite: Sprite::Player }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let (player_handle, object) = collision_world.add( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Isometry2::translation(20.0, 20.0), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ShapeHandle::new(Ball::new(1.0)), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            group, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            contacts_query, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            CollisionData { for_entity: None }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let player = world 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .create_entity() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .with(Drawn { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                sprite: Sprite::Player, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             .with(Position { x: 200.0, y: 200.0 }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             .with(Controlled) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             .with(Velocity { dx: 0.0, dy: 0.0 }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             .with(HP { hp: MAX_HP }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .with(Collidable { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                handle: player_handle, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             .build(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        object.data_mut().for_entity = Some(player); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // create ten ENEMY ORBS!!!!!!!11111one 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for _ in 0..10 { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -402,18 +417,31 @@ impl MyGame { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             let y = rand::random::<f32>() * HEIGHT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             let dx = (rand::random::<f32>() * 20.0) - 10.0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             let dy = (rand::random::<f32>() * 20.0) - 10.0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            world.create_entity() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                .with(Drawn { sprite: Sprite::Hostile }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let (handle, object) = collision_world.add( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Isometry2::translation(x / 10.0, y / 10.0), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ShapeHandle::new(Ball::new(1.0)), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                group, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                contacts_query, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                CollisionData { for_entity: None }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let orb = world 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .create_entity() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .with(Drawn { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    sprite: Sprite::Hostile, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 .with(Position { x, y }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 .with(Velocity { dx, dy }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 .with(HP { hp: 50 }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .with(Collidable { handle }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 .build(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            object.data_mut().for_entity = Some(orb); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        world.insert(collision_world); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // this is the world I have created. observe it and despair 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         MyGame { world } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 impl ggez::event::EventHandler for MyGame { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -447,8 +475,7 @@ impl ggez::event::EventHandler for MyGame { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if keycode == winit::VirtualKeyCode::Escape { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ggez::event::quit(ctx); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        KeyState::handle_down(&mut self.world.write_resource(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                              keycode); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        KeyState::handle_down(&mut self.world.write_resource(), keycode); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     fn key_up_event( 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -457,10 +484,8 @@ impl ggez::event::EventHandler for MyGame { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         keycode: winit::VirtualKeyCode, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         _keymod: ggez::event::KeyMods, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        KeyState::handle_up(&mut self.world.write_resource(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            keycode); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        KeyState::handle_up(&mut self.world.write_resource(), keycode); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // * main 
			 |