diff --git a/src/main.rs b/src/main.rs index 5e906b7..39f8bfa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,15 @@ +use ggez::input::mouse::{self, MouseButton}; use ggez::event::{self, EventHandler}; use ggez::graphics::{self, Color, DrawMode, Mesh, MeshBuilder}; use ggez::{Context, ContextBuilder, GameResult}; +use std::env; +use std::path; + +const START_X: f32 = 20.0; +const START_Y: f32 = 20.0; +const SIZE: f32 = 20.0; + struct Apr { row: i32, col: i32, @@ -9,14 +17,18 @@ struct Apr { grid: Mesh, should_update_grid: bool, // Your state here... - __TEST_state: usize + __TEST_state: usize, + + //These would go in a dedicated Actor struct in the real game. + __test_pawn_image: graphics::Image, + __test_pawn_x: f32, + __test_pawn_y: f32, + __test_pawn_held: bool, + __test_pawn_h_x: f32, + __test_pawn_h_y: f32, } fn make_grid(ctx: &mut Context, r: i32, c: i32, board: &[Vec]) -> GameResult { - let start_x: f32 = 20.0; - let start_y: f32 = 20.0; - let size: f32 = 4.0; //compile time constants for now - let mut builder = MeshBuilder::new(); for row in 0..r { @@ -24,10 +36,10 @@ fn make_grid(ctx: &mut Context, r: i32, c: i32, board: &[Vec]) -> GameResult builder.rectangle( DrawMode::fill(), graphics::Rect { - x: start_x + (size * col as f32), - y: start_y + (size * row as f32), - w: size, - h: size, + x: START_X + (SIZE * col as f32), + y: START_Y + (SIZE * row as f32), + w: SIZE, + h: SIZE, }, match board[row as usize][col as usize] { 0 => Color::WHITE, @@ -58,36 +70,83 @@ fn make_board(r: i32, c: i32) -> Vec> { } impl Apr { - pub fn new(_ctx: &mut Context, r: i32, c: i32) -> Apr { + pub fn new(_ctx: &mut Context, r: i32, c: i32) -> GameResult { // Load/create resources such as images here. let board = make_board(r, c); - Apr { + Ok(Apr { row: r, col: c, - grid: make_grid(_ctx, r, c, board.as_slice()).unwrap(), + grid: make_grid(_ctx, r, c, board.as_slice())?, board: board, should_update_grid: false, __TEST_state: 0, - } + + __test_pawn_image: graphics::Image::new(_ctx, "/pawn.png")?, + __test_pawn_x: 20.0, + __test_pawn_y: 20.0, + __test_pawn_held: false, + __test_pawn_h_x: 0.0, + __test_pawn_h_y: 0.0 + }) } - fn set_colour(&mut self, r : usize, c : usize, col : u8) -> GameResult<()> { + fn set_colour(&mut self, r: usize, c: usize, col: u8) -> GameResult<()> { self.board[r][c] = col; self.should_update_grid = true; Ok(()) } + + fn closest_square_coords(&self, x: f32, y: f32) -> (f32, f32) { + //First, normalise to within the grid. + let mut x = x; + x = x.max(START_X); + x = x.min(START_X + (SIZE * self.col as f32) - 1.0); + + let mut y = y; + y = y.max(START_Y); + y = y.min(START_Y + (SIZE * self.row as f32) - 1.0); + + //Then, snap to top left. + + x = (x / SIZE).trunc() * SIZE; + y = (y / SIZE).trunc() * SIZE; + + (x, y) + } } impl EventHandler for Apr { - fn update(&mut self, _ctx: &mut Context) -> GameResult<()> { - // Err(ggez::GameError::CustomError("You done messed up trying to play this game!".to_string())) - // Update code here... - for _x in 0..self.row*self.col { + fn update(&mut self, ctx: &mut Context) -> GameResult<()> { + for _x in 0..self.col { let c = self.__TEST_state % self.col as usize; let r = (self.__TEST_state / self.row as usize) % self.row as usize; self.set_colour(r, c, (self.board[r][c] + 1) % 8)?; self.__TEST_state += 1; } + + if self.__test_pawn_held { + if !mouse::button_pressed(ctx, MouseButton::Left) { // no long clicking and dragging + let (x, y) = self.closest_square_coords(self.__test_pawn_x, self.__test_pawn_y); + self.__test_pawn_x = x; + self.__test_pawn_y = y; + } else { + let posn = mouse::position(ctx); + self.__test_pawn_x = posn.x + self.__test_pawn_h_x; + self.__test_pawn_y = posn.y + self.__test_pawn_h_y; + } + } else { + if mouse::button_pressed(ctx, MouseButton::Left) { + let posn = mouse::position(ctx); + let posx = posn.x; + let posy = posn.y; + if posx >= self.__test_pawn_x && posx <= self.__test_pawn_x + 20.0 && posy >= self.__test_pawn_y && posy <= self.__test_pawn_y + 20.0 { //In real game don't hardcode size + self.__test_pawn_h_x = self.__test_pawn_x - posx; + self.__test_pawn_h_y = self.__test_pawn_y - posy; + self.__test_pawn_held = true; + } + } + } + Ok(()) } @@ -100,21 +159,31 @@ impl EventHandler for Apr { self.should_update_grid = false; } graphics::draw(ctx, &self.grid, drawparams)?; + graphics::draw(ctx, &self.__test_pawn_image, drawparams.dest([self.__test_pawn_x, self.__test_pawn_y]))?; // Draw code here... graphics::present(ctx) } } -fn main() { +fn main() -> GameResult<()> { + let mut cb = ContextBuilder::new("apruebo", "s1m7u and e-dt"); + + if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") { + let mut path = path::PathBuf::from(manifest_dir); + path.push("resources"); + println!("Adding path {:?}", path); + cb = cb.add_resource_path(path); + } + // Make a Context. - let (mut ctx, event_loop) = ContextBuilder::new("apruebo", "s1m7u and e-dt") + let (mut ctx, event_loop) = cb .build() .expect("aieee, could not create ggez context!"); // Create an instance of your event handler. // Usually, you should provide it with the Context object to // use when setting your game up. - let apr = Apr::new(&mut ctx, 128, 128); + let apr = Apr::new(&mut ctx, 8, 8)?; // Run! event::run(ctx, event_loop, apr);