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