Refactor
[kaka/rust-sdl-test.git] / src / core / game.rs
1 use AppState;
2 use common::Point2D;
3 use core::controller::Controller;
4 use core::controller::ControllerManager;
5 use core::level::Level;
6 use core::render::Renderer;
7 use point;
8 use sdl2::event::Event;
9 use sdl2::joystick::PowerLevel;
10 use sdl2::keyboard::Keycode;
11 use sdl2::rect::Rect;
12 use sprites::SpriteManager;
13 use std::cell::RefCell;
14 use std::rc::Rc;
15 use time::Duration;
16
17 ////////// GAMESTATE ///////////////////////////////////////////////////////////
18
19 #[derive(Default)]
20 pub struct GameState {
21     world: World,
22 }
23
24 impl GameState {
25     pub fn new() -> Self {
26         GameState {
27             world: World::new(),
28         }
29     }
30 }
31
32 impl AppState for GameState {
33     fn enter(&mut self, ctrl_man: &ControllerManager) {
34         if let Some(ctrl) = ctrl_man.controllers.get(&0) {
35             self.world.add(Box::new(Character::new(ctrl.clone())));
36         }
37     }
38
39     fn leave(&mut self) {}
40
41     fn update(&mut self, dt: Duration) {
42         self.world.update(dt);
43     }
44
45     fn render(&mut self, renderer: &mut Renderer, sprites: &SpriteManager) {
46         self.world.render(renderer, sprites);
47     }
48
49     fn handle_event(&mut self, event: Event) {
50         match event {
51             Event::KeyDown { keycode: Some(Keycode::Space), .. } => {
52                 self.world.level.regenerate();
53             }
54             Event::KeyDown { keycode: Some(Keycode::KpPlus), .. } => {
55                 self.world.level.increase_iteration();
56             }
57             Event::KeyDown { keycode: Some(Keycode::KpMinus), .. } => {
58                 self.world.level.decrease_iteration();
59             }
60             _ => {}
61         }
62     }
63 }
64
65 ////////// WORLD ///////////////////////////////////////////////////////////////
66
67 #[derive(Default)]
68 pub struct World {
69     level: Level,
70     objects: Objects,
71 }
72
73 impl World {
74     pub fn new() -> Self {
75         World {
76             level: Level::new(point!(0.0, 0.1), 600.0),
77             ..Default::default()
78         }
79     }
80
81     pub fn update(&mut self, dt: Duration) {
82         let mut breeding_ground = vec!();
83
84         for i in (0..self.objects.len()).rev() {
85             if self.objects[i].update(&mut breeding_ground, &self.level, dt) == Dead {
86                 self.objects.remove(i); // swap_remove is more efficient, but changes the order of the array
87             }
88         }
89
90         for o in breeding_ground {
91             self.add(o);
92         }
93     }
94
95     pub fn render(&mut self, renderer: &mut Renderer, sprites: &SpriteManager) {
96         self.level.render(renderer, sprites);
97         for o in &mut self.objects {
98             o.render(renderer, sprites);
99         }
100     }
101
102     pub fn add(&mut self, object: Box<dyn Object>) {
103         self.objects.push(object);
104     }
105 }
106
107 ////////// OBJECT //////////////////////////////////////////////////////////////
108
109 type Objects = Vec<Box<dyn Object>>;
110
111 pub trait Object {
112     fn update(&mut self, objects: &mut Objects, lvl: &Level, dt: Duration) -> ObjectState;
113     fn render(&self, _renderer: &mut Renderer, _sprites: &SpriteManager) {}
114 }
115
116 #[derive(PartialEq)]
117 pub enum ObjectState { Alive, Dead }
118 use self::ObjectState::*;
119
120
121 pub trait Physical {}
122 pub trait Drawable {}
123
124 ////////// CHARACTER ///////////////////////////////////////////////////////////
125
126 pub struct Character {
127     ctrl: Rc<RefCell<Controller>>,
128     pos: Point2D<f64>,
129     vel: Point2D<f64>,
130 }
131
132 impl Character {
133     pub fn new(ctrl: Rc<RefCell<Controller>>) -> Self {
134         Character {
135             ctrl,
136             pos: point!(100.0, 100.0),
137             vel: point!(0.0, 0.0),
138         }
139     }
140 }
141
142 impl Object for Character {
143     fn update(&mut self, objects: &mut Objects, lvl: &Level, dt: Duration) -> ObjectState {
144         self.vel += lvl.gravity;
145         self.pos += self.vel;
146
147         let ctrl = self.ctrl.borrow();
148
149         if self.pos.y >= lvl.ground {
150             self.pos.y = lvl.ground;
151             self.vel.y = 0.0;
152             self.vel.x *= 0.9;
153
154             if ctrl.jump.is_pressed {
155                 self.vel = ctrl.aim.to_point() * 5.0;
156             }
157         }
158
159         if ctrl.shoot.is_pressed {
160             use rand::distributions::{Distribution, Normal};
161             let normal = Normal::new(0.0, 0.1);
162             for _i in 0..100 {
163                 objects.push(Box::new(Boll {
164                     pos: self.pos,
165                     vel: ctrl.aim.to_point() * (3.0 + rand::random::<f64>()) + point!(normal.sample(&mut rand::thread_rng()), normal.sample(&mut rand::thread_rng())) + self.vel,
166                     bounces: 2,
167                 }));
168             }
169             ctrl.rumble(1.0, dt);
170         }
171
172         if ctrl.start.is_pressed && !ctrl.start.was_pressed {
173             match ctrl.device.power_level() {
174                 Ok(PowerLevel::Unknown) => { println!("power level unknown"); }
175                 Ok(PowerLevel::Empty) => { println!("power level empty"); }
176                 Ok(PowerLevel::Low) => { println!("power level low"); }
177                 Ok(PowerLevel::Medium) => { println!("power level medium"); }
178                 Ok(PowerLevel::Full) => { println!("power level full"); }
179                 Ok(PowerLevel::Wired) => { println!("power level wired"); }
180                 Err(_) => {}
181             };
182         }
183
184         match ctrl.mov.x {
185             v if v < -0.9 => { self.vel.x -= 0.5 }
186             v if v > 0.9 => { self.vel.x += 0.5 }
187             _ => {}
188         }
189
190         Alive
191     }
192
193     fn render(&self, renderer: &mut Renderer, sprites: &SpriteManager) {
194         let block = sprites.get("mario");
195         let size = 32;
196         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));
197
198         let ctrl = &self.ctrl.borrow();
199         let l = 300.0;
200         let pos = (self.pos.x as i32, self.pos.y as i32);
201         // axis values
202         let p = (self.pos + ctrl.aim.to_axis_point() * l).to_i32().into();
203         renderer.draw_line(pos, p, (0, 255, 0));
204         draw_cross(renderer, p);
205         // values limited to unit vector
206         let p = (self.pos + ctrl.aim.to_point() * l).to_i32().into();
207         renderer.draw_line(pos, p, (255, 0, 0));
208         draw_cross(renderer, p);
209         // circle values
210         let p = (self.pos + Point2D::from(ctrl.aim.a) * l).to_i32().into();
211         renderer.draw_line(pos, p, (0, 0, 255));
212         draw_cross(renderer, p);
213     }
214 }
215
216 fn draw_cross(renderer: &mut Renderer, p: (i32, i32)) {
217     renderer.canvas().draw_line((p.0 - 5, p.1), (p.0 + 5, p.1)).unwrap();
218     renderer.canvas().draw_line((p.0, p.1 - 5), (p.0, p.1 + 5)).unwrap();
219 }
220
221 ////////// BOLL ////////////////////////////////////////////////////////////////
222
223 pub struct Boll {
224     pos: Point2D<f64>,
225     vel: Point2D<f64>,
226     bounces: u8,
227 }
228
229 impl Object for Boll {
230     fn update(&mut self, objects: &mut Objects, lvl: &Level, _dt: Duration) -> ObjectState {
231         self.vel += lvl.gravity;
232         self.pos += self.vel;
233
234         let x = (self.pos.x / lvl.grid.cell_size as f64).min(lvl.grid.width as f64 - 1.0).max(0.0) as usize;
235         let y = (self.pos.y / lvl.grid.cell_size as f64).min(lvl.grid.height as f64 - 1.0).max(0.0) as usize;
236         if lvl.grid.cells[x][y] {
237             if self.bounces == 0 {
238                 return Dead
239             }
240             self.vel = -self.vel;
241             self.bounces -= 1;
242             use rand::distributions::{Distribution, Normal};
243             let normal = Normal::new(0.5, 0.4);
244             objects.push(Box::new(Boll {
245                 vel: self.vel * normal.sample(&mut rand::thread_rng()),
246                 ..*self
247             }));
248         }
249
250         Alive
251     }
252
253     fn render(&self, renderer: &mut Renderer, _sprites: &SpriteManager) {
254         let block = _sprites.get("block");
255         let size = 4 + self.bounces * 6;
256         renderer.blit(block, None, Rect::new(self.pos.x as i32 - size as i32 / 2, self.pos.y as i32 - size as i32 / 2, size as u32, size as u32));
257         // renderer.canvas().set_draw_color((0, self.bounces * 100, 255));
258         // renderer.canvas().draw_point((self.pos.x as i32, self.pos.y as i32)).unwrap();
259     }
260 }