expect() with formatting -> unwrap_or_else()
[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 14use NS_PER_FRAME;
787dbfb4 15use point; // defined in common, but loaded from main...
95e3e10d
TW
16
17pub type Nanoseconds = u64;
3bfea951
TW
18
19pub struct App {
20 pub canvas: Canvas<Window>,
21 pub event_pump: EventPump,
22 pub sprites: SpriteManager,
95e3e10d 23 pub state: Box<AppState>,
3bfea951
TW
24}
25
26impl 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,
95e3e10d 47 state: Box::new(ActiveState::new()),
3bfea951
TW
48 }
49 }
50
51 pub fn load_sprites(&mut self, sprites: &[(&'static str, &str)]) {
52 for (name, file) in sprites {
53 self.sprites.load(name, file);
54 }
55 }
56}
95e3e10d
TW
57
58pub 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
65type Bollar = Vec<Box<dyn Boll>>;
66
67pub struct ActiveState {
68 bolls: Bollar,
69 boll_size: u32,
70}
71
72impl 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
101impl AppState for ActiveState {
102 fn update(&mut self, dt: Nanoseconds) {
93679b27 103 for b in &mut self.bolls {
95e3e10d
TW
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>) {
93679b27 115 for b in &self.bolls {
95e3e10d
TW
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}