8632ee2a0c13a626ea17e134db3cc81367775dc4
[kaka/rust-sdl-test.git] / src / core / object / character.rs
1 use core::controller::Controller;
2 use core::object::boll::Boll;
3 use core::level::{Level, Wall, IntersectResult::Intersection};
4 use core::object::{Object, Objects, ObjectState};
5 use core::render::Renderer;
6 use geometry::Point;
7 use point;
8 use sdl2::rect::Rect;
9 use sprites::SpriteManager;
10 use std::cell::RefCell;
11 use std::rc::Rc;
12 use time::Duration;
13
14 ////////// CHARACTER ///////////////////////////////////////////////////////////
15
16 pub struct Character {
17     ctrl: Rc<RefCell<Controller>>,
18     pos: Point<f64>,
19     vel: Point<f64>,
20     standing_on: Option<Wall>,
21 }
22
23 impl Character {
24     pub fn new(ctrl: Rc<RefCell<Controller>>) -> Self {
25         Character {
26             ctrl,
27             pos: point!(300.0, 300.0),
28             vel: point!(0.0, 0.0),
29             standing_on: None,
30         }
31     }
32 }
33
34 impl Object for Character {
35     fn update(&mut self, objects: &mut Objects, lvl: &Level, dt: Duration) -> ObjectState {
36         let ctrl = self.ctrl.borrow();
37
38         match &self.standing_on {
39             Some(wall) => {
40                 if ctrl.jump.is_pressed && !ctrl.jump.was_pressed {
41                     if ctrl.mov.to_point().length() < 0.1 {
42                         self.vel = wall.normal().into();
43                     } else {
44                         self.vel = ctrl.mov.to_point();
45                     }
46                     self.vel *= 5.0;
47                     self.pos += self.vel * 0.1;
48                     self.standing_on = None;
49                 } else {
50                     self.vel *= 0.9;
51                 }
52             },
53             None => {
54                 self.vel += lvl.gravity;
55                 self.pos += self.vel;
56
57                 match ctrl.mov.x {
58                     v if v < -0.9 && self.vel.x > -5.0 => { self.vel.x -= 0.5 }
59                     v if v > 0.9 && self.vel.x < 5.0 => { self.vel.x += 0.5 }
60                     _ => {}
61                 }
62
63                 if let Intersection(wall, pos) = lvl.intersect_walls(self.pos - self.vel, self.pos) {
64                     self.standing_on = Some(wall);
65                     self.pos = pos;
66                     self.vel = point!(0.0, 0.0);
67                 }
68             }
69         }
70
71         if ctrl.shoot.is_pressed {
72             use rand::distributions::{Distribution, Normal};
73             let normal = Normal::new(0.0, 0.1);
74             let direction = if ctrl.aim.to_point().length() > 0.1 { ctrl.aim.to_point() } else { ctrl.mov.to_point() };
75             for _i in 0..100 {
76                 objects.push(Box::new(Boll::new(
77                     self.pos + point!(0.0, -16.0), // half the height of mario
78                     direction * (10.0 + rand::random::<f64>()) + point!(normal.sample(&mut rand::thread_rng()), normal.sample(&mut rand::thread_rng())) + self.vel,
79                     2,
80                 )));
81             }
82             ctrl.rumble(1.0, dt);
83             self.vel -= direction * 0.1;
84         }
85
86         ObjectState::Alive
87     }
88
89     fn render(&self, renderer: &mut Renderer, sprites: &SpriteManager) {
90         let block = sprites.get("mario");
91         let size = 32;
92         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));
93
94         let ctrl = &self.ctrl.borrow();
95         let l = 300.0;
96         let pos = (self.pos.x as i32, self.pos.y as i32);
97         // // axis values
98         // let p = (self.pos + ctrl.aim.to_axis_point() * l).to_i32().into();
99         // renderer.draw_line(pos, p, (0, 255, 0));
100         // draw_cross(renderer, p);
101         // values limited to unit vector
102         let p = (self.pos + ctrl.aim.to_point() * l).to_i32().into();
103         renderer.draw_line(pos, p, (255, 0, 0));
104         draw_cross(renderer, p);
105         let p = (self.pos + ctrl.mov.to_point() * l).to_i32().into();
106         renderer.draw_line(pos, p, (0, 255, 0));
107         draw_cross(renderer, p);
108         // // circle values
109         // let p = (self.pos + Point::from(ctrl.aim.a) * l).to_i32().into();
110         // renderer.draw_line(pos, p, (0, 0, 255));
111         // draw_cross(renderer, p);
112     }
113 }
114
115 fn draw_cross(renderer: &mut Renderer, p: (i32, i32)) {
116     renderer.canvas().draw_line((p.0 - 5, p.1), (p.0 + 5, p.1)).unwrap();
117     renderer.canvas().draw_line((p.0, p.1 - 5), (p.0, p.1 + 5)).unwrap();
118 }