This commit is contained in:
cool-mist
2026-01-26 20:00:50 +05:30
parent dc61d6d956
commit 280150b0b0
18 changed files with 779 additions and 325 deletions
+17 -8
View File
@@ -2,6 +2,8 @@ pub mod constants;
mod draw;
mod logic;
use std::collections::HashMap;
use crate::{resources::Resources, widgets::*};
use macroquad::prelude::*;
use sol_lib::generator::Puzzle;
@@ -15,30 +17,36 @@ pub struct Game {
window_width: f32,
puzzle: Puzzle,
id_text: IdTextInput,
id_text_btn: ButtonWidget,
reset_btn: ButtonWidget,
next_btn: ButtonWidget,
show_rules: bool,
rules_font_size: f32,
board: BoardWidget,
heading_rect: Rect,
heading_font_size: f32,
heading_text: String,
heading: LabelWidget,
show_rules: bool,
rules_text: String,
rules_btn_text: String,
rules_btn: ButtonWidget,
game_mode: GameMode,
easy_btn: ButtonWidget,
medium_btn: ButtonWidget,
hard_btn: ButtonWidget,
game_mode_btns: HashMap<GameMode, ButtonWidget>,
pieces_label: LabelWidget,
max_age_label: LabelWidget,
pieces_counter: CounterWidget,
max_age_counter: CounterWidget,
generate_btn: ButtonWidget,
}
#[derive(Default)]
pub struct GameSettings {
pub volume: f32,
pub max_moves_per_piece: u32,
pub debug: bool,
pub num_pieces: u32,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
@@ -46,6 +54,7 @@ pub enum GameMode {
Easy,
Medium,
Hard,
Custom,
}
impl Default for GameMode {
+10 -5
View File
@@ -6,7 +6,7 @@ pub const SCREEN_WIDTH_MIN: f32 = 200.0;
pub const SCREEN_WIDTH_MAX: f32 = 10000.0;
// How big the square should be relative to the screen size, between 0 and 1
pub const BOARD_SQUARE_WIDTH_MULTIPLIER: f32 = 0.15;
pub const BOARD_SQUARE_WIDTH_MULTIPLIER: f32 = 0.11;
pub const BOARD_SHADOW_MULTIPLIER: f32 = 0.1;
@@ -22,19 +22,24 @@ pub const BUTTON_HEIGHT_MULTIPLIER: f32 = 0.08;
pub const BUTTON_WIDTH_MULTIPLIER: f32 = 0.20;
// Gap between the bottom of the board and the first row of buttons
pub const BOTTOM_BUTTON_ROW_OFFSET_MULTIPLIER: f32 = 0.3;
pub const BOTTOM_ROW_OFFSET_MULTIPLIER: f32 = 0.3;
// Gap between the right of the board and the first row of buttons
pub const BOTTOM_RIGHT_ROW_OFFSET_MULTIPLIER: f32 = 0.3;
pub const RIGHT_COLUMN_OFFSET_MULTIPLIER: f32 = 0.3;
// Gap between the top of the board and the heading
pub const TOP_HEADING_OFFSET_MULTIPLIER: f32 = 0.5;
pub const HEADING_TEXT: &str = "Solitaire Chess";
pub const RESET_BUTTON_TEXT: &str = "R";
pub const NEXT_BUTTON_TEXT: &str = "N";
pub const RESET_BUTTON_TEXT: &str = "RESET";
pub const NEXT_BUTTON_TEXT: &str = "NEXT";
pub const RULES_BUTTON_TEXT: &str = "RULES";
pub const RULES_BUTTON_ALT_TEXT: &str = "CLOSE";
pub const EASY_BUTTON_TEXT: &str = "EASY";
pub const MEDIUM_BUTTON_TEXT: &str = "MEDIUM";
pub const HARD_BUTTON_TEXT: &str = "HARD";
pub const CUSTOM_BUTTON_TEXT: &str = "CUSTOM";
pub const GENERATE_BUTTON_TEXT: &str = "GENERATE";
pub const PIECES_LABEL_TEXT: &str = "Pieces";
pub const AGE_LABEL_TEXT: &str = " Age";
+173 -84
View File
@@ -1,53 +1,66 @@
use super::{Game, constants};
use crate::widgets::*;
use crate::{game::GameMode, widgets::*};
use macroquad::{math, prelude::*};
impl Game {
fn initialize_drawables(&mut self) {
fn initialize_drawables(&mut self, new_width: f32, new_height: f32) {
self.window_height = new_height;
self.window_width = new_width;
let min_dimension = f32::min(self.window_height, self.window_width);
let square_width = constants::BOARD_SQUARE_WIDTH_MULTIPLIER * min_dimension;
let num_squares = self.board.num_squares;
let board_width = square_width * num_squares as f32;
let board_x = (self.window_width - board_width) / 2.0;
let board_x = (self.window_width * 0.6 - board_width) / 2.0;
let board_y = (self.window_height - board_width) / 2.0;
let board_rect = Rect::new(board_x, board_y, board_width, board_width);
self.board.initialize_drawables(square_width, board_rect);
self.heading_font_size = constants::HEADING_FONT_SIZE_MULTIPLIER * min_dimension;
let f = self.heading_font_size.floor() as u16;
let dims = measure_text(
let heading_font_size = constants::HEADING_FONT_SIZE_MULTIPLIER * min_dimension;
let f = heading_font_size.floor() as u16;
let heading_text_dims = measure_text(
self.heading_text.as_str(),
Some(&self.resources.font()),
f,
1.0,
);
self.heading_rect = Rect::new(
board_x + (board_width - dims.width) / 2.0,
board_y - dims.height - constants::TOP_HEADING_OFFSET_MULTIPLIER * square_width,
dims.width,
dims.height,
let heading_rect = Rect::new(
(self.window_width - heading_text_dims.width) / 2.0,
board_y
- heading_text_dims.height
- constants::TOP_HEADING_OFFSET_MULTIPLIER * square_width,
heading_text_dims.width,
heading_text_dims.height,
);
self.heading
.initialize_drawables(heading_rect, heading_font_size, &self.resources);
// Buttons
let btn_h = constants::BUTTON_HEIGHT_MULTIPLIER * min_dimension;
let btn_w = board_width * constants::BUTTON_WIDTH_MULTIPLIER;
let btn_w_sq = btn_h;
let btn_w = constants::BUTTON_WIDTH_MULTIPLIER * board_width;
// Bottom row
let bottom_row_y =
board_width + board_y + constants::BOTTOM_BUTTON_ROW_OFFSET_MULTIPLIER * square_width;
self.reset_btn.initialize_drawables(Rect::new(
board_x + (square_width - btn_w_sq) / 2.,
board_width + board_y + constants::BOTTOM_ROW_OFFSET_MULTIPLIER * square_width;
self.rules_btn.initialize_drawables(Rect::new(
board_x + (square_width - btn_w) / 2.,
bottom_row_y,
btn_w_sq,
btn_w,
btn_h,
));
let btn_next_x_offset = (board_width - square_width) + (square_width - btn_w_sq) / 2.;
self.reset_btn.initialize_drawables(Rect::new(
board_x + square_width + (square_width - btn_w) / 2.,
bottom_row_y,
btn_w,
btn_h,
));
let btn_next_x_offset = (board_width - square_width) + (square_width - btn_w) / 2.;
self.next_btn.initialize_drawables(Rect::new(
board_x + btn_next_x_offset,
bottom_row_y,
btn_w_sq,
btn_w,
btn_h,
));
@@ -57,77 +70,131 @@ impl Game {
btn_w * 2.,
btn_h,
);
self.id_text = IdTextInput::new(id_text_rect);
self.id_text_btn.initialize_drawables(id_text_rect);
// Left column
let left_column_x =
board_x - constants::BOTTOM_RIGHT_ROW_OFFSET_MULTIPLIER * square_width - btn_w;
self.rules_btn.initialize_drawables(Rect::new(
left_column_x,
board_y + board_rect.h - square_width + (square_width - btn_h) / 2.,
btn_w,
btn_h,
));
self.rules_font_size = heading_font_size;
// Right column
let right_column_x =
board_x + board_width + constants::BOTTOM_RIGHT_ROW_OFFSET_MULTIPLIER * square_width;
self.easy_btn.initialize_drawables(Rect::new(
right_column_x,
board_y + square_width + (square_width - btn_h) / 2.,
btn_w,
board_x + board_width + constants::RIGHT_COLUMN_OFFSET_MULTIPLIER * square_width;
self.get_game_mode_button(&GameMode::Easy)
.initialize_drawables(Rect::new(
right_column_x,
board_y + (square_width - btn_h) / 2.,
btn_w,
btn_h,
));
self.get_game_mode_button(&GameMode::Medium)
.initialize_drawables(Rect::new(
right_column_x,
board_y + square_width + (square_width - btn_h) / 2.,
btn_w,
btn_h,
));
self.get_game_mode_button(&GameMode::Hard)
.initialize_drawables(Rect::new(
right_column_x,
board_y + 2. * square_width + (square_width - btn_h) / 2.,
btn_w,
btn_h,
));
self.get_game_mode_button(&GameMode::Custom)
.initialize_drawables(Rect::new(
right_column_x,
board_y + 3. * square_width + (square_width - btn_h) / 2.,
btn_w,
btn_h,
));
// Right column 2
let right_column_2_x =
right_column_x + btn_w + constants::RIGHT_COLUMN_OFFSET_MULTIPLIER * square_width;
self.generate_btn.initialize_drawables(Rect::new(
right_column_2_x,
board_y + board_width - square_width + (square_width - btn_h) / 2.,
2. * btn_w,
btn_h,
));
self.medium_btn.initialize_drawables(Rect::new(
right_column_x,
board_y + 2. * square_width + (square_width - btn_h) / 2.,
btn_w,
btn_h,
));
self.pieces_label.initialize_drawables(
Rect::new(
right_column_2_x,
board_y + (square_width + btn_h) / 2.,
btn_w,
btn_h,
),
0.30 * btn_h,
&self.resources,
);
self.pieces_counter.initialize_drawables(
Rect::new(
right_column_2_x,
board_y + square_width + (2. * square_width - 2. * btn_h) / 2.,
btn_w,
2. * btn_h,
),
30.,
&self.resources,
);
self.hard_btn.initialize_drawables(Rect::new(
right_column_x,
board_y + 3. * square_width + (square_width - btn_h) / 2.,
btn_w,
btn_h,
));
// Right column 3
let right_column_3_x = right_column_2_x + btn_w;
self.max_age_label.initialize_drawables(
Rect::new(
right_column_2_x + btn_w,
board_y + (square_width + btn_h) / 2.,
btn_w,
btn_h,
),
0.30 * btn_h,
&self.resources,
);
self.max_age_counter.initialize_drawables(
Rect::new(
right_column_3_x,
board_y + square_width + (2. * square_width - 2. * btn_h) / 2.,
btn_w,
2. * btn_h,
),
30.,
&self.resources,
);
}
pub fn draw(&mut self) {
self.update_window_size();
self.draw_heading();
self.board.draw(
self.show_rules,
self.heading_font_size,
&self.resources,
&self.settings,
);
self.id_text.draw(&self.resources, &self.puzzle.board.id);
self.draw_board();
self.draw_id_text_button();
self.draw_buttons();
self.draw_setting_controls();
self.draw_debug();
}
fn draw_heading(&self) {
let f = self.heading_font_size.floor() as u16;
let dims = measure_text(
self.heading_text.as_str(),
Some(&self.resources.font()),
f,
1.0,
);
let draw_text_params = TextParams {
font_size: f,
font: Some(&self.resources.font()),
color: BLACK,
..Default::default()
self.heading.draw(&self.resources);
}
fn draw_board(&mut self) {
let params = BoardDrawParams {
show_rules: self.show_rules,
rules_font_size: self.rules_font_size,
};
draw_text_ex(
self.heading_text.as_str(),
self.heading_rect.x,
self.heading_rect.y + dims.offset_y,
draw_text_params,
);
self.board.draw(&params, &self.resources, &self.settings);
}
fn get_game_mode_button<'a>(&'a mut self, mode: &GameMode) -> &'a mut ButtonWidget {
self.game_mode_btns.get_mut(mode).unwrap()
}
fn draw_game_mode_button(&mut self, mode: &GameMode, color: &UiColor, text: &str) {
let btn = self.game_mode_btns.get_mut(mode).unwrap();
btn.draw(text, color, &self.resources);
}
fn draw_buttons(&mut self) {
@@ -143,26 +210,50 @@ impl Game {
&self.resources,
);
self.easy_btn.draw(
self.draw_game_mode_button(
&GameMode::Easy,
&UiColor::Yellow,
constants::EASY_BUTTON_TEXT,
&UiColor::Yellow,
&self.resources,
);
self.medium_btn.draw(
self.draw_game_mode_button(
&GameMode::Medium,
&UiColor::Yellow,
constants::MEDIUM_BUTTON_TEXT,
&UiColor::Yellow,
&self.resources,
);
self.hard_btn.draw(
constants::HARD_BUTTON_TEXT,
self.draw_game_mode_button(
&GameMode::Hard,
&UiColor::Yellow,
constants::HARD_BUTTON_TEXT,
);
self.draw_game_mode_button(
&GameMode::Custom,
&UiColor::Blue,
constants::CUSTOM_BUTTON_TEXT,
);
self.generate_btn.draw(
constants::GENERATE_BUTTON_TEXT,
&UiColor::Pink,
&self.resources,
);
self.rules_btn
.draw(&self.rules_text, &UiColor::Brown, &self.resources);
.draw(&self.rules_btn_text, &UiColor::Brown, &self.resources);
}
fn draw_setting_controls(&mut self) {
self.pieces_label.draw(&self.resources);
self.pieces_counter.draw(&self.resources);
self.max_age_label.draw(&self.resources);
self.max_age_counter.draw(&self.resources);
}
fn draw_id_text_button(&self) {
// self.id_text_btn
// .draw(&self.puzzle.board.id, &UiColor::Yellow, &self.resources);
}
fn draw_debug(&self) {
@@ -198,8 +289,6 @@ impl Game {
return;
}
self.window_height = new_height;
self.window_width = new_width;
self.initialize_drawables();
self.initialize_drawables(new_width, new_height);
}
}
+130 -55
View File
@@ -1,3 +1,5 @@
use std::collections::HashMap;
use super::{Game, GameMode, GameSettings, constants};
use crate::{
resources::{self, *},
@@ -15,26 +17,61 @@ impl Game {
let game_mode = GameMode::Medium;
let settings = GameSettings {
volume: constants::VOLUME,
max_moves_per_piece: 3,
num_pieces: 2,
..Default::default()
};
let puzzle = Game::generate_puzzle(game_mode);
let puzzle = Game::generate_puzzle(game_mode, &settings);
let board = BoardWidget::initialize_state(puzzle.board.size, puzzle.board.clone());
let medium_btn = ButtonWidget::initialize_state(false);
let mut game_mode_btns = HashMap::new();
let game_mode = GameMode::Medium;
game_mode_btns.insert(GameMode::Easy, ButtonWidget::initialize_state(true));
game_mode_btns.insert(GameMode::Medium, ButtonWidget::initialize_state(true));
game_mode_btns.insert(GameMode::Hard, ButtonWidget::initialize_state(true));
game_mode_btns.insert(GameMode::Custom, ButtonWidget::initialize_state(true));
let reset_btn = ButtonWidget::initialize_state(true);
let next_btn = ButtonWidget::initialize_state(false);
let rules_btn = ButtonWidget::initialize_state(true);
let generate_btn = ButtonWidget::initialize_state(false);
let id_text_btn = ButtonWidget::initialize_state(true);
let heading = LabelWidget::initialize_state(constants::HEADING_TEXT);
let pieces_label = LabelWidget::initialize_state(constants::PIECES_LABEL_TEXT);
let max_age_label = LabelWidget::initialize_state(constants::AGE_LABEL_TEXT);
let show_rules = false;
let pieces_counter = CounterWidget::initialize_state(2, 7, settings.num_pieces, false);
let moves_counter = CounterWidget::initialize_state(1, 7, settings.max_moves_per_piece, false);
game_mode_btns.get_mut(&game_mode).unwrap().is_active = false;
Self {
puzzle,
board,
resources,
game_mode,
settings,
heading_text: constants::HEADING_TEXT.to_string(),
rules_text: constants::RULES_BUTTON_TEXT.to_string(),
medium_btn,
game_mode,
game_mode_btns,
rules_btn_text: constants::RULES_BUTTON_TEXT.to_string(),
reset_btn,
next_btn,
..Self::default()
rules_btn,
id_text_btn,
show_rules,
heading_text: constants::HEADING_TEXT.to_string(),
heading,
pieces_counter,
max_age_counter: moves_counter,
generate_btn,
pieces_label,
max_age_label,
..Default::default()
}
}
pub fn handle_input(&mut self) {
let (mx, my) = mouse_position();
let winput = WidgetInput {
mouse_pos: Circle::new(mx, my, 0.0),
};
// CORE GAMEPLAY
let (mouse_x, mouse_y) = mouse_position();
let mouse_pos = Circle::new(mouse_x, mouse_y, 0.0);
@@ -56,6 +93,11 @@ impl Game {
return;
}
self.id_text_btn.handle_input(
&self.resources.sound(&SoundKind::Click),
self.settings.volume,
);
if self
.reset_btn
.handle_input(
@@ -81,50 +123,41 @@ impl Game {
}
// PRESETS
let mut clicked_game_mode_btn: Option<&ButtonWidget> = None;
if self
.easy_btn
.handle_input(
&self.resources.sound(&SoundKind::Mode),
self.settings.volume,
)
.is_clicked
{
self.game_mode = GameMode::Easy;
self.easy_btn.is_active = false;
self.medium_btn.is_active = true;
self.hard_btn.is_active = true;
clicked_game_mode_btn = Some(&self.easy_btn);
} else if self
.medium_btn
.handle_input(
&self.resources.sound(&SoundKind::Mode),
self.settings.volume,
)
.is_clicked
{
self.game_mode = GameMode::Medium;
self.easy_btn.is_active = true;
self.medium_btn.is_active = false;
self.hard_btn.is_active = true;
clicked_game_mode_btn = Some(&self.medium_btn);
} else if self
.hard_btn
.handle_input(
&self.resources.sound(&SoundKind::Mode),
self.settings.volume,
)
.is_clicked
{
self.game_mode = GameMode::Hard;
self.easy_btn.is_active = true;
self.medium_btn.is_active = true;
self.hard_btn.is_active = false;
clicked_game_mode_btn = Some(&self.hard_btn);
let mut game_mode_changed = false;
for (mode, btn) in &mut self.game_mode_btns {
if btn
.handle_input(
&self.resources.sound(&SoundKind::Mode),
self.settings.volume,
)
.is_clicked
{
self.game_mode = *mode;
game_mode_changed = true;
break;
}
}
if let Some(_) = clicked_game_mode_btn {
self.next_puzzle();
if game_mode_changed {
for (mode, btn) in &mut self.game_mode_btns {
if *mode == self.game_mode {
btn.is_active = false;
} else {
btn.is_active = true;
}
}
if self.game_mode != GameMode::Custom {
self.generate_btn.is_active = false;
self.pieces_counter.set_active(false);
self.max_age_counter.set_active(false);
self.next_puzzle();
} else {
self.generate_btn.is_active = true;
self.pieces_counter.set_active(true);
self.max_age_counter.set_active(true);
}
return;
}
@@ -137,7 +170,7 @@ impl Game {
.is_clicked
{
self.show_rules = !self.show_rules;
self.rules_text = match self.show_rules {
self.rules_btn_text = match self.show_rules {
true => constants::RULES_BUTTON_ALT_TEXT.to_string(),
false => constants::RULES_BUTTON_TEXT.to_string(),
};
@@ -145,6 +178,36 @@ impl Game {
return;
}
let pieces_counter_interaction =
self.pieces_counter
.handle_input(&winput, &self.resources, &self.settings);
if pieces_counter_interaction.interacted {
self.settings.num_pieces = pieces_counter_interaction.current;
return;
}
let moves_counter_interaction =
self.max_age_counter
.handle_input(&winput, &self.resources, &self.settings);
if moves_counter_interaction.interacted {
self.settings.max_moves_per_piece = moves_counter_interaction.current;
return;
}
if self
.generate_btn
.handle_input(
&self.resources.sound(&SoundKind::Button),
self.settings.volume,
)
.is_clicked
{
if self.game_mode == GameMode::Custom {
self.next_puzzle();
}
return;
}
// KEY INPUTS
if is_key_released(KeyCode::Escape) {
if self.show_rules {
@@ -153,7 +216,7 @@ impl Game {
self.settings.volume,
);
self.show_rules = false;
self.rules_text = constants::RULES_BUTTON_TEXT.to_string();
self.rules_btn_text = constants::RULES_BUTTON_TEXT.to_string();
}
return;
@@ -175,7 +238,7 @@ impl Game {
fn reset_game(&mut self, options: ResetOptions) {
if options.create_new_puzzle {
self.puzzle = Game::generate_puzzle(self.game_mode);
self.puzzle = Game::generate_puzzle(self.game_mode, &self.settings);
}
self.next_btn.is_active = false;
@@ -189,15 +252,27 @@ impl Game {
});
}
fn generate_puzzle(mode: GameMode) -> Puzzle {
fn generate_puzzle(mode: GameMode, settings: &GameSettings) -> Puzzle {
let piece_count = match mode {
GameMode::Easy => 3,
GameMode::Medium => 5,
GameMode::Hard => 7,
GameMode::Custom => settings.num_pieces,
};
let generated =
generator::generate_weighted_random(piece_count, 100, &MacroquadRandAdapter);
let max_moves_per_piece = match mode {
GameMode::Easy => 2,
GameMode::Medium => 2,
GameMode::Hard => 2,
GameMode::Custom => settings.max_moves_per_piece,
};
let generated = generator::generate_weighted_random(
piece_count,
100,
max_moves_per_piece,
&MacroquadRandAdapter,
);
let puzzle = generated.puzzle();
puzzle.expect("No puzzle was generated")
}
+1
View File
@@ -36,3 +36,4 @@ async fn main() {
next_frame().await
}
}
+36 -18
View File
@@ -2,13 +2,14 @@ use macroquad::{
audio::{self, Sound},
prelude::*,
};
use sol_lib::board::piece::Piece;
use sol_lib::board::piece::{Piece, PieceKind};
use std::collections::HashMap;
#[derive(Default)]
pub struct Resources {
texture_pieces: Option<Texture2D>,
texture_rects_pieces: HashMap<Piece, Rect>,
texture_rects_pieces: HashMap<PieceKind, Rect>,
texture_rects_inactive_pieces: HashMap<PieceKind, Rect>,
sounds: HashMap<SoundKind, Sound>,
@@ -52,32 +53,43 @@ pub async fn init() -> Resources {
texture_pieces.set_filter(FilterMode::Nearest);
build_textures_atlas();
let mut texture_rects_pieces = HashMap::new();
texture_rects_pieces.insert(Piece::Pawn, piece_texture_rect(Piece::Pawn));
texture_rects_pieces.insert(Piece::Knight, piece_texture_rect(Piece::Knight));
texture_rects_pieces.insert(Piece::Bishop, piece_texture_rect(Piece::Bishop));
texture_rects_pieces.insert(Piece::Rook, piece_texture_rect(Piece::Rook));
texture_rects_pieces.insert(Piece::Queen, piece_texture_rect(Piece::Queen));
texture_rects_pieces.insert(Piece::King, piece_texture_rect(Piece::King));
let texture_rects_pieces = generate_texture_rects_pieces(true);
let texture_rects_inactive_pieces = generate_texture_rects_pieces(false);
Resources {
texture_pieces: Some(texture_pieces),
texture_rects_pieces,
texture_rects_inactive_pieces,
sounds,
font: Some(font),
}
}
fn piece_texture_rect(piece: Piece) -> Rect {
fn generate_texture_rects_pieces(active: bool) -> HashMap<PieceKind, Rect> {
let mut texture_rects_pieces = HashMap::new();
texture_rects_pieces.insert(PieceKind::Pawn, piece_texture_rect(PieceKind::Pawn, active));
texture_rects_pieces.insert(PieceKind::Knight, piece_texture_rect(PieceKind::Knight, active));
texture_rects_pieces.insert(PieceKind::Bishop, piece_texture_rect(PieceKind::Bishop, active));
texture_rects_pieces.insert(PieceKind::Rook, piece_texture_rect(PieceKind::Rook, active));
texture_rects_pieces.insert(PieceKind::Queen, piece_texture_rect(PieceKind::Queen, active));
texture_rects_pieces.insert(PieceKind::King, piece_texture_rect(PieceKind::King, active));
texture_rects_pieces
}
fn piece_texture_rect(piece: PieceKind, active: bool) -> Rect {
let index = match piece {
Piece::Pawn => 0,
Piece::Knight => 1,
Piece::Bishop => 2,
Piece::Rook => 3,
Piece::Queen => 4,
Piece::King => 5,
PieceKind::Pawn => 0,
PieceKind::Knight => 1,
PieceKind::Bishop => 2,
PieceKind::Rook => 3,
PieceKind::Queen => 4,
PieceKind::King => 5,
};
let color = match active {
true => 1,
false => 0,
};
let color = 0;
Rect::new(index as f32 * 128.0, color as f32 * 128.0, 128.0, 128.0)
}
@@ -93,7 +105,13 @@ pub enum SoundKind {
impl Resources {
pub fn get_piece_texture<'a>(&'a self, piece: &Piece) -> Texture<'a> {
let texture = self.texture_pieces.as_ref().unwrap();
let texture_rect = self.texture_rects_pieces.get(piece).unwrap();
let texture_rects_lookup = if piece.active {
&self.texture_rects_pieces
} else {
&self.texture_rects_inactive_pieces
};
let texture_rect = texture_rects_lookup.get(&piece.kind).unwrap();
Texture {
texture: texture,
texture_rect: *texture_rect,
+10 -1
View File
@@ -5,7 +5,12 @@ mod button;
pub use button::*;
mod id_text_input;
pub use id_text_input::*;
mod label;
pub use label::*;
mod counter;
pub use counter::*;
use macroquad::{
audio::{self, Sound},
@@ -13,6 +18,10 @@ use macroquad::{
};
use quad_snd::PlaySoundParams;
pub struct WidgetInput {
pub mouse_pos: Circle,
}
#[allow(unused)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UiColor {
+16 -9
View File
@@ -28,10 +28,6 @@ pub struct BoardInteraction<'a> {
}
impl BoardWidget {
fn get(&mut self, i: usize, j: usize) -> &mut GameSquare {
&mut self.squares[i * self.num_squares + j]
}
pub fn initialize_state(num_squares: usize, current_board: Board) -> BoardWidget {
let mut board = BoardWidget::default();
board.num_squares = num_squares;
@@ -71,11 +67,11 @@ impl BoardWidget {
self.squares = rects;
}
pub fn draw(&self, show_rules: bool, rules_font_size: f32, resources: &Resources, settings: &GameSettings) {
pub fn draw(&self, params: &BoardDrawParams, resources: &Resources, settings: &GameSettings) {
let board_shadow_width = constants::BOARD_SHADOW_MULTIPLIER * self.square_width;
draw_shadow(&self.board_rect, board_shadow_width);
if show_rules {
if params.show_rules {
draw_rectangle(
self.board_rect.x,
self.board_rect.y,
@@ -84,11 +80,13 @@ impl BoardWidget {
UiColor::Yellow.to_bg_color(),
);
let font_size = rules_font_size * 0.6;
let font_size = params.rules_font_size * 0.4;
let rules = "\
Every move should be a \n\
capture. Win when only \n\
one piece is left.\n";
one piece is left.\n\
Age: Each piece can only \n\
move 'age' times";
let measurement = measure_text(rules, Some(resources.font()), font_size as u16, 1.0);
let draw_text_params = TextParams {
font_size: font_size as u16,
@@ -99,7 +97,7 @@ impl BoardWidget {
draw_multiline_text_ex(
rules,
self.board_rect.x + 0.5 * self.square_width,
self.board_rect.y + 0.5 * (self.board_rect.h - measurement.height)
self.board_rect.y + 0.4 * (self.board_rect.h - measurement.height)
- 2. * measurement.offset_y,
Some(2.),
draw_text_params,
@@ -161,6 +159,10 @@ impl BoardWidget {
}
}
fn get(&mut self, i: usize, j: usize) -> &mut GameSquare {
&mut self.squares[i * self.num_squares + j]
}
fn draw_debug(&self) {
let mut debug_lines = vec![];
let (mx, my) = mouse_position();
@@ -420,3 +422,8 @@ struct PieceDrawTextureParams<'a> {
texture: &'a Texture2D,
draw_text_params: DrawTextureParams,
}
pub struct BoardDrawParams {
pub show_rules: bool,
pub rules_font_size: f32,
}
+13 -2
View File
@@ -66,8 +66,19 @@ impl ButtonWidget {
};
let font = resources.font();
let font_size = (0.2 * self.rect.w) as u16;
let dims = measure_text(&text, Some(&font), font_size, 1.0);
let mut dim_width = self.rect.w;
let mut font_size = 30.0;
let mut dims = measure_text(&text, Some(&font), font_size as u16, 1.0);
loop {
if dim_width <= self.rect.w * 0.8 {
break;
}
dims = measure_text(&text, Some(&font), font_size as u16, 1.0);
dim_width = dims.width;
font_size -= 2.0;
}
let button_draw_offset = self.get_button_draw_offset();
let text_params = TextParams {
+127
View File
@@ -0,0 +1,127 @@
use crate::{
game::GameSettings,
resources::{Resources, SoundKind},
widgets::*,
};
use macroquad::prelude::*;
#[derive(Default)]
pub struct CounterWidget {
visual_rect: Rect,
increment: ButtonWidget,
decrement: ButtonWidget,
min: u32,
max: u32,
current: u32,
font_size: f32,
visual_dims: TextDimensions,
increment_dims: TextDimensions,
decrement_dims: TextDimensions,
is_active: bool,
}
pub struct CounterWidgetInteraction {
pub current: u32,
pub interacted: bool,
}
impl CounterWidget {
pub fn initialize_state(min: u32, max: u32, current: u32, is_active: bool) -> Self {
Self {
min,
max,
current,
is_active,
..Default::default()
}
}
pub fn set_active(&mut self, is_active: bool) {
self.is_active = is_active;
self.increment.is_active = is_active;
self.decrement.is_active = is_active;
}
pub fn initialize_drawables(
&mut self,
total_area: Rect,
font_size: f32,
resources: &Resources,
) {
let margin_y = 0.05 * total_area.h;
let btn_h = total_area.h * 0.3;
let btn_w = total_area.w * 0.9;
let btn_x = total_area.x + (total_area.w - btn_w) / 2.;
let increment_y = total_area.y + margin_y;
let visual_y = increment_y + btn_h + margin_y;
let decrement_y = visual_y + btn_h + margin_y;
self.visual_rect = Rect::new(btn_x, visual_y, btn_w, btn_h);
let increment_rect = Rect::new(btn_x, increment_y, btn_w, btn_h);
self.increment = ButtonWidget::initialize_state(self.is_active);
self.increment.initialize_drawables(increment_rect);
let decrement_rect = Rect::new(btn_x, decrement_y, btn_w, btn_h);
self.decrement = ButtonWidget::initialize_state(self.is_active);
self.decrement.initialize_drawables(decrement_rect);
self.increment_dims = measure_text("+", Some(resources.font()), font_size as u16, 1.0);
self.decrement_dims = measure_text("-", Some(resources.font()), font_size as u16, 1.0);
self.visual_dims = measure_text("0", Some(resources.font()), font_size as u16, 1.0);
self.font_size = font_size;
}
pub fn handle_input(
&mut self,
_: &WidgetInput,
resources: &Resources,
settings: &GameSettings,
) -> CounterWidgetInteraction {
let mut interacted = false;
if self
.increment
.handle_input(resources.sound(&SoundKind::Click), settings.volume)
.is_clicked
{
if self.current < self.max {
self.current += 1;
interacted = true;
}
}
if self
.decrement
.handle_input(resources.sound(&SoundKind::Click), settings.volume)
.is_clicked
{
if self.current > self.min {
self.current -= 1;
interacted = true;
}
}
return CounterWidgetInteraction {
current: self.current,
interacted,
};
}
pub fn draw(&mut self, resources: &Resources) {
self.increment.draw("+", &UiColor::Yellow, resources);
self.decrement.draw("-", &UiColor::Yellow, resources);
draw_text_ex(
&self.current.to_string(),
self.visual_rect.x + (self.visual_rect.w - self.visual_dims.width) / 2.,
self.visual_rect.y + (self.visual_rect.h + self.font_size) / 2.,
TextParams {
font: Some(resources.font()),
font_size: self.font_size as u16,
color: UiColor::Yellow.to_fg_color(),
..Default::default()
},
);
}
}
+44 -48
View File
@@ -1,77 +1,73 @@
#[allow(dead_code)]
use crate::{resources::Resources, widgets::*};
use macroquad::prelude::*;
#[derive(Default)]
pub struct IdTextInput {
rect: Rect,
text_rect: Rect,
copy_box_rect: Rect,
paste_box_rect: Rect,
shadow_width: f32,
color: UiColor,
copy_color: UiColor,
paste_color: UiColor,
}
pub struct IdTextInputDrawParams<'a> {
pub text: &'a str,
pub color: UiColor,
pub copy_color: UiColor,
pub paste_color: UiColor,
pub shadow_width: f32,
}
impl IdTextInput {
pub fn new(rect: Rect) -> Self {
let copy_button_w = 0.25 * rect.w;
let paste_button_h = 0.5 * rect.h;
Self {
rect,
text_rect: Rect::new(rect.x, rect.y, rect.w - copy_button_w, rect.h),
copy_box_rect: Rect::new(
rect.x + (rect.w - copy_button_w),
rect.y,
copy_button_w,
paste_button_h,
),
paste_box_rect: Rect::new(
rect.x + (rect.w - copy_button_w),
rect.y + paste_button_h,
copy_button_w,
paste_button_h,
),
shadow_width: 3.0,
color: UiColor::Yellow,
copy_color: UiColor::Blue,
paste_color: UiColor::Pink,
}
pub fn initialize_state() -> Self {
Default::default()
}
pub fn draw(&self, resources: &Resources, text: &str) {
draw_rect(&self.text_rect, self.color);
draw_rect(&self.copy_box_rect, self.copy_color);
draw_rect(&self.paste_box_rect, self.paste_color);
draw_shadow(&self.rect, self.shadow_width);
pub fn initialize_drawables(&mut self, rect: Rect) {
let copy_button_w = 0.25 * rect.w;
let paste_button_h = 0.5 * rect.h;
self.rect = rect;
self.text_rect = Rect::new(rect.x, rect.y, rect.w - copy_button_w, rect.h);
self.copy_box_rect = Rect::new(
rect.x + (rect.w - copy_button_w),
rect.y,
copy_button_w,
paste_button_h,
);
self.paste_box_rect = Rect::new(
rect.x + (rect.w - copy_button_w),
rect.y + paste_button_h,
copy_button_w,
paste_button_h,
);
}
pub fn draw(&self, params: &IdTextInputDrawParams, resources: &Resources) {
draw_rect(&self.text_rect, params.color);
draw_rect(&self.copy_box_rect, params.copy_color);
draw_rect(&self.paste_box_rect, params.paste_color);
draw_shadow(&self.rect, params.shadow_width);
let font = resources.font();
let font_size = (0.15 * self.text_rect.w) as u16;
let text_dims = measure_text(text, Some(font), font_size, 1.0);
let text_dims = measure_text(params.text, Some(font), font_size, 1.0);
draw_text_ex(
&text,
params.text,
self.rect.x + (self.text_rect.w - text_dims.width) / 2.,
self.rect.y + (self.text_rect.h - text_dims.height) / 2. + text_dims.offset_y,
TextParams {
font: Some(font),
font_size: font_size,
color: self.color.to_fg_color(),
color: params.color.to_fg_color(),
..Default::default()
},
);
}
}
impl Default for IdTextInput {
fn default() -> Self {
Self {
rect: Default::default(),
text_rect: Default::default(),
copy_box_rect: Default::default(),
paste_box_rect: Default::default(),
shadow_width: Default::default(),
color: UiColor::Grey,
copy_color: UiColor::Grey,
paste_color: UiColor::Grey,
}
pub fn handle_input(&self, _: &WidgetInput) -> IdTextInputInteraction {
IdTextInputInteraction {}
}
}
pub struct IdTextInputInteraction {}
+42
View File
@@ -0,0 +1,42 @@
use macroquad::prelude::*;
use crate::resources::Resources;
#[derive(Default)]
pub struct LabelWidget {
rect: Rect,
font_size: f32,
text_dimensions: TextDimensions,
text: String,
}
impl LabelWidget {
pub fn initialize_state(text: &str) -> Self {
Self {
text: text.to_string(),
..Default::default()
}
}
pub fn initialize_drawables(&mut self, rect: Rect, font_size: f32, resources: &Resources) {
self.rect = rect;
self.font_size = font_size;
self.text_dimensions = measure_text(&self.text, Some(resources.font()), font_size as u16, 1.0);
}
pub fn draw(&self, resources: &Resources) {
let draw_text_params = TextParams {
font: Some(&resources.font()),
font_size: self.font_size as u16,
color: BLACK,
..Default::default()
};
draw_text_ex(
&self.text,
self.rect.x,
self.rect.y + self.text_dimensions.offset_y,
draw_text_params,
);
}
}