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