50acaa10725b6a3b689e2cd089e95b6b48559089
[kaka/rust-sdl-test.git] / src / game / app.rs
1 use rand::Rng;
2 use sdl2::event::Event;
3 use sdl2::EventPump;
4 use sdl2::keyboard::Keycode;
5 use sdl2::pixels::Color;
6 use sdl2::render::BlendMode;
7 use sdl2::render::Canvas;
8 use sdl2::video::Window;
9
10 use ::{SCREEN_HEIGHT, SCREEN_WIDTH};
11 use boll::*;
12 use common::Point2D;
13 use sprites::SpriteManager;
14 use NS_PER_FRAME;
15 use point; // defined in common, but loaded from main...
16
17 pub type Nanoseconds = u64;
18
19 pub struct App {
20     pub canvas: Canvas<Window>,
21     pub event_pump: EventPump,
22     pub sprites: SpriteManager,
23     pub state: Box<dyn AppState>,
24 }
25
26 impl App {
27     pub fn new() -> App {
28         let context = sdl2::init().unwrap();
29         sdl2::image::init(sdl2::image::InitFlag::PNG).unwrap();
30         let window = context.video().unwrap().window("SDL test", SCREEN_WIDTH, SCREEN_HEIGHT)
31             .position_centered()
32             .opengl()
33             .build()
34             .unwrap();
35         context.mouse().show_cursor(false);
36         let mut canvas = window.into_canvas().build().unwrap();
37         canvas.set_blend_mode(BlendMode::Add);
38         canvas.set_draw_color(Color::RGB(0, 0, 0));
39         canvas.clear();
40         canvas.present();
41         let event_pump = context.event_pump().unwrap();
42         let sprites = SpriteManager::new(canvas.texture_creator());
43         App {
44             canvas,
45             event_pump,
46             sprites,
47             state: Box::new(ActiveState::new()),
48         }
49     }
50
51     pub fn load_sprites(&mut self, sprites: &[(&str, &str)]) {
52         for (name, file) in sprites {
53             self.sprites.load(name, file);
54         }
55     }
56 }
57
58 pub trait AppState {
59     fn update(&mut self, dt: Nanoseconds);
60     fn render(&self, canvas: &mut Canvas<Window>);
61     fn leave(&self);
62     fn on_event(&mut self, event: Event);
63 }
64
65 type Bollar = Vec<Box<dyn Boll>>;
66
67 pub struct ActiveState {
68     bolls: Bollar,
69     boll_size: u32,
70 }
71
72 impl ActiveState {
73     fn new() -> ActiveState {
74         ActiveState {
75             bolls: Bollar::new(),
76             boll_size: 1,
77         }
78     }
79
80     fn change_boll_count(&mut self, delta: i32) {
81         if delta > 0 {
82             for _i in 0..delta {
83                 self.add_boll();
84             }
85         } else if delta < 0 {
86             for _i in 0..(-delta) {
87                 self.bolls.pop();
88             }
89         }
90     }
91
92     fn add_boll(&mut self) {
93         let mut rng = rand::thread_rng();
94         self.bolls.push(Box::new(SquareBoll {
95             pos: point!(rng.gen_range(0, SCREEN_WIDTH) as f64, rng.gen_range(0, SCREEN_HEIGHT) as f64),
96             vel: point!(rng.gen_range(-2.0, 2.0), rng.gen_range(-2.0, 2.0)),
97         }));
98     }
99 }
100
101 impl AppState for ActiveState {
102     fn update(&mut self, dt: Nanoseconds) {
103         for b in &mut self.bolls {
104             b.update();
105         }
106
107         match dt {
108             ns if ns < (NS_PER_FRAME - 90_0000) as u64 => { self.change_boll_count(100) }
109             ns if ns > (NS_PER_FRAME + 90_0000) as u64 => { self.change_boll_count(-100) }
110             _ => {}
111         }
112     }
113
114     fn render(&self, canvas: &mut Canvas<Window>) {
115         for b in &self.bolls {
116             b.draw(canvas, self.boll_size);
117         }
118     }
119
120     fn leave(&self) {
121         println!("number of bolls: {}", self.bolls.len());
122     }
123
124     fn on_event(&mut self, event: Event) {
125         match event {
126             Event::KeyDown { keycode: Some(Keycode::KpPlus), .. } => { self.boll_size = std::cmp::min(self.boll_size + 1, 32) }
127             Event::KeyDown { keycode: Some(Keycode::KpMinus), .. } => { self.boll_size = std::cmp::max(self.boll_size - 1, 1) }
128             Event::MouseMotion { x, y, .. } => {
129                 self.bolls.push(Box::new(CircleBoll::new(
130                     point!(x as f64, y as f64),
131                     point!(0.0, 0.0),
132                 )))
133             }
134             _ => {}
135         }
136     }
137 }