diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..c4d6b0d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,329 @@ +[root] +name = "rust-2048" +version = "0.0.0" +dependencies = [ + "piston 0.1.1 (git+https://github.com/pistondevelopers/piston)", + "piston2d-graphics 0.0.46 (git+https://github.com/pistondevelopers/graphics)", + "piston2d-opengl_graphics 0.0.16 (git+https://github.com/pistondevelopers/opengl_graphics)", + "pistoncore-sdl2_window 0.0.13 (git+https://github.com/pistondevelopers/sdl2_window)", + "rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clock_ticks" +version = "0.0.5" +source = "git+https://github.com/tomaka/clock_ticks#462848731d99ed2f800e2e5a19e2d8ca3b11c90c" +dependencies = [ + "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "draw_state" +version = "0.0.7" +source = "git+https://github.com/gfx-rs/draw_state#44a0aed11abccbf970fc7efbe84b6482f0548248" +dependencies = [ + "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "enum_primitive" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "freetype-rs" +version = "0.0.9" +source = "git+https://github.com/PistonDevelopers/freetype-rs.git#686a4d7ff99eddfc64fbe7d2c3a19832ee564614" +dependencies = [ + "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "freetype-sys 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "freetype-sys" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gl" +version = "0.0.12" +source = "git+https://github.com/bjz/gl-rs#62b66a85e4c2c0d88fb916040bc462702c8e0346" +dependencies = [ + "gl_common 0.0.4 (git+https://github.com/bjz/gl-rs)", + "gl_generator 0.0.25 (git+https://github.com/bjz/gl-rs)", + "khronos_api 0.0.5 (git+https://github.com/bjz/gl-rs)", + "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gl_common" +version = "0.0.4" +source = "git+https://github.com/bjz/gl-rs#62b66a85e4c2c0d88fb916040bc462702c8e0346" +dependencies = [ + "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gl_generator" +version = "0.0.25" +source = "git+https://github.com/bjz/gl-rs#62b66a85e4c2c0d88fb916040bc462702c8e0346" +dependencies = [ + "khronos_api 0.0.5 (git+https://github.com/bjz/gl-rs)", + "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "xml-rs 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "image" +version = "0.3.9" +source = "git+https://github.com/pistondevelopers/image#75f9b791d6b030bc975ec737e9a2d78de39331af" +dependencies = [ + "byteorder 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "enum_primitive 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "interpolation" +version = "0.0.5" +source = "git+https://github.com/PistonDevelopers/interpolation#c0c9e970e42a48402514285a5608e4729cf83298" + +[[package]] +name = "khronos_api" +version = "0.0.5" +source = "git+https://github.com/bjz/gl-rs#62b66a85e4c2c0d88fb916040bc462702c8e0346" + +[[package]] +name = "khronos_api" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libz-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "piston" +version = "0.1.1" +source = "git+https://github.com/pistondevelopers/piston#e4b588cf22275acb230a4d6baace2567ea66391a" +dependencies = [ + "pistoncore-event 0.1.3 (git+https://github.com/pistondevelopers/event)", + "pistoncore-input 0.0.9 (git+https://github.com/pistondevelopers/input)", + "pistoncore-window 0.1.2 (git+https://github.com/pistondevelopers/window)", +] + +[[package]] +name = "piston-float" +version = "0.0.1" +source = "git+https://github.com/pistondevelopers/float#2c73a3e34c384c79e95b35c069d5a69dda3a0cc4" + +[[package]] +name = "piston-shaders_graphics2d" +version = "0.0.0" +source = "git+https://github.com/pistondevelopers/shaders#a2cbd6c63b5cb6852f2bef9e28e04301bca96efe" + +[[package]] +name = "piston-texture" +version = "0.0.1" +source = "git+https://github.com/pistondevelopers/texture#3cc4cddc3f8c51c36ea11dd2f63d70aa887f53fb" + +[[package]] +name = "piston-viewport" +version = "0.0.2" +source = "git+https://github.com/pistondevelopers/viewport#3819edeb0982d2552669e03ad9c0317e75340510" +dependencies = [ + "piston-float 0.0.1 (git+https://github.com/pistondevelopers/float)", +] + +[[package]] +name = "piston2d-graphics" +version = "0.0.46" +source = "git+https://github.com/pistondevelopers/graphics#e5885956fd49bafa968f85976b153b341a473389" +dependencies = [ + "draw_state 0.0.7 (git+https://github.com/gfx-rs/draw_state)", + "interpolation 0.0.5 (git+https://github.com/PistonDevelopers/interpolation)", + "piston-texture 0.0.1 (git+https://github.com/pistondevelopers/texture)", + "piston-viewport 0.0.2 (git+https://github.com/pistondevelopers/viewport)", + "read_color 0.0.2 (git+https://github.com/PistonDevelopers/read_color)", + "vecmath 0.0.22 (git+https://github.com/PistonDevelopers/vecmath)", +] + +[[package]] +name = "piston2d-opengl_graphics" +version = "0.0.16" +source = "git+https://github.com/pistondevelopers/opengl_graphics#c5d22694c53d58290b9e58e3411053d39250da89" +dependencies = [ + "freetype-rs 0.0.9 (git+https://github.com/PistonDevelopers/freetype-rs.git)", + "gl 0.0.12 (git+https://github.com/bjz/gl-rs)", + "image 0.3.9 (git+https://github.com/pistondevelopers/image)", + "khronos_api 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "piston-shaders_graphics2d 0.0.0 (git+https://github.com/pistondevelopers/shaders)", + "piston-texture 0.0.1 (git+https://github.com/pistondevelopers/texture)", + "piston2d-graphics 0.0.46 (git+https://github.com/pistondevelopers/graphics)", + "shader_version 0.0.6 (git+https://github.com/pistondevelopers/shader_version)", +] + +[[package]] +name = "pistoncore-event" +version = "0.1.3" +source = "git+https://github.com/pistondevelopers/event#c51e721f4b346fe7cc8a4c0e2658a70d257202ce" +dependencies = [ + "pistoncore-event_loop 0.1.5 (git+https://github.com/PistonDevelopers/event_loop)", + "pistoncore-input 0.0.9 (git+https://github.com/pistondevelopers/input)", + "pistoncore-window 0.1.2 (git+https://github.com/pistondevelopers/window)", +] + +[[package]] +name = "pistoncore-event_loop" +version = "0.1.5" +source = "git+https://github.com/PistonDevelopers/event_loop#d7541e44e33016b0584579e800879120cf982639" +dependencies = [ + "clock_ticks 0.0.5 (git+https://github.com/tomaka/clock_ticks)", + "piston-viewport 0.0.2 (git+https://github.com/pistondevelopers/viewport)", + "pistoncore-window 0.1.2 (git+https://github.com/pistondevelopers/window)", +] + +[[package]] +name = "pistoncore-input" +version = "0.0.9" +source = "git+https://github.com/pistondevelopers/input#cb0615041f0dd1e4cd1cfc6d4e0e4bae0a575a8e" +dependencies = [ + "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pistoncore-sdl2_window" +version = "0.0.13" +source = "git+https://github.com/pistondevelopers/sdl2_window#d9dd95cadd5c8de09ddb163812761738b999b3f4" +dependencies = [ + "gl 0.0.12 (git+https://github.com/bjz/gl-rs)", + "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "piston 0.1.1 (git+https://github.com/pistondevelopers/piston)", + "sdl2 0.2.3 (git+https://github.com/AngryLawyer/rust-sdl2)", + "shader_version 0.0.6 (git+https://github.com/pistondevelopers/shader_version)", +] + +[[package]] +name = "pistoncore-window" +version = "0.1.2" +source = "git+https://github.com/pistondevelopers/window#73314c130ce0b8fc22e47fc636a4724b6e02a365" +dependencies = [ + "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "pistoncore-input 0.0.9 (git+https://github.com/pistondevelopers/input)", +] + +[[package]] +name = "pkg-config" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "read_color" +version = "0.0.2" +source = "git+https://github.com/PistonDevelopers/read_color#568723fb7d9a69833e1d5a5ec79ded8ce9562920" + +[[package]] +name = "rustc-serialize" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "sdl2" +version = "0.2.3" +source = "git+https://github.com/AngryLawyer/rust-sdl2#f270e9879cd91324a3adc7c0367971e7cda27b9c" +dependencies = [ + "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2-sys 0.2.2 (git+https://github.com/AngryLawyer/rust-sdl2)", +] + +[[package]] +name = "sdl2-sys" +version = "0.2.2" +source = "git+https://github.com/AngryLawyer/rust-sdl2#f270e9879cd91324a3adc7c0367971e7cda27b9c" +dependencies = [ + "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "shader_version" +version = "0.0.6" +source = "git+https://github.com/pistondevelopers/shader_version#14aa73be33b6d23d6b3cb27f94426545372df287" + +[[package]] +name = "vecmath" +version = "0.0.22" +source = "git+https://github.com/PistonDevelopers/vecmath#d6bb5cf609b51cae8f296945e179bd42a74c9a51" +dependencies = [ + "piston-float 0.0.1 (git+https://github.com/pistondevelopers/float)", +] + +[[package]] +name = "xml-rs" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + diff --git a/Cargo.toml b/Cargo.toml index 8dcf37c..e25007b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,10 @@ authors = ["coeuvre "] name = "rust-2048" path = "src/main.rs" +[dependencies] +rustc-serialize = "0.3" +rand = "0.3.7" + [dependencies.piston2d-graphics] git = "https://github.com/pistondevelopers/graphics" @@ -20,4 +24,3 @@ git = "https://github.com/pistondevelopers/opengl_graphics" [dependencies.pistoncore-sdl2_window] git = "https://github.com/pistondevelopers/sdl2_window" - diff --git a/README.md b/README.md index c3128de..c3aafc3 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,10 @@ Use arrow key to move tiles. To build this repository, you need [Cargo](https://github.com/rust-lang/cargo). +You also need the _Freetype 6_ and _SDL2_ libs. +Look at [Piston-Tutorials - Installing Dependencies](https://github.com/PistonDevelopers/Piston-Tutorials/tree/master/getting-started#installing-dependencies) and [Rust-SDL2 - Requirements](https://github.com/AngryLawyer/rust-sdl2#sdl20--development-libraries) how to install them. + + Clone this repository ``` git clone https://github.com/Coeuvre/rust-2048.git @@ -23,13 +27,7 @@ Use Cargo to build cargo build ``` -Move binary to `bin` directory -``` -mv ./target/rust-2048 ./bin -``` - Play! ``` -./bin/rust-2048 +cargo run ``` - diff --git a/src/app.rs b/src/app.rs index cdeb2fb..2ecaca1 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,15 +1,18 @@ +use std::path::{Path, PathBuf}; + use graphics::*; -use piston::*; -use piston::events::{ RenderArgs, UpdateArgs }; +use piston::input::Button; +use piston::event::*; use board::Board; use number_renderer::NumberRenderer; use settings::Settings; use opengl_graphics::{ - Gl, + GlGraphics, Texture, }; + pub struct App<'a> { board: Board<'a>, number_renderer: Option, @@ -18,11 +21,11 @@ pub struct App<'a> { logo: Option, comment1: Option, comment2: Option, - window_background_color: [f32; ..4], - - gl: Gl, + window_background_color: [f32; 4], } +fn rgb2rgba(c: [f32; 3]) -> [f32; 4] { [c[0], c[1], c[2], 1.0] } + impl<'a> App<'a> { pub fn new(settings: &'a Settings) -> App<'a> { App { @@ -34,96 +37,103 @@ impl<'a> App<'a> { comment1: None, comment2: None, window_background_color: [1.0, 1.0, 1.0, 1.0], - - gl: Gl::new(), } } - fn render_ui(&mut self, c: &Context) { - // logo - c.trans(self.settings.board_padding, self.settings.board_padding) - .image(self.logo.get_ref()) - .rgb(self.settings.text_dark_color[0], - self.settings.text_dark_color[1], - self.settings.text_dark_color[2]) - .draw(&mut self.gl); + fn render_ui(&self, c: &Context, gl: &mut GlGraphics) { + use graphics::*; - c.view() - .rect(self.settings.best_rect[0], - self.settings.best_rect[1], - self.settings.best_rect[2], - self.settings.best_rect[3]) - .rgba(self.settings.label_color[0], - self.settings.label_color[1], - self.settings.label_color[2], - 1.0) - .draw(&mut self.gl); + Image::new_colored(rgb2rgba(self.settings.text_dark_color)) + .draw(self.logo.iter().next().unwrap(), + default_draw_state(), + c.trans(self.settings.board_padding,self.settings.board_padding).transform, + gl); + + Rectangle::new(rgb2rgba(self.settings.label_color)) + .draw(self.settings.best_rect, + default_draw_state(), + c.transform, + gl); let comment1_offset_y = self.settings.comment1_offset_y; let comment1 = self.comment1.as_ref().unwrap(); - App::render_comment(self.settings, comment1, comment1_offset_y, c, &mut self.gl); + App::render_comment(self.settings, comment1, comment1_offset_y, c, gl); let comment2_offset_y = self.settings.comment2_offset_y; let comment2 = self.comment2.as_ref().unwrap(); - App::render_comment(self.settings, comment2, comment2_offset_y, c, &mut self.gl); + App::render_comment(self.settings, comment2, comment2_offset_y, c, gl); } - fn render_comment(settings: &Settings, comment: &Texture, y: f64, c: &Context, gl: &mut Gl) { + fn render_comment(settings: &Settings, comment: &Texture, y: f64, c: &Context, gl: &mut GlGraphics) { let (width, height) = comment.get_size(); let w = settings.window_size[0] as f64 - 2.0 * settings.board_padding; let h = height as f64 * w / width as f64; - c.rect(settings.board_padding, y, w, h) - .image(comment) - .rgb(settings.text_dark_color[0], - settings.text_dark_color[1], - settings.text_dark_color[2]) - .draw(gl); + + Image::new_colored(rgb2rgba(settings.text_dark_color)) + .rect([settings.board_padding, y, w, h]) + .draw( comment, + default_draw_state(), + c.transform, + gl); } pub fn load(&mut self) { - let asset_store = Path::new(self.settings.asset_folder.as_slice()); - self.number_renderer = Some(NumberRenderer::new(&asset_store)); + let mut asset_root = PathBuf::new(); + asset_root.push(Path::new(&self.settings.asset_folder)); - self.logo = Some(Texture::from_path(&asset_store.path("logo.png").unwrap()).unwrap()); - self.comment1 = Some(Texture::from_path(&asset_store.path("comment1.png").unwrap()).unwrap()); - self.comment2 = Some(Texture::from_path(&asset_store.path("comment2.png").unwrap()).unwrap()); + let mut logo_path = asset_root.clone(); + logo_path.push(Path::new("logo.png")); + let mut comment1_path = asset_root.clone(); + comment1_path.push(Path::new("comment1.png")); + let mut comment2_path = asset_root.clone(); + comment2_path.push(Path::new("comment2.png")); + + self.number_renderer = Some(NumberRenderer::new()); + self.logo = Some(Texture::from_path(&logo_path).unwrap()); + self.comment1 = Some(Texture::from_path(&comment1_path).unwrap()); + self.comment2 = Some(Texture::from_path(&comment2_path).unwrap()); } - pub fn render(&mut self, args: &RenderArgs) { - self.gl.viewport(0, 0, args.width as i32, args.height as i32); - let ref c = Context::abs(args.width as f64, args.height as f64); - c.color(self.window_background_color).draw(&mut self.gl); + pub fn render(&mut self, args: &RenderArgs, gl: &mut GlGraphics) { + + let ref c = Context::abs(args.width as f64, args.height as f64); + + let w_bg_col = self.window_background_color; + let ref nr = self.number_renderer; + + gl.draw(args.viewport(), |_, gl| { + clear(w_bg_col, gl); + self.render_ui(c, gl); + self.board.render(nr.iter().next().unwrap(), c, gl); + }); - self.render_ui(c); - self.board.render(self.number_renderer.get_ref(), c, &mut self.gl); } pub fn update(&mut self, args: &UpdateArgs) { self.board.update(args.dt); } - pub fn key_press(&mut self, args: &KeyPressArgs) { + pub fn key_press(&mut self, args: &Button) { use piston::input::Button::Keyboard; use piston::input::keyboard::Key; - if args.key == Keyboard(Key::Left) { + if *args == Keyboard(Key::Left) { self.board.merge_from_right_to_left(); } - - if args.key == Keyboard(Key::Right) { + + if *args == Keyboard(Key::Right) { self.board.merge_from_left_to_right(); } - - if args.key == Keyboard(Key::Up) { + + if *args == Keyboard(Key::Up) { self.board.merge_from_bottom_to_top(); } - - if args.key == Keyboard(Key::Down) { + + if *args == Keyboard(Key::Down) { self.board.merge_from_top_to_bottom(); } - - if args.key == Keyboard(Key::Space) { + + if *args == Keyboard(Key::Space) { self.board = Board::new(self.settings); } } } - diff --git a/src/board.rs b/src/board.rs index 8af8f20..07b929f 100644 --- a/src/board.rs +++ b/src/board.rs @@ -1,11 +1,10 @@ -use std::iter::range_step; use std::collections::HashSet; -use std::rand::random; +// use std::iter::range_step_inclusive; +use rand::random; use graphics::*; -use piston::*; use opengl_graphics::{ - Gl, + GlGraphics, }; use number_renderer::NumberRenderer; use settings::Settings; @@ -14,10 +13,11 @@ use tile::{ TileState, }; +fn rgb2rgba(c: [f32; 3]) -> [f32; 4] { [c[0], c[1], c[2], 1.0] } + pub struct Board<'a> { tiles: Vec>, - score: int, - + score: i32, settings: &'a Settings, } @@ -34,13 +34,13 @@ impl<'a> Board<'a> { } pub fn generate_tile(&mut self) { - if self.tiles.len() == (self.settings.tile_width * self.settings.tile_height) as uint { + if self.tiles.len() == (self.settings.tile_width * self.settings.tile_height) as usize { return; } loop { - let x = (random::() % self.settings.tile_width as uint) as int; - let y = (random::() % self.settings.tile_height as uint) as int; + let x = (random::() % self.settings.tile_width as u32) as i32; + let y = (random::() % self.settings.tile_height as u32) as i32; if self.get_tile(x, y).is_none() { self.tiles.push(Tile::new(self.settings, 2, x, y)); break; @@ -49,26 +49,26 @@ impl<'a> Board<'a> { } pub fn update(&mut self, dt: f64) { - for tile in self.tiles.mut_iter() { + for tile in self.tiles.iter_mut() { tile.update(dt); } - + if self.is_locking() { return; } let mut score_to_added = 0; - let mut tiles_need_removed = HashSet::::new(); + let mut tiles_need_removed = HashSet::::new(); let mut tiles_need_added = Vec::::new(); - for i in range(0, self.tiles.len()) { + for i in 0..self.tiles.len() { let tile1 = &self.tiles[i]; if tile1.status != TileState::TileStatic { continue; } - for j in range(i + 1, self.tiles.len()) { + for j in i+1..self.tiles.len() { let tile2 = &self.tiles[j]; if tile2.status != TileState::TileStatic - || tile1.tile_x != tile2.tile_x - || tile1.tile_y != tile2.tile_y { + || tile1.tile_x != tile2.tile_x + || tile1.tile_y != tile2.tile_y { continue; } @@ -82,23 +82,27 @@ impl<'a> Board<'a> { if tiles_need_removed.len() > 0 { let mut tiles = Vec::::new(); - for i in range(0, self.tiles.len()) { + for i in 0..self.tiles.len() { if !tiles_need_removed.contains(&i) { - tiles.push(self.tiles[i]); + tiles.push(self.tiles[i].clone()); } } - self.tiles = tiles.append(tiles_need_added.as_slice()); + // better but unstable: tiles.append(&mut tiles_need_added); + while let Some(tile_to_add) = tiles_need_added.pop() { + tiles.push(tile_to_add); + } + self.tiles = tiles; self.add_score(score_to_added); } } - pub fn render(&mut self, number_renderer: &NumberRenderer, c: &Context, gl: &mut Gl) { + pub fn render(&self, number_renderer: &NumberRenderer, c: &Context, gl: &mut GlGraphics) { number_renderer.render( - self.score as u32, - self.settings.best_rect[0] + self.settings.best_rect[2] / 2.0, - self.settings.best_rect[1] + self.settings.best_rect[3] / 2.0, - self.settings.best_rect[2], - self.settings.text_light_color, c, gl); + self.score as u32, + self.settings.best_rect[0] + self.settings.best_rect[2] / 2.0, + self.settings.best_rect[1] + self.settings.best_rect[3] / 2.0, + self.settings.best_rect[2], + self.settings.text_light_color, c, gl); self.render_board(c, gl); self.render_tiles(number_renderer, c, gl); @@ -114,22 +118,30 @@ impl<'a> Board<'a> { self.merge_col(height - 1, -1, -1); } - fn merge_col(&mut self, y_start: int, y_end: int, y_step: int) { + fn merge_col(&mut self, y_start: i32, y_end: i32, y_step: i32) { if self.is_locking() { + println!("return"); return; } - let mut need_generate = false; + let mut steps: Vec = Vec::with_capacity(self.settings.tile_height as usize); + let mut next_step = y_start; + if y_step < 0 { + while next_step > y_end { steps.push(next_step); next_step += y_step } + } else { + while next_step < y_end { steps.push(next_step); next_step += y_step } + }; loop { // move all tiles to right place - for col in range(0, self.settings.tile_width) { - for row in range_step(y_start, y_end, y_step) { + for col in 0 .. self.settings.tile_width { + // TODO: replace steps by (y_start .. y_end).step_by(y_step) if step_by becomes stable + for row in steps.to_vec() { match self.get_mut_tile(col, row) { None => { match self.get_mut_next_tile(col, row, 0, y_step) { Some(ref mut tile) => { println!("move ({}, {}) to ({}, {})", - tile.tile_x, tile.tile_y, col, row); + tile.tile_x, tile.tile_y, col, row); need_generate = true; tile.start_moving(col, row); }, @@ -142,19 +154,19 @@ impl<'a> Board<'a> { } let mut did_merged = false; - for col in range(0, self.settings.tile_width) { + for col in 0..self.settings.tile_width { let mut found = false; let mut sx = 0; let mut sy = 0; let mut dx = 0; let mut dy = 0; - for row in range_step(y_start, y_end, y_step) { + for row in steps.to_vec() { match self.get_tile(col, row) { Some(ref d_tile) => { match self.get_next_tile(col, row, 0, y_step) { Some(ref s_tile) if d_tile.score == s_tile.score - && self.get_tile_count(d_tile.tile_x, d_tile.tile_y) == 1 => { + && self.get_tile_count(d_tile.tile_x, d_tile.tile_y) == 1 => { found = true; dx = d_tile.tile_x; dy = d_tile.tile_y; @@ -173,8 +185,7 @@ impl<'a> Board<'a> { if found { need_generate = true; did_merged = true; - let mut tile = self.get_mut_tile(sx, sy); - let tile = tile.get_mut_ref(); + let tile = self.get_mut_tile(sx, sy).unwrap(); tile.start_moving(dx, dy); println!("merge ({}, {}) to ({}, {})", sx, sy, dx, dy); } @@ -199,16 +210,24 @@ impl<'a> Board<'a> { self.merge_row(0, width, 1); } - fn merge_row(&mut self, x_start: int, x_end: int, x_step: int) { + fn merge_row(&mut self, x_start: i32, x_end: i32, x_step: i32) { if self.is_locking() { return; } let mut need_generate = false; + let mut steps: Vec = Vec::with_capacity(self.settings.tile_width as usize); + let mut next_step = x_start; + if x_step < 0 { + while next_step > x_end { steps.push(next_step); next_step += x_step } + } else { + while next_step < x_end { steps.push(next_step); next_step += x_step } + }; loop { // move all tiles to right place - for row in range(0, self.settings.tile_height) { - for col in range_step(x_start, x_end, x_step) { + for row in 0..self.settings.tile_height { + for col in steps.to_vec() { + match self.get_mut_tile(col, row) { None => { match self.get_mut_next_tile(col, row, x_step, 0) { @@ -227,19 +246,19 @@ impl<'a> Board<'a> { // merge let mut did_merged = false; - for row in range(0, self.settings.tile_height) { + for row in 0..self.settings.tile_height { let mut found = false; let mut sx = 0; let mut sy = 0; let mut dx = 0; let mut dy = 0; - for col in range_step(x_start, x_end, x_step) { + for col in steps.to_vec() { match self.get_tile(col, row) { Some(ref d_tile) => { match self.get_next_tile(col, row, x_step, 0) { Some(ref s_tile) if d_tile.score == s_tile.score - && self.get_tile_count(d_tile.tile_x, d_tile.tile_y) == 1 => { + && self.get_tile_count(d_tile.tile_x, d_tile.tile_y) == 1 => { found = true; dx = d_tile.tile_x; dy = d_tile.tile_y; @@ -258,8 +277,7 @@ impl<'a> Board<'a> { if found { need_generate = true; did_merged = true; - let mut tile = self.get_mut_tile(sx, sy); - let tile = tile.get_mut_ref(); + let tile = self.get_mut_tile(sx, sy).unwrap(); tile.start_moving(dx, dy); println!("merge ({}, {}) to ({}, {})", sx, sy, dx, dy); } @@ -285,11 +303,11 @@ impl<'a> Board<'a> { } /// Returns next tile right besides (x, y) - fn get_next_tile<'b>(&'b self, x: int, y: int, step_x: int, step_y: int) -> Option<&'b Tile<'a>> { + fn get_next_tile<'b>(&'b self, x: i32, y: i32, step_x: i32, step_y: i32) -> Option<&'b Tile<'a>> { let mut x = x + step_x; let mut y = y + step_y; while x >= 0 && x < self.settings.tile_width - && y >= 0 && y < self.settings.tile_height { + && y >= 0 && y < self.settings.tile_height { let tile = self.get_tile(x, y); if tile.is_some() { return tile; @@ -300,12 +318,12 @@ impl<'a> Board<'a> { None } - fn get_mut_next_tile<'b>(&'b mut self, x: int, y: int, step_x: int, step_y: int) -> Option<&'b mut Tile<'a>> { + fn get_mut_next_tile<'b>(&'b mut self, x: i32, y: i32, step_x: i32, step_y: i32) -> Option<&'b mut Tile<'a>> { let mut x = x + step_x; let mut y = y + step_y; let mut found = false; while x >= 0 && x < self.settings.tile_width - && y >= 0 && y < self.settings.tile_height { + && y >= 0 && y < self.settings.tile_height { let tile = self.get_tile(x, y); if tile.is_some() { found = true; @@ -316,13 +334,13 @@ impl<'a> Board<'a> { } if found { - self.get_mut_tile(x, y) + self.get_mut_tile(x, y) } else { None } } - fn get_tile<'b>(&'b self, x: int, y: int) -> Option<&'b Tile<'a>> { + fn get_tile<'b>(&'b self, x: i32, y: i32) -> Option<&'b Tile<'a>> { for tile in self.tiles.iter() { if tile.tile_x == x && tile.tile_y == y { return Some(tile); @@ -331,8 +349,8 @@ impl<'a> Board<'a> { None } - fn get_mut_tile<'b>(&'b mut self, x: int, y: int) -> Option<&'b mut Tile<'a>> { - for tile in self.tiles.mut_iter() { + fn get_mut_tile<'b>(&'b mut self, x: i32, y: i32) -> Option<&'b mut Tile<'a>> { + for tile in self.tiles.iter_mut() { if tile.tile_x == x && tile.tile_y == y { return Some(tile); } @@ -340,7 +358,7 @@ impl<'a> Board<'a> { None } - fn get_tile_count(&self, x: int, y: int) -> int { + fn get_tile_count(&self, x: i32, y: i32) -> i32 { let mut count = 0; for tile in self.tiles.iter() { if tile.tile_x == x && tile.tile_y == y { @@ -350,29 +368,25 @@ impl<'a> Board<'a> { count } - fn render_board(&self, c: &Context, gl: &mut Gl) { - c.view() - .rect(self.settings.board_padding, - self.settings.board_padding + self.settings.board_offset_y, - self.settings.board_size[0], - self.settings.board_size[1]) - .rgba(self.settings.tile_background_color[0], - self.settings.tile_background_color[1], - self.settings.tile_background_color[2], - 1.0) - .draw(gl); - + fn render_board(&self, c: &Context, gl: &mut GlGraphics) { + Rectangle::new(rgb2rgba(self.settings.label_color)) + .draw([self.settings.board_padding, + self.settings.board_padding + self.settings.board_offset_y, + self.settings.board_size[0], + self.settings.board_size[1]], + default_draw_state(), + c.transform, + gl); + let mut x = self.settings.board_padding + self.settings.tile_padding; let mut y = self.settings.board_padding + self.settings.board_offset_y + self.settings.tile_padding; - for _ in range(0, self.settings.tile_height) { - for _ in range(0, self.settings.tile_width) { - c.view() - .rect(x, y, self.settings.tile_size, self.settings.tile_size) - .rgba(self.settings.tiles_colors[0][0], - self.settings.tiles_colors[0][1], - self.settings.tiles_colors[0][2], - 1.0) - .draw(gl); + for _ in 0..self.settings.tile_height { + for _ in 0..self.settings.tile_width { + Rectangle::new(rgb2rgba(self.settings.tiles_colors[0])) + .draw([x, y, self.settings.tile_size, self.settings.tile_size], + default_draw_state(), + c.transform, + gl); x += self.settings.tile_padding + self.settings.tile_size; } @@ -381,15 +395,14 @@ impl<'a> Board<'a> { } } - fn render_tiles(&self, number_renderer: &NumberRenderer, c: &Context, gl: &mut Gl) { + fn render_tiles(&self, number_renderer: &NumberRenderer, c: &Context, gl: &mut GlGraphics) { for tile in self.tiles.iter() { tile.render(number_renderer, c, gl); } } - fn add_score(&mut self, score: int) { + fn add_score(&mut self, score: i32) { self.score += score; println!("Score: {}", self.score); } } - diff --git a/src/main.rs b/src/main.rs index 58b5043..cea4115 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,15 @@ - -#![feature(globs)] - -extern crate serialize; +extern crate rustc_serialize; +extern crate rand; extern crate graphics; extern crate piston; extern crate opengl_graphics; extern crate sdl2_window; -use piston::*; +use piston::event::*; +use piston::window::{WindowSettings, Size}; use sdl2_window::Sdl2Window; +use opengl_graphics::{GlGraphics,OpenGL}; mod app; mod board; @@ -20,13 +20,12 @@ mod tile; fn main() { let settings = settings::Settings::load(); - let mut window = Sdl2Window::new( - Sdl2Window { - title: "Rust-2048".to_string(), - size: settings.window_size, - fullscreen: false, - exit_on_esc: true, - } + let window = Sdl2Window::new( + OpenGL::_3_2, + WindowSettings::new( + "Rust-2048".to_string(), + Size { width: settings.window_size[0], height: settings.window_size[1] }) + .exit_on_esc(true) ); let mut app = app::App::new(&settings); @@ -39,26 +38,27 @@ fn main() { max_frames_per_second: 60, }; */ + let mut gl = GlGraphics::new(OpenGL::_3_2); - for e in piston::events(&window) { + for e in window.events() { use piston::event::{ RenderEvent, PressEvent }; - - if let Some(args) = e.render_args() { - app.render(args); + if let Some(ref args) = e.render_args() { + app.render(args, &mut gl); } - if let Some(args) = e.update_args() { - app.update(args); + if let Some(ref args) = e.update_args() { + // TODO: only update if necessary + // println!("update"); + app.update(args); } - - if let Some(args) = e.press_args() { + if let Some(ref args) = e.press_args() { app.key_press(args); } - } +} /* for e in GameIterator::new(&mut window, &game_iter_settings) { - + match e { Render(ref args) => { app.render(args); @@ -74,4 +74,3 @@ fn main() { } */ } - diff --git a/src/number_renderer.rs b/src/number_renderer.rs index f0b6a5c..9057446 100644 --- a/src/number_renderer.rs +++ b/src/number_renderer.rs @@ -1,7 +1,8 @@ +use std::path::Path; use graphics::*; use opengl_graphics::{ - Gl, + GlGraphics, Texture, }; @@ -15,12 +16,12 @@ pub struct NumberRenderer { impl NumberRenderer { pub fn new() -> NumberRenderer { NumberRenderer { - image: Texture::from_path(Path::new("digits.png")).unwrap(), + image: Texture::from_path(Path::new("bin/assets/digits.png")).unwrap(), } } pub fn render(&self, number: u32, center_x: f64, center_y: f64, max_width: f64, - color: [f32; ..3], c: &Context, gl: &mut Gl) { + color: [f32; 3], c: &Context, gl: &mut GlGraphics) { let digits = number_to_digits(number); let total_width = DIGITS_WIDTH * digits.len() as f64; let total_width = if total_width > max_width { @@ -34,11 +35,13 @@ impl NumberRenderer { let y = center_y - height / 2.0; for digit in digits.iter() { - c.rect(x, y, width, height) - .image(&self.image) - .src_rect((*digit * DIGITS_WIDTH as u32) as i32, 0, DIGITS_WIDTH as i32, DIGITS_HEIGHT as i32) - .rgba(color[0], color[1], color[2], 1.0) - .draw(gl); + Image::new_colored([color[0], color[1], color[2], 1.0]) + .src_rect([(*digit * DIGITS_WIDTH as u32) as i32, 0, DIGITS_WIDTH as i32, DIGITS_HEIGHT as i32]) + .rect([x, y, width, height]) + .draw(&self.image, + default_draw_state(), + c.transform, + gl); x += width; } } @@ -58,4 +61,3 @@ fn number_to_digits(number: u32) -> Vec { } digits } - diff --git a/src/settings.rs b/src/settings.rs index b52057b..0f400ea 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,8 +1,9 @@ -use std::os::self_exe_path; -use std::old_io::{BufferedWriter, BufferedReader}; -use std::fs::File; -use serialize::{ +use std::env::current_exe; +use std::io::{BufWriter, BufReader, Write}; +use std::fs::{File}; +use std::path::Path; +use rustc_serialize::{ json, Encodable, Decodable, @@ -12,29 +13,29 @@ static SETTING_FILENAME: &'static str = "settings.json"; pub struct Settings { pub asset_folder: String, - pub window_size: [u32; ..2], - pub window_background_color: [f32; ..3], + pub window_size: [u32; 2], + pub window_background_color: [f32; 3], pub comment1_offset_y: f64, pub comment2_offset_y: f64, pub board_padding: f64, - pub board_size: [f64; ..2], + pub board_size: [f64; 2], pub board_offset_y: f64, - pub tile_width: int, - pub tile_height: int, + pub tile_width: i32, + pub tile_height: i32, pub tile_size: f64, pub tile_padding: f64, - pub tile_background_color: [f32; ..3], - pub tiles_colors: Vec<[f32; ..3]>, - pub tile_unknow_color: [f32; ..3], + pub tile_background_color: [f32; 3], + pub tiles_colors: Vec<[f32; 3]>, + pub tile_unknow_color: [f32; 3], pub tile_move_time: f64, pub tile_new_time: f64, pub tile_combine_time: f64, - pub best_rect: [f64; ..4], - pub score_rect: [f64; ..4], - pub label_color: [f32; ..3], - pub button_color: [f32; ..3], - pub text_dark_color: [f32; ..3], - pub text_light_color: [f32; ..3], + pub best_rect: [f64; 4], + pub score_rect: [f64; 4], + pub label_color: [f32; 3], + pub button_color: [f32; 3], + pub text_dark_color: [f32; 3], + pub text_light_color: [f32; 3], } impl Settings { @@ -49,7 +50,7 @@ impl Settings { ]; - let mut tiles_colors = Vec::<[f32; ..3]>::new(); + let mut tiles_colors = Vec::<[f32; 3]>::new(); for color in s.tiles_colors.iter() { tiles_colors.push([ color[0] / 255.0, @@ -127,7 +128,7 @@ impl Settings { } } -#[derive(Encodable, Decodable)] +#[derive(RustcEncodable, RustcDecodable)] struct SettingsInJson { asset_folder: String, @@ -140,8 +141,8 @@ struct SettingsInJson { board_padding: f64, board_offset_y: f64, - tile_width: int, - tile_height: int, + tile_width: i32, + tile_height: i32, tile_size: f64, tile_padding: f64, tile_background_color: Vec, @@ -185,7 +186,7 @@ impl SettingsInJson { // 512 color tiles_colors.push(vec![237.0, 200.0, 80.0]); SettingsInJson { - asset_folder: "assets".to_string(), + asset_folder: "bin/assets".to_string(), window_background_color: vec![255.0, 248.0, 239.0], comment1_offset_y: 72.0, comment2_offset_y: 100.0, @@ -211,37 +212,62 @@ impl SettingsInJson { } pub fn load() -> SettingsInJson { - let exe_path = self_exe_path(); - if exe_path.is_none() { + let exe_path = current_exe(); + if exe_path.is_err() { return SettingsInJson::default_settings(); } - let exe_path = exe_path.unwrap(); + let mut exe_path = exe_path.unwrap(); + exe_path.pop(); let path = exe_path.join(Path::new(SETTING_FILENAME)); - if !path.exists() || !path.is_file() { +// FIXME: use this if possible (.exists() is unstable in Rust 1.0.0) +/* if !path.as_path().exists() || !path.is_file() { + println!("Configuration file not found. Generating a default one."); let default = SettingsInJson::default_settings(); default.save(); return default; } let file = File::open(&path).unwrap(); - let mut reader = BufferedReader::new(file); - let mut decoder = json::Decoder::new(json::from_reader(&mut reader).unwrap()); + let mut reader = BufReader::new(file); +*/ + let file = File::open(&path); + match file { + Err(e) => { + println!("Configuration file can't be open ({}). Try to generate a default one.", e); + let default = SettingsInJson::default_settings(); + default.save(); + return default; + }, + _ => {} + } + let mut reader = BufReader::new(file.unwrap()); +// End FIXME + let mut decoder = json::Decoder::new(json::Json::from_reader(&mut reader).unwrap()); Decodable::decode(&mut decoder).unwrap() } pub fn save(&self) { - let exe_path = self_exe_path(); - if exe_path.is_none() { + let exe_path = current_exe(); + if exe_path.is_err() { println!("WARNING: Failed to save settings: can't find exe path."); return; } - let path = exe_path.unwrap().join(Path::new(SETTING_FILENAME)); - let file = File::create(&path).unwrap(); - let mut writer = BufferedWriter::new(file); - let mut encoder = json::Encoder::new(&mut writer); - match self.encode(&mut encoder) { - Ok(()) => (), - Err(e) => { println!("WARNING: Failed to save settings: {}", e); }, + let path = exe_path.unwrap(); + let file = File::create(&path.with_file_name(SETTING_FILENAME)).unwrap(); + let mut writer = BufWriter::new(file); + + match json::encode(self) { + Ok(encoded) => { + if let Err(e) = writer.write(encoded.as_bytes()) { + println!("WARNING: Failed to save settings: {}", e); + } + }, Err(e) => { + println!("WARNING: Failed to save settings: {}", e); + } } + + // match self.encode(&mut encoder) { + // Ok(()) => (), + // Err(e) => { println!("WARNING: Failed to save settings: {}", e); }, + // } } } - diff --git a/src/tile.rs b/src/tile.rs index eb9d66d..6e2164b 100644 --- a/src/tile.rs +++ b/src/tile.rs @@ -1,7 +1,6 @@ use graphics::*; -use piston::*; -use opengl_graphics::Gl; +use opengl_graphics::GlGraphics; use number_renderer::NumberRenderer; use settings::Settings; @@ -9,7 +8,7 @@ use settings::Settings; pub enum TileState { TileStatic, /// (t, x, y, origin_x, origin_x) - TileMoving(f64, f64, f64, int, int), + TileMoving(f64, f64, f64, i32, i32), /// (t, size) TileNew(f64, f64), /// (t, size) @@ -18,16 +17,16 @@ pub enum TileState { #[derive(Clone)] pub struct Tile<'a> { - pub score: int, - pub tile_x: int, - pub tile_y: int, + pub score: i32, + pub tile_x: i32, + pub tile_y: i32, pub status: TileState, settings: &'a Settings, } impl<'a> Tile<'a> { - pub fn new(settings: &'a Settings, score: int, tile_x: int, tile_y: int) -> Tile<'a> { + pub fn new(settings: &'a Settings, score: i32, tile_x: i32, tile_y: i32) -> Tile<'a> { Tile { score: score, tile_x: tile_x, @@ -38,7 +37,7 @@ impl<'a> Tile<'a> { } } - pub fn new_combined(settings: &'a Settings, score: int, tile_x: int, tile_y: int) -> Tile<'a> { + pub fn new_combined(settings: &'a Settings, score: i32, tile_x: i32, tile_y: i32) -> Tile<'a> { Tile { score: score, tile_x: tile_x, @@ -49,13 +48,13 @@ impl<'a> Tile<'a> { } } - fn tile_to_pos(&self, tile_x: int, tile_y: int) -> (f64, f64) { + fn tile_to_pos(&self, tile_x: i32, tile_y: i32) -> (f64, f64) { let x = self.settings.board_padding + tile_x as f64 * self.settings.tile_size + (tile_x + 1) as f64 * self.settings.tile_padding; let y = self.settings.board_padding + self.settings.board_offset_y + tile_y as f64 * self.settings.tile_size + (tile_y + 1) as f64 * self.settings.tile_padding; (x, y) } - pub fn start_moving(&mut self, destination_tile_x: int, destination_tile_y: int) { + pub fn start_moving(&mut self, destination_tile_x: i32, destination_tile_y: i32) { match self.status { TileState::TileMoving(_, _, _, ox, oy) => { let (x, y) = self.tile_to_pos(ox, oy); @@ -104,7 +103,7 @@ impl<'a> Tile<'a> { } } - pub fn render(&self, number_renderer: &NumberRenderer, c: &Context, gl: &mut Gl) { + pub fn render(&self, number_renderer: &NumberRenderer, c: &Context, gl: &mut GlGraphics) { let mut pos = self.tile_to_pos(self.tile_x, self.tile_y); let mut size = (self.settings.tile_size, self.settings.tile_size); match self.status { @@ -122,11 +121,14 @@ impl<'a> Tile<'a> { let (x, y) = pos; let (w, h) = size; let color = self.get_color(); - c.view() - .rect_centered(x + self.settings.tile_size / 2.0, - y + self.settings.tile_size / 2.0, - w / 2.0, h / 2.0) - .rgba(color[0], color[1], color[2], 1.0).draw(gl); + + Rectangle::new([color[0], color[1], color[2], 1.0]) + .draw(rectangle::centered([x + self.settings.tile_size / 2.0, + y + self.settings.tile_size / 2., + w/2.0, h/2.0]), + default_draw_state(), + c.transform, + gl); let color = if self.score >= 8 { self.settings.text_light_color @@ -136,8 +138,8 @@ impl<'a> Tile<'a> { number_renderer.render(self.score as u32, x + self.settings.tile_size / 2.0, y + self.settings.tile_size / 2.0, self.settings.tile_size, color, c, gl); } - fn get_color(&self) -> [f32; ..3] { - let i = (self.score as f64).log2() as uint; + fn get_color(&self) -> [f32; 3] { + let i = (self.score as f64).log2() as usize; if i > 0 && i < self.settings.tiles_colors.len() { self.settings.tiles_colors[i] } else { @@ -145,4 +147,3 @@ impl<'a> Tile<'a> { } } } -