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 BOARD_SQUARE_SIZE: f32 = 20.0; struct Apr { row: i32, col: i32, board: Vec>, grid: Mesh, should_update_grid: bool, // Your state here... __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 mut builder = MeshBuilder::new(); for row in 0..r { for col in 0..c { builder.rectangle( DrawMode::fill(), graphics::Rect { x: START_X + (BOARD_SQUARE_SIZE * col as f32), y: START_Y + (BOARD_SQUARE_SIZE * row as f32), w: BOARD_SQUARE_SIZE, h: BOARD_SQUARE_SIZE, }, match board[row as usize][col as usize] { 0 => Color::WHITE, 1 => Color::BLACK, 2 => Color::RED, 3 => Color::CYAN, 4 => Color::YELLOW, 5 => Color::GREEN, 6 => Color::BLUE, 7 => Color::MAGENTA, _ => Color::BLACK, } )?; } } builder.build(ctx) } fn make_board(r: i32, c: i32) -> Vec> { let mut init : Vec> = vec![vec![0u8; r as usize]; c as usize]; for row in 0..r as usize { for col in 0..c as usize { init[row][col] = (row + col) as u8 % 8; } } init } impl 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); Ok(Apr { row: r, col: c, 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<()> { 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 + (BOARD_SQUARE_SIZE * self.col as f32) - 1.0); let mut y = y; y = y.max(START_Y); y = y.min(START_Y + (BOARD_SQUARE_SIZE * self.row as f32) - 1.0); //Then, snap to top left. x = (x / BOARD_SQUARE_SIZE).trunc() * BOARD_SQUARE_SIZE; y = (y / BOARD_SQUARE_SIZE).trunc() * BOARD_SQUARE_SIZE; (x, y) } } impl EventHandler for Apr { 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; } let posn = mouse::position(ctx); if self.__test_pawn_held { if !mouse::button_pressed(ctx, MouseButton::Left) { // no long clicking and dragging let (x, y) = self.closest_square_coords(posn.x, posn.y); self.__test_pawn_x = x; self.__test_pawn_y = y; self.__test_pawn_held = false; } else { 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 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; } } } self.set_colour((self.__test_pawn_x - START_X) / BOARD_SQUARE_SIZE, (self.__test_pawn_y - START_Y) / BOARD_SQUARE_SIZE, 3); Ok(()) } fn draw(&mut self, ctx: &mut Context) -> GameResult<()> { graphics::clear(ctx, Color::new(0.5, 0.5, 0.5, 1.0)); let drawparams = graphics::DrawParam::new(); if self.should_update_grid { self.grid = make_grid(ctx, self.row, self.col, self.board.as_slice())?; 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() -> 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) = 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, 8, 8)?; // Run! event::run(ctx, event_loop, apr); }