Moved out objects from game module
[kaka/rust-sdl-test.git] / src / core / object / character.rs
diff --git a/src/core/object/character.rs b/src/core/object/character.rs
new file mode 100644 (file)
index 0000000..8632ee2
--- /dev/null
@@ -0,0 +1,118 @@
+use core::controller::Controller;
+use core::object::boll::Boll;
+use core::level::{Level, Wall, IntersectResult::Intersection};
+use core::object::{Object, Objects, ObjectState};
+use core::render::Renderer;
+use geometry::Point;
+use point;
+use sdl2::rect::Rect;
+use sprites::SpriteManager;
+use std::cell::RefCell;
+use std::rc::Rc;
+use time::Duration;
+
+////////// CHARACTER ///////////////////////////////////////////////////////////
+
+pub struct Character {
+    ctrl: Rc<RefCell<Controller>>,
+    pos: Point<f64>,
+    vel: Point<f64>,
+    standing_on: Option<Wall>,
+}
+
+impl Character {
+    pub fn new(ctrl: Rc<RefCell<Controller>>) -> Self {
+       Character {
+           ctrl,
+           pos: point!(300.0, 300.0),
+           vel: point!(0.0, 0.0),
+           standing_on: None,
+       }
+    }
+}
+
+impl Object for Character {
+    fn update(&mut self, objects: &mut Objects, lvl: &Level, dt: Duration) -> ObjectState {
+       let ctrl = self.ctrl.borrow();
+
+       match &self.standing_on {
+           Some(wall) => {
+               if ctrl.jump.is_pressed && !ctrl.jump.was_pressed {
+                   if ctrl.mov.to_point().length() < 0.1 {
+                       self.vel = wall.normal().into();
+                   } else {
+                       self.vel = ctrl.mov.to_point();
+                   }
+                   self.vel *= 5.0;
+                   self.pos += self.vel * 0.1;
+                   self.standing_on = None;
+               } else {
+                   self.vel *= 0.9;
+               }
+           },
+           None => {
+               self.vel += lvl.gravity;
+               self.pos += self.vel;
+
+               match ctrl.mov.x {
+                   v if v < -0.9 && self.vel.x > -5.0 => { self.vel.x -= 0.5 }
+                   v if v > 0.9 && self.vel.x < 5.0 => { self.vel.x += 0.5 }
+                   _ => {}
+               }
+
+               if let Intersection(wall, pos) = lvl.intersect_walls(self.pos - self.vel, self.pos) {
+                   self.standing_on = Some(wall);
+                   self.pos = pos;
+                   self.vel = point!(0.0, 0.0);
+               }
+           }
+       }
+
+       if ctrl.shoot.is_pressed {
+           use rand::distributions::{Distribution, Normal};
+           let normal = Normal::new(0.0, 0.1);
+           let direction = if ctrl.aim.to_point().length() > 0.1 { ctrl.aim.to_point() } else { ctrl.mov.to_point() };
+           for _i in 0..100 {
+               objects.push(Box::new(Boll::new(
+                   self.pos + point!(0.0, -16.0), // half the height of mario
+                   direction * (10.0 + rand::random::<f64>()) + point!(normal.sample(&mut rand::thread_rng()), normal.sample(&mut rand::thread_rng())) + self.vel,
+                   2,
+               )));
+           }
+           ctrl.rumble(1.0, dt);
+           self.vel -= direction * 0.1;
+       }
+
+       ObjectState::Alive
+    }
+
+    fn render(&self, renderer: &mut Renderer, sprites: &SpriteManager) {
+        let block = sprites.get("mario");
+       let size = 32;
+        renderer.blit(block, None, Rect::new(self.pos.x as i32 - size as i32 / 2, self.pos.y as i32 - size as i32, size, size));
+
+       let ctrl = &self.ctrl.borrow();
+       let l = 300.0;
+       let pos = (self.pos.x as i32, self.pos.y as i32);
+       // // axis values
+       // let p = (self.pos + ctrl.aim.to_axis_point() * l).to_i32().into();
+       // renderer.draw_line(pos, p, (0, 255, 0));
+       // draw_cross(renderer, p);
+       // values limited to unit vector
+       let p = (self.pos + ctrl.aim.to_point() * l).to_i32().into();
+       renderer.draw_line(pos, p, (255, 0, 0));
+       draw_cross(renderer, p);
+       let p = (self.pos + ctrl.mov.to_point() * l).to_i32().into();
+       renderer.draw_line(pos, p, (0, 255, 0));
+       draw_cross(renderer, p);
+       // // circle values
+       // let p = (self.pos + Point::from(ctrl.aim.a) * l).to_i32().into();
+       // renderer.draw_line(pos, p, (0, 0, 255));
+       // draw_cross(renderer, p);
+    }
+}
+
+fn draw_cross(renderer: &mut Renderer, p: (i32, i32)) {
+    renderer.canvas().draw_line((p.0 - 5, p.1), (p.0 + 5, p.1)).unwrap();
+    renderer.canvas().draw_line((p.0, p.1 - 5), (p.0, p.1 + 5)).unwrap();
+}