use ggez::event::{self, EventHandler, MouseButton}; use ggez::graphics::DrawParam; use ggez::graphics::Rect; use ggez::input::mouse; use ggez::mint::Point2; use ggez::{graphics, Context, ContextBuilder, GameResult}; mod board; mod picker; mod piece; use crate::board::*; use crate::picker::*; use crate::piece::*; const BACKGROUND: graphics::Color = graphics::Color::new(100. / 255., 61. / 255., 1. / 255., 1.0); fn main() { let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); let mut path = std::path::PathBuf::from(manifest_dir); path.push("resources"); let (mut ctx, event_loop) = ContextBuilder::new("pawn_example", "") .add_resource_path(path) .build() .expect("Could not create context"); let game = BoardGame::new(&mut ctx); event::run(ctx, event_loop, game); } struct BoardGame { board: Board, picker: Picker, has_resized: bool, hdpi_factor: f32, draggin: Option<(graphics::Image, Name, PColor, [f32; 2])>, } const START_BOARD: &str = r#" BR BN BB BQ BK BB BN BR BL BG BP BP BP BP BG BL N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N WL WG WP WP WP WP WG WL WR WN WB WQ WK WB WN WR "#; fn parse_to_piece(ctx: &mut Context, s: &str) -> BoardPiece { let mut chars = s.chars(); let first = chars.next().unwrap(); let pcolor = match first { 'B' => PColor::BLACK, 'W' => PColor::WHITE, _ => return None, }; let second = chars.next().unwrap(); let name = match second { 'R' => Name::ROOK, 'N' => Name::KNIGHT, 'B' => Name::BISHOP, 'Q' => Name::QUEEN, 'K' => Name::KING, 'P' => Name::PAWN, 'L' => Name::BLOCKER, 'G' => Name::GIRAFFE, _ => return None, }; Some(new_piece(ctx, name, pcolor)) } impl BoardGame { fn new(ctx: &mut Context) -> Self { let start_board = START_BOARD .split_whitespace() .map(|s| parse_to_piece(ctx, s)) .collect(); let mut grid = gridit::Grid::from(start_board, 8, 8); let hdpi_factor = graphics::window(&ctx).scale_factor() as f32; Self { board: Board::new(grid, (50.0, 50.0), 400.0), picker: Picker::new(ctx, Rect::new(550., 50., 200., 700.)), has_resized: true, hdpi_factor, draggin: None, } } fn resize_board(&mut self, ctx: &Context) { let hdpi_factor = graphics::window(ctx).scale_factor() as f32; let (x, y) = graphics::size(ctx); let size = if x >= y { y } else { x * 0.8 }; let padding = x / 16.; let draw_rect = Rect::new( padding, padding, size * hdpi_factor - (padding * 2.), size * hdpi_factor - (padding * 2.), ); self.board.set_rect(draw_rect); } fn resize_picker(&mut self, ctx: &Context) { let hdpi_factor = graphics::window(ctx).scale_factor() as f32; let (x, y) = graphics::size(ctx); let height = y; let width = x * 0.20; let padding = x / 16.; let draw_rect = Rect::new( (x - width) * hdpi_factor, padding, width * hdpi_factor - padding, height * hdpi_factor - (padding * 2.), ); self.picker.set_rect(draw_rect); } } impl EventHandler for BoardGame { fn update(&mut self, ctx: &mut Context) -> GameResult<()> { let mpoint = mouse::position(ctx); if self.draggin.is_some() { mouse::set_cursor_type(ctx, mouse::CursorIcon::Grabbing); } else if self.picker.on_dragable(mpoint) { mouse::set_cursor_type(ctx, mouse::CursorIcon::Grab); } else { mouse::set_cursor_type(ctx, mouse::CursorIcon::Default); } if self.board.contains_point(mpoint) { self.board.hover_field(mpoint); } else { self.board.unhover(); } Ok(()) } fn draw(&mut self, ctx: &mut Context) -> GameResult<()> { graphics::clear(ctx, BACKGROUND); let hdpi_factor = graphics::window(&ctx).scale_factor() as f32; if self.has_resized || self.hdpi_factor != hdpi_factor { self.hdpi_factor = hdpi_factor; let (x, y) = graphics::size(&ctx); let draw_rect = Rect::new(0.0, 0.0, x * hdpi_factor, y * hdpi_factor); graphics::set_screen_coordinates(ctx, draw_rect)?; self.resize_board(ctx); self.resize_picker(ctx); self.has_resized = false; } graphics::draw(ctx, &self.board, DrawParam::default())?; graphics::draw(ctx, &self.picker, DrawParam::default())?; if let Some(item) = &self.draggin { let mpos = mouse::position(ctx); let [sx, sy] = item.3; let img = &item.0; let mut ir = img.dimensions(); ir.scale(sx, sy); let img_center_w = ir.w / 2.; let dest: Point2 = [(mpos.x - img_center_w), (mpos.y - ir.h)].into(); graphics::draw(ctx, img, DrawParam::default().dest(dest).scale(item.3))?; } graphics::present(ctx) } fn resize_event(&mut self, _ctx: &mut Context, _width: f32, _height: f32) { self.has_resized = true; } fn mouse_button_up_event(&mut self, ctx: &mut Context, _button: MouseButton, x: f32, y: f32) { let mpoint = [x, y].into(); if self.board.contains_point(mpoint) && self.draggin.is_some() { let info = self.draggin.take(); let (_, name, pcolor, _) = info.unwrap(); self.board.set_field(mpoint, new_piece(ctx, name, pcolor)); } else if self.draggin.is_some() { self.draggin = None; } } fn mouse_button_down_event( &mut self, _ctx: &mut Context, _button: MouseButton, x: f32, y: f32, ) { let mpoint = [x, y].into(); if self.board.contains_point(mpoint) { self.board.select_field(mpoint); return; } if self.picker.contains_point(mpoint) { if self.picker.on_dragable(mpoint) { let piece_info = self.picker.get_item_at(mpoint); self.draggin = Some(piece_info); } } self.board.unselect_field(); } }