1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
extern crate sdl2;
#[macro_use] pub mod types;
pub mod object;
pub mod pixel;
pub mod renderer;
pub mod screen;
use sdl2::event::Event as SdlEvent;
use std::error;
use std::thread;
use std::time::Duration;
use std::time::Instant;
mod texture;
mod utils;
use renderer::Renderer;
use screen::GraphicalScreen;
const NANOS_PER_SECOND: u32 = 1_000_000_000;
type InitFunc<WorldState, S> =
fn (&mut Renderer<S>) -> Result<WorldState, Box<error::Error>>;
type ParseEventFunc<WorldState> =
fn (&mut LoopState, &mut WorldState, SdlEvent);
type UpdateFunc<WorldState> = fn (&mut WorldState) -> bool;
type RenderFunc<WorldState, S> =
fn (&mut Renderer<S>, &WorldState) -> Result<(), Box<error::Error>>;
pub fn main_loop<'a, WorldState>
(
screen_config: ScreenConfig,
init: InitFunc<WorldState, screen::GraphicalScreen<'a>>,
parse_event: ParseEventFunc<WorldState>,
update: UpdateFunc<WorldState>,
render: RenderFunc<WorldState, screen::GraphicalScreen<'a>>,
)
-> Result<(), Box<error::Error>>
{
let sdl_context = sdl2::init().unwrap();
let screen = try!(GraphicalScreen::new(
screen_config.title,
screen_config.width,
screen_config.height,
&sdl_context,
));
let mut renderer = Renderer::new(screen);
let mut event_pump = sdl_context.event_pump().unwrap();
let mut world_state = try!(init(&mut renderer));
let frame_len_nanos = NANOS_PER_SECOND / screen_config.target_fps;
let mut loop_state = LoopState::new();
while loop_state.running {
let frame_start = Instant::now();
for event in event_pump.poll_iter() {
parse_event(&mut loop_state, &mut world_state, event);
}
if loop_state.should_tick() {
loop_state.step = false;
let frame_dirty = update(&mut world_state);
if frame_dirty { try!(render(&mut renderer, &world_state)); }
}
let frame_len = Instant::now() - frame_start;
let target_frame_len = Duration::new(0, frame_len_nanos);
if frame_len < target_frame_len {
thread::sleep(target_frame_len - frame_len);
} else {
println!("slowed down!");
}
}
Ok(())
}
pub struct ScreenConfig {
pub title: &'static str,
pub width: u32,
pub height: u32,
pub target_fps: u32
}
pub struct LoopState {
pub running: bool,
pub paused: bool,
pub step: bool,
}
impl LoopState {
pub fn new() -> LoopState {
LoopState {
running: true,
paused: false,
step: false,
}
}
pub fn should_tick(&self) -> bool {
!self.paused || self.step
}
}