Built an app builder and other minor things
[kaka/rust-sdl-test.git] / src / game / 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
9c06350b 10use ::{SCREEN_HEIGHT, SCREEN_WIDTH};
95e3e10d 11use boll::*;
6edafdc0 12use common::{Point2D, Rect};
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 18
6edafdc0
TW
19#[derive(Default)]
20pub struct AppBuilder {
21 resolution: Rect<u16>,
22 fps: u8,
23 state: Option<Box<dyn AppState>>,
24 title: Option<String>,
3bfea951
TW
25}
26
6edafdc0
TW
27impl AppBuilder {
28 pub fn with_resolution(mut self, width: u16, height: u16) -> Self {
29 self.resolution = Rect { width, height };
30 self
31 }
32
33 pub fn with_fps(mut self, fps: u8) -> Self {
34 unimplemented!()
35 // self.fps = fps;
36 // self
37 }
38
39 pub fn with_state(mut self, state: Box<dyn AppState>) -> Self {
40 self.state = Some(state);
41 self
42 }
43
44 pub fn with_title(mut self, title: &str) -> Self {
45 self.title = Some(title.to_string());
46 self
47 }
48
49 pub fn start(self) -> App {
3bfea951
TW
50 let context = sdl2::init().unwrap();
51 sdl2::image::init(sdl2::image::InitFlag::PNG).unwrap();
6edafdc0
TW
52 let window = context
53 .video().unwrap()
54 .window(&self.title.unwrap(), self.resolution.width.into(), self.resolution.height.into())
3bfea951
TW
55 .position_centered()
56 .opengl()
6edafdc0 57 .build().unwrap();
3bfea951 58 context.mouse().show_cursor(false);
6edafdc0 59
3bfea951
TW
60 let mut canvas = window.into_canvas().build().unwrap();
61 canvas.set_blend_mode(BlendMode::Add);
62 canvas.set_draw_color(Color::RGB(0, 0, 0));
63 canvas.clear();
64 canvas.present();
6edafdc0 65
3bfea951
TW
66 let event_pump = context.event_pump().unwrap();
67 let sprites = SpriteManager::new(canvas.texture_creator());
6edafdc0 68
3bfea951
TW
69 App {
70 canvas,
71 event_pump,
72 sprites,
6edafdc0 73 state: self.state.unwrap_or(Box::new(ActiveState::new())),
3bfea951
TW
74 }
75 }
6edafdc0
TW
76}
77
78pub struct App {
79 pub canvas: Canvas<Window>,
80 pub event_pump: EventPump,
81 pub sprites: SpriteManager,
82 pub state: Box<dyn AppState>,
83}
84
85impl App {
86 pub fn new() -> AppBuilder {
87 Default::default()
88 }
3bfea951 89
1e322944 90 pub fn load_sprites(&mut self, sprites: &[(&str, &str)]) {
3bfea951
TW
91 for (name, file) in sprites {
92 self.sprites.load(name, file);
93 }
94 }
95}
95e3e10d
TW
96
97pub trait AppState {
98 fn update(&mut self, dt: Nanoseconds);
99 fn render(&self, canvas: &mut Canvas<Window>);
100 fn leave(&self);
101 fn on_event(&mut self, event: Event);
102}
103
104type Bollar = Vec<Box<dyn Boll>>;
105
106pub struct ActiveState {
107 bolls: Bollar,
108 boll_size: u32,
109}
110
111impl ActiveState {
6edafdc0 112 pub fn new() -> ActiveState {
95e3e10d
TW
113 ActiveState {
114 bolls: Bollar::new(),
115 boll_size: 1,
116 }
117 }
118
119 fn change_boll_count(&mut self, delta: i32) {
120 if delta > 0 {
121 for _i in 0..delta {
122 self.add_boll();
123 }
124 } else if delta < 0 {
5cbbebbe 125 for _i in 0..(-delta) {
95e3e10d
TW
126 self.bolls.pop();
127 }
128 }
129 }
130
131 fn add_boll(&mut self) {
132 let mut rng = rand::thread_rng();
133 self.bolls.push(Box::new(SquareBoll {
134 pos: point!(rng.gen_range(0, SCREEN_WIDTH) as f64, rng.gen_range(0, SCREEN_HEIGHT) as f64),
135 vel: point!(rng.gen_range(-2.0, 2.0), rng.gen_range(-2.0, 2.0)),
136 }));
137 }
138}
139
140impl AppState for ActiveState {
141 fn update(&mut self, dt: Nanoseconds) {
93679b27 142 for b in &mut self.bolls {
95e3e10d
TW
143 b.update();
144 }
145
146 match dt {
147 ns if ns < (NS_PER_FRAME - 90_0000) as u64 => { self.change_boll_count(100) }
148 ns if ns > (NS_PER_FRAME + 90_0000) as u64 => { self.change_boll_count(-100) }
149 _ => {}
150 }
151 }
152
153 fn render(&self, canvas: &mut Canvas<Window>) {
93679b27 154 for b in &self.bolls {
95e3e10d
TW
155 b.draw(canvas, self.boll_size);
156 }
157 }
158
159 fn leave(&self) {
160 println!("number of bolls: {}", self.bolls.len());
161 }
162
163 fn on_event(&mut self, event: Event) {
164 match event {
165 Event::KeyDown { keycode: Some(Keycode::KpPlus), .. } => { self.boll_size = std::cmp::min(self.boll_size + 1, 32) }
166 Event::KeyDown { keycode: Some(Keycode::KpMinus), .. } => { self.boll_size = std::cmp::max(self.boll_size - 1, 1) }
167 Event::MouseMotion { x, y, .. } => {
168 self.bolls.push(Box::new(CircleBoll::new(
169 point!(x as f64, y as f64),
170 point!(0.0, 0.0),
171 )))
172 }
173 _ => {}
174 }
175 }
176}