|
|
@@ -1,29 +1,161 @@
|
|
|
extern crate sdl2;
|
|
|
|
|
|
+use std::fs::File;
|
|
|
+use std::io::{Read, Write};
|
|
|
+use std::time::{Duration, SystemTime};
|
|
|
+use std::{io, thread};
|
|
|
+
|
|
|
use sdl2::event::Event;
|
|
|
use sdl2::keyboard::Keycode;
|
|
|
use sdl2::pixels::Color;
|
|
|
-use std::time::Duration;
|
|
|
+use sdl2::rect::Rect;
|
|
|
+use sdl2::render::{Texture, TextureCreator, WindowCanvas};
|
|
|
+use sdl2::video::WindowContext;
|
|
|
+
|
|
|
+// Crate a texture with 32x32 size
|
|
|
+const TEXTURE_SIZE: u32 = 32;
|
|
|
+const SCORE_FILE_NAME: &str = "scores.txt";
|
|
|
+
|
|
|
+#[derive(Clone, Copy)]
|
|
|
+enum TextureColor {
|
|
|
+ Green,
|
|
|
+ Blue,
|
|
|
+}
|
|
|
+
|
|
|
+fn create_texture_rect<'a>(
|
|
|
+ canvas: &mut WindowCanvas,
|
|
|
+ texture_creator: &'a TextureCreator<WindowContext>,
|
|
|
+ color: TextureColor,
|
|
|
+ size: u32,
|
|
|
+) -> Option<Texture<'a>> {
|
|
|
+ if let Ok(mut square_texture) = texture_creator.create_texture_target(None, size, size) {
|
|
|
+ canvas
|
|
|
+ .with_texture_canvas(&mut square_texture, |texture| {
|
|
|
+ match color {
|
|
|
+ TextureColor::Green => texture.set_draw_color(Color::RGB(0, 255, 0)),
|
|
|
+ TextureColor::Blue => texture.set_draw_color(Color::RGB(0, 0, 255)),
|
|
|
+ }
|
|
|
+ texture.clear();
|
|
|
+ })
|
|
|
+ .expect("Failed to color a texture");
|
|
|
+ Some(square_texture)
|
|
|
+ } else {
|
|
|
+ None
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// # 写入文件
|
|
|
+/// @content 内容
|
|
|
+///
|
|
|
+/// @file_name 文件名
|
|
|
+fn write_into_file(content: &str, file_name: &str) -> io::Result<()> {
|
|
|
+ let mut f = File::create(file_name)?;
|
|
|
+ f.write_all(content.as_bytes())
|
|
|
+}
|
|
|
+
|
|
|
+/// # 读取文件内容
|
|
|
+/// file_name 文件名
|
|
|
+///
|
|
|
+/// Return io::Result<String>
|
|
|
+fn read_from_file(file_name: &str) -> io::Result<String> {
|
|
|
+ let mut f = File::open(file_name)?;
|
|
|
+ let mut content = String::new();
|
|
|
+ f.read_to_string(&mut content)?;
|
|
|
+ Ok(content)
|
|
|
+}
|
|
|
+
|
|
|
+/// To keep things simple, we'll have a very simple file format:
|
|
|
+///
|
|
|
+/// 1. On the fire line, we store the best scores
|
|
|
+///
|
|
|
+/// 2. On the second line, we store the highest number of lines.
|
|
|
+fn slice_to_string(slice: &[u32]) -> String {
|
|
|
+ slice
|
|
|
+ .iter()
|
|
|
+ .map(|highscore| highscore.to_string())
|
|
|
+ .collect::<Vec<String>>()
|
|
|
+ .join(" ")
|
|
|
+}
|
|
|
+fn save_highscore_and_lines(highscores: &[u32], number_of_lines: &[u32]) -> bool {
|
|
|
+ let s_highscores = slice_to_string(highscores);
|
|
|
+ let s_number_of_lines = slice_to_string(number_of_lines);
|
|
|
+ write_into_file(
|
|
|
+ &*format!("{}\n{}\n", s_highscores, s_number_of_lines),
|
|
|
+ SCORE_FILE_NAME,
|
|
|
+ )
|
|
|
+ .is_ok()
|
|
|
+}
|
|
|
+/// # Reading formatted data from files
|
|
|
+fn line_to_slice(line: &str) -> Vec<u32> {
|
|
|
+ line.split(" ")
|
|
|
+ .filter_map(|nb| nb.parse::<u32>().ok())
|
|
|
+ .collect()
|
|
|
+}
|
|
|
+fn load_highscores_and_lines() -> Option<(Vec<u32>, Vec<u32>)> {
|
|
|
+ if let Ok(content) = read_from_file(SCORE_FILE_NAME) {
|
|
|
+ let mut lines = content
|
|
|
+ .splitn(2, "\n")
|
|
|
+ .map(|line| line_to_slice(line))
|
|
|
+ .collect::<Vec<_>>();
|
|
|
+
|
|
|
+ if lines.len() == 2 {
|
|
|
+ let (number_lines, hightscores) = (lines.pop().unwrap(), lines.pop().unwrap());
|
|
|
+ Some((hightscores, number_lines))
|
|
|
+ } else {
|
|
|
+ None
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ None
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
pub fn main() {
|
|
|
let sdl_context = sdl2::init().expect("SDL init failed");
|
|
|
let video_subsystem = sdl_context.video().expect("Couldn't get video subsystem");
|
|
|
|
|
|
+ // Parameters are: title, width, height
|
|
|
let window = video_subsystem
|
|
|
.window("rust-sdl2 demo", 800, 600)
|
|
|
- .position_centered()
|
|
|
- .build()
|
|
|
+ .position_centered() // to put it in the middle of the screen
|
|
|
+ .build() // to create the window
|
|
|
.unwrap();
|
|
|
|
|
|
- let mut canvas = window.into_canvas().build().expect("Failed to get SDL event pump");
|
|
|
+ let mut canvas = window
|
|
|
+ .into_canvas()
|
|
|
+ .target_texture()
|
|
|
+ .present_vsync() // To enable v-sync.
|
|
|
+ .build()
|
|
|
+ .expect("Failed to get SDL event pump");
|
|
|
|
|
|
- canvas.set_draw_color(Color::RGB(255, 0, 0));
|
|
|
- canvas.clear();
|
|
|
- canvas.present();
|
|
|
- let mut event_pump = sdl_context.event_pump().unwrap();
|
|
|
+ let texture_creator: TextureCreator<_> = canvas.texture_creator();
|
|
|
+
|
|
|
+ // Web create a texture with a 32x32 size.
|
|
|
+ let green_square = create_texture_rect(
|
|
|
+ &mut canvas,
|
|
|
+ &texture_creator,
|
|
|
+ TextureColor::Green,
|
|
|
+ TEXTURE_SIZE,
|
|
|
+ )
|
|
|
+ .expect("Failed to create a texture");
|
|
|
+
|
|
|
+ let blue_square = create_texture_rect(
|
|
|
+ &mut canvas,
|
|
|
+ &texture_creator,
|
|
|
+ TextureColor::Blue,
|
|
|
+ TEXTURE_SIZE,
|
|
|
+ )
|
|
|
+ .expect("Failed to create a texture");
|
|
|
+
|
|
|
+ let timer = SystemTime::now();
|
|
|
+
|
|
|
+ let mut event_pump = sdl_context
|
|
|
+ .event_pump()
|
|
|
+ .expect("Failed to get SDL event pump");
|
|
|
'running: loop {
|
|
|
for event in event_pump.poll_iter() {
|
|
|
match event {
|
|
|
+ // If we receive a 'quit' event or if the user press the
|
|
|
+ // 'ESC' key, we quit.
|
|
|
Event::Quit { .. }
|
|
|
| Event::KeyDown {
|
|
|
keycode: Some(Keycode::Escape),
|
|
|
@@ -33,7 +165,36 @@ pub fn main() {
|
|
|
}
|
|
|
}
|
|
|
// The rest of the game loop goes here...
|
|
|
+ canvas.set_draw_color(Color::RGB(255, 0, 0));
|
|
|
+ // We draw it
|
|
|
+ canvas.clear();
|
|
|
+
|
|
|
+ // The rectangle switch happens here:
|
|
|
+ let display_green = match timer.elapsed() {
|
|
|
+ Ok(elapsed) => elapsed.as_secs() % 2 == 0,
|
|
|
+ Err(_) => {
|
|
|
+ // In case of error, we do nothing
|
|
|
+ true
|
|
|
+ }
|
|
|
+ };
|
|
|
+ let square_texture = if display_green {
|
|
|
+ &green_square
|
|
|
+ } else {
|
|
|
+ &blue_square
|
|
|
+ };
|
|
|
+ // Copy our texture into the window.
|
|
|
+ canvas
|
|
|
+ .copy(
|
|
|
+ &square_texture,
|
|
|
+ None,
|
|
|
+ Rect::new(0, 0, TEXTURE_SIZE, TEXTURE_SIZE),
|
|
|
+ )
|
|
|
+ .expect("Couldn't copy texture in to window");
|
|
|
+ // We update window's display
|
|
|
+ canvas.present();
|
|
|
|
|
|
- ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
|
|
|
+ // We sleep enough to get ~60 fps. If we don't call this,
|
|
|
+ // the program will take 100% of a CPU time.
|
|
|
+ thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
|
|
|
}
|
|
|
}
|