move to retained mode complete
This commit is contained in:
Binary file not shown.
+2
-276
@@ -4,11 +4,7 @@ mod logic;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
game,
|
||||
resources::{self, Resources, SoundKind},
|
||||
widgets::*,
|
||||
};
|
||||
use crate::{resources::Resources, widgets::*};
|
||||
use macroquad::prelude::*;
|
||||
use sol_lib::{board::BoardState, generator::Puzzle};
|
||||
|
||||
@@ -16,14 +12,12 @@ use sol_lib::{board::BoardState, generator::Puzzle};
|
||||
pub struct Game {
|
||||
resources: Resources,
|
||||
|
||||
// Game state
|
||||
settings: Settings,
|
||||
puzzle: Puzzle,
|
||||
show_rules: bool,
|
||||
game_mode: GameMode,
|
||||
game_mode_btns: HashMap<GameMode, WidgetId>,
|
||||
|
||||
// Render state
|
||||
window_height: f32,
|
||||
window_width: f32,
|
||||
|
||||
@@ -44,109 +38,6 @@ pub struct Game {
|
||||
btn_generate: WidgetId,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Hash, Default)]
|
||||
pub struct WidgetId(u64);
|
||||
|
||||
pub enum Widget {
|
||||
Label(LabelWidget),
|
||||
Counter(CounterWidget),
|
||||
Button(ButtonWidget),
|
||||
Board(BoardWidget),
|
||||
}
|
||||
|
||||
impl Widget {
|
||||
fn draw(&mut self, resources: &Resources, settings: &Settings) {
|
||||
match self {
|
||||
Widget::Label(label) => label.draw(&resources),
|
||||
Widget::Counter(counter) => counter.draw(&resources),
|
||||
Widget::Button(btn) => btn.draw(&resources),
|
||||
Widget::Board(board) => board.draw(&resources, &settings),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(
|
||||
&mut self,
|
||||
interaction: &Interaction,
|
||||
resources: &Resources,
|
||||
settings: &Settings,
|
||||
) -> Command {
|
||||
match self {
|
||||
Widget::Label(_) => Command::NoInteraction,
|
||||
Widget::Counter(c) => handle_counter_input(interaction, c, resources, settings),
|
||||
Widget::Button(b) => handle_button_input(interaction, b, resources, settings),
|
||||
Widget::Board(_) => Command::NoInteraction,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_counter_input(
|
||||
interaction: &Interaction,
|
||||
counter: &mut CounterWidget,
|
||||
resources: &Resources,
|
||||
settings: &Settings,
|
||||
) -> Command {
|
||||
let counter_interaction = counter.handle_input(interaction, resources, settings);
|
||||
let Some(interaction_type) = counter_interaction.interaction_type else {
|
||||
return Command::NoInteraction;
|
||||
};
|
||||
|
||||
match interaction_type {
|
||||
CounterInteractionType::Increment => (counter.on_increment)(counter_interaction),
|
||||
CounterInteractionType::Decrement => (counter.on_decrement)(counter_interaction),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_button_input(
|
||||
interaction: &Interaction,
|
||||
button: &mut ButtonWidget,
|
||||
resources: &Resources,
|
||||
settings: &Settings,
|
||||
) -> Command {
|
||||
let clicked = button
|
||||
.handle_input(interaction, resources, settings)
|
||||
.clicked;
|
||||
if clicked {
|
||||
return (button.on_click)(button);
|
||||
}
|
||||
|
||||
Command::NoInteraction
|
||||
}
|
||||
|
||||
macro_rules! get_widget_fn {
|
||||
($name:ident, $ret:ty, $variant:path) => {
|
||||
fn $name(widgets: &mut HashMap<WidgetId, Widget>, id: WidgetId) -> &mut $ret {
|
||||
match widgets.get_mut(&id) {
|
||||
Some(w) => match w {
|
||||
$variant(v) => return v,
|
||||
_ => panic!("Widget with id {} not found", id.0),
|
||||
},
|
||||
None => panic!("Widget with id {} not found", id.0),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
get_widget_fn!(label, LabelWidget, Widget::Label);
|
||||
get_widget_fn!(button, ButtonWidget, Widget::Button);
|
||||
get_widget_fn!(counter, CounterWidget, Widget::Counter);
|
||||
get_widget_fn!(board, BoardWidget, Widget::Board);
|
||||
|
||||
macro_rules! widget_accessor {
|
||||
($name:ident, $fn:ident) => {
|
||||
macro_rules! $name {
|
||||
($this:expr, $widget_id:ident) => {
|
||||
game::$fn(&mut $this.widgets, $this.$widget_id)
|
||||
};
|
||||
}
|
||||
pub(crate) use $name;
|
||||
};
|
||||
}
|
||||
|
||||
widget_accessor!(w_button, button);
|
||||
widget_accessor!(w_label, label);
|
||||
widget_accessor!(w_counter, counter);
|
||||
widget_accessor!(w_board, board);
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Settings {
|
||||
pub volume: f32,
|
||||
@@ -169,6 +60,7 @@ impl Default for GameMode {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Command {
|
||||
NoInteraction,
|
||||
ResetBoard,
|
||||
@@ -183,169 +75,3 @@ pub enum Command {
|
||||
HideRules,
|
||||
Quit,
|
||||
}
|
||||
|
||||
pub async fn new_game() -> Game {
|
||||
let resources = resources::init().await;
|
||||
let game_mode = GameMode::Medium;
|
||||
let settings = Settings {
|
||||
volume: constants::VOLUME,
|
||||
max_age: 3,
|
||||
max_pieces: 2,
|
||||
..Default::default()
|
||||
};
|
||||
let puzzle = logic::generate_new_puzzle(game_mode, &settings);
|
||||
let game_mode = GameMode::Medium;
|
||||
let label_heading = LabelWidget::initialize_state(constants::HEADING_TEXT);
|
||||
let label_pieces = LabelWidget::initialize_state(constants::PIECES_LABEL_TEXT);
|
||||
let label_max_age = LabelWidget::initialize_state(constants::AGE_LABEL_TEXT);
|
||||
let show_rules = false;
|
||||
|
||||
let mut widgets = HashMap::new();
|
||||
let label_pieces = add_widget(&mut widgets, Widget::Label(label_pieces));
|
||||
let label_max_age = add_widget(&mut widgets, Widget::Label(label_max_age));
|
||||
let label_heading = add_widget(&mut widgets, Widget::Label(label_heading));
|
||||
|
||||
let mut w_counter_pieces =
|
||||
CounterWidget::new(2, 7, settings.max_pieces, false, UiColor::Yellow);
|
||||
w_counter_pieces.on_increment = |c| Command::UpdateMaxPieceCount(c.current);
|
||||
w_counter_pieces.on_decrement = |c| Command::UpdateMaxPieceCount(c.current);
|
||||
let counter_pieces = add_widget(&mut widgets, Widget::Counter(w_counter_pieces));
|
||||
|
||||
let mut w_counter_moves = CounterWidget::new(1, 7, settings.max_age, false, UiColor::Yellow);
|
||||
w_counter_moves.on_increment = |c| Command::UpdateMaxAge(c.current);
|
||||
w_counter_moves.on_decrement = |c| Command::UpdateMaxAge(c.current);
|
||||
let counter_moves = add_widget(&mut widgets, Widget::Counter(w_counter_moves));
|
||||
|
||||
let btn_reset = add_widget(
|
||||
&mut widgets,
|
||||
Widget::Button(ButtonWidget::new(
|
||||
true,
|
||||
UiColor::Yellow,
|
||||
constants::RESET_BUTTON_TEXT,
|
||||
SoundKind::Button,
|
||||
)),
|
||||
);
|
||||
|
||||
let btn_next = add_widget(
|
||||
&mut widgets,
|
||||
Widget::Button(ButtonWidget::new(
|
||||
false,
|
||||
UiColor::Green,
|
||||
constants::NEXT_BUTTON_TEXT,
|
||||
SoundKind::Button,
|
||||
)),
|
||||
);
|
||||
|
||||
let btn_rules = add_widget(
|
||||
&mut widgets,
|
||||
Widget::Button(ButtonWidget::new(
|
||||
true,
|
||||
UiColor::Brown,
|
||||
constants::RULES_BUTTON_TEXT,
|
||||
SoundKind::Button,
|
||||
)),
|
||||
);
|
||||
|
||||
let btn_generate = add_widget(
|
||||
&mut widgets,
|
||||
Widget::Button(ButtonWidget::new(
|
||||
false,
|
||||
UiColor::Pink,
|
||||
constants::GENERATE_BUTTON_TEXT,
|
||||
SoundKind::Button,
|
||||
)),
|
||||
);
|
||||
|
||||
let mut game_mode_btns = HashMap::new();
|
||||
game_mode_btns.insert(
|
||||
GameMode::Easy,
|
||||
add_widget(
|
||||
&mut widgets,
|
||||
Widget::Button(ButtonWidget::new(
|
||||
true,
|
||||
UiColor::Yellow,
|
||||
constants::EASY_BUTTON_TEXT,
|
||||
SoundKind::Mode,
|
||||
)),
|
||||
),
|
||||
);
|
||||
|
||||
game_mode_btns.insert(
|
||||
GameMode::Medium,
|
||||
add_widget(
|
||||
&mut widgets,
|
||||
Widget::Button(ButtonWidget::new(
|
||||
true,
|
||||
UiColor::Yellow,
|
||||
constants::MEDIUM_BUTTON_TEXT,
|
||||
SoundKind::Mode,
|
||||
)),
|
||||
),
|
||||
);
|
||||
|
||||
game_mode_btns.insert(
|
||||
GameMode::Hard,
|
||||
add_widget(
|
||||
&mut widgets,
|
||||
Widget::Button(ButtonWidget::new(
|
||||
true,
|
||||
UiColor::Yellow,
|
||||
constants::HARD_BUTTON_TEXT,
|
||||
SoundKind::Mode,
|
||||
)),
|
||||
),
|
||||
);
|
||||
|
||||
game_mode_btns.insert(
|
||||
GameMode::Custom,
|
||||
add_widget(
|
||||
&mut widgets,
|
||||
Widget::Button(ButtonWidget::new(
|
||||
true,
|
||||
UiColor::Blue,
|
||||
constants::CUSTOM_BUTTON_TEXT,
|
||||
SoundKind::Mode,
|
||||
)),
|
||||
),
|
||||
);
|
||||
|
||||
let active_game_mode_btn = game_mode_btns.get(&game_mode).unwrap();
|
||||
game::button(&mut widgets, *active_game_mode_btn).is_active = false;
|
||||
|
||||
let board = add_widget(
|
||||
&mut widgets,
|
||||
Widget::Board(BoardWidget::initialize_state(
|
||||
puzzle.board.size,
|
||||
puzzle.board.clone(),
|
||||
)),
|
||||
);
|
||||
|
||||
Game {
|
||||
puzzle,
|
||||
board,
|
||||
resources,
|
||||
settings,
|
||||
game_mode,
|
||||
game_mode_btns,
|
||||
btn_reset,
|
||||
btn_next,
|
||||
btn_rules,
|
||||
show_rules,
|
||||
widgets,
|
||||
counter_pieces,
|
||||
counter_moves,
|
||||
btn_generate,
|
||||
label_pieces,
|
||||
label_max_age,
|
||||
label_heading,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn add_widget(widgets: &mut HashMap<WidgetId, Widget>, w: Widget) -> WidgetId {
|
||||
let id = rand::rand() as u64;
|
||||
let widget_id = WidgetId(id);
|
||||
widgets.insert(widget_id, w);
|
||||
|
||||
widget_id
|
||||
}
|
||||
|
||||
+69
-59
@@ -1,6 +1,6 @@
|
||||
use super::{Game, constants};
|
||||
use crate::{
|
||||
game::{self, GameMode, w_board, w_button, w_counter, w_label},
|
||||
game::{self, GameMode},
|
||||
widgets::*,
|
||||
};
|
||||
use macroquad::{math, prelude::*};
|
||||
@@ -33,92 +33,102 @@ impl Game {
|
||||
heading_text_dims.width,
|
||||
heading_text_dims.height,
|
||||
);
|
||||
w_label!(self, label_heading).initialize_drawables(
|
||||
heading_rect,
|
||||
heading_font_size,
|
||||
&self.resources,
|
||||
);
|
||||
w_label!(self, label_heading).place(heading_rect, heading_font_size, &self.resources);
|
||||
|
||||
let board_rect = Rect::new(board_x, board_y, board_width, board_width);
|
||||
w_board!(self, board).initialize_drawables(
|
||||
square_width,
|
||||
board_rect,
|
||||
heading_font_size * 0.4,
|
||||
);
|
||||
w_board!(self, board).place(square_width, board_rect, heading_font_size * 0.4);
|
||||
|
||||
// Buttons
|
||||
let btn_h = constants::BUTTON_HEIGHT_MULTIPLIER * min_dimension;
|
||||
let btn_w = constants::BUTTON_WIDTH_MULTIPLIER * board_width;
|
||||
let btn_font_size = heading_font_size * 0.3;
|
||||
|
||||
// Bottom row
|
||||
let bottom_row_y =
|
||||
board_width + board_y + constants::BOTTOM_ROW_OFFSET_MULTIPLIER * square_width;
|
||||
w_button!(self, btn_rules).place(Rect::new(
|
||||
board_x + (square_width - btn_w) / 2.,
|
||||
bottom_row_y,
|
||||
btn_w,
|
||||
btn_h,
|
||||
));
|
||||
w_button!(self, btn_rules).place(
|
||||
Rect::new(
|
||||
board_x + (square_width - btn_w) / 2.,
|
||||
bottom_row_y,
|
||||
btn_w,
|
||||
btn_h,
|
||||
),
|
||||
FontSize::Fixed(btn_font_size),
|
||||
);
|
||||
|
||||
w_button!(self, btn_reset).place(Rect::new(
|
||||
board_x + square_width + (square_width - btn_w) / 2.,
|
||||
bottom_row_y,
|
||||
btn_w,
|
||||
btn_h,
|
||||
));
|
||||
w_button!(self, btn_reset).place(
|
||||
Rect::new(
|
||||
board_x + square_width + (square_width - btn_w) / 2.,
|
||||
bottom_row_y,
|
||||
btn_w,
|
||||
btn_h,
|
||||
),
|
||||
FontSize::Fixed(btn_font_size),
|
||||
);
|
||||
|
||||
let btn_next_x_offset = (board_width - square_width) + (square_width - btn_w) / 2.;
|
||||
w_button!(self, btn_next).place(Rect::new(
|
||||
board_x + btn_next_x_offset,
|
||||
bottom_row_y,
|
||||
btn_w,
|
||||
btn_h,
|
||||
));
|
||||
w_button!(self, btn_next).place(
|
||||
Rect::new(board_x + btn_next_x_offset, bottom_row_y, btn_w, btn_h),
|
||||
FontSize::Fixed(btn_font_size),
|
||||
);
|
||||
|
||||
// Right column
|
||||
let right_column_x =
|
||||
board_x + board_width + constants::RIGHT_COLUMN_OFFSET_MULTIPLIER * square_width;
|
||||
self.get_game_mode_button(&GameMode::Easy).place(Rect::new(
|
||||
right_column_x,
|
||||
board_y + (square_width - btn_h) / 2.,
|
||||
btn_w,
|
||||
btn_h,
|
||||
));
|
||||
self.get_game_mode_button(&GameMode::Easy).place(
|
||||
Rect::new(
|
||||
right_column_x,
|
||||
board_y + (square_width - btn_h) / 2.,
|
||||
btn_w,
|
||||
btn_h,
|
||||
),
|
||||
FontSize::Fixed(btn_font_size),
|
||||
);
|
||||
|
||||
self.get_game_mode_button(&GameMode::Medium)
|
||||
.place(Rect::new(
|
||||
self.get_game_mode_button(&GameMode::Medium).place(
|
||||
Rect::new(
|
||||
right_column_x,
|
||||
board_y + square_width + (square_width - btn_h) / 2.,
|
||||
btn_w,
|
||||
btn_h,
|
||||
));
|
||||
),
|
||||
FontSize::Fixed(btn_font_size),
|
||||
);
|
||||
|
||||
self.get_game_mode_button(&GameMode::Hard).place(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::Hard).place(
|
||||
Rect::new(
|
||||
right_column_x,
|
||||
board_y + 2. * square_width + (square_width - btn_h) / 2.,
|
||||
btn_w,
|
||||
btn_h,
|
||||
),
|
||||
FontSize::Fixed(btn_font_size),
|
||||
);
|
||||
|
||||
self.get_game_mode_button(&GameMode::Custom)
|
||||
.place(Rect::new(
|
||||
self.get_game_mode_button(&GameMode::Custom).place(
|
||||
Rect::new(
|
||||
right_column_x,
|
||||
board_y + 3. * square_width + (square_width - btn_h) / 2.,
|
||||
btn_w,
|
||||
btn_h,
|
||||
));
|
||||
),
|
||||
FontSize::Fixed(btn_font_size),
|
||||
);
|
||||
|
||||
// Right column 2
|
||||
let right_column_2_x =
|
||||
right_column_x + btn_w + constants::RIGHT_COLUMN_OFFSET_MULTIPLIER * square_width;
|
||||
w_button!(self, btn_generate).place(Rect::new(
|
||||
right_column_2_x,
|
||||
board_y + board_width - square_width + (square_width - btn_h) / 2.,
|
||||
2. * btn_w,
|
||||
btn_h,
|
||||
));
|
||||
w_button!(self, btn_generate).place(
|
||||
Rect::new(
|
||||
right_column_2_x,
|
||||
board_y + board_width - square_width + (square_width - btn_h) / 2.,
|
||||
2. * btn_w,
|
||||
btn_h,
|
||||
),
|
||||
FontSize::Fixed(btn_font_size),
|
||||
);
|
||||
|
||||
w_label!(self, label_pieces).initialize_drawables(
|
||||
w_label!(self, label_pieces).place(
|
||||
Rect::new(
|
||||
right_column_2_x,
|
||||
board_y + (square_width + btn_h) / 2.,
|
||||
@@ -129,20 +139,20 @@ impl Game {
|
||||
&self.resources,
|
||||
);
|
||||
|
||||
w_counter!(self, counter_pieces).initialize_drawables(
|
||||
w_counter!(self, counter_pieces).place(
|
||||
Rect::new(
|
||||
right_column_2_x,
|
||||
board_y + square_width + (2. * square_width - 2. * btn_h) / 2.,
|
||||
btn_w,
|
||||
2. * btn_h,
|
||||
),
|
||||
30.,
|
||||
0.50 * btn_h,
|
||||
&self.resources,
|
||||
);
|
||||
|
||||
// Right column 3
|
||||
let right_column_3_x = right_column_2_x + btn_w;
|
||||
w_label!(self, label_max_age).initialize_drawables(
|
||||
w_label!(self, label_max_age).place(
|
||||
Rect::new(
|
||||
right_column_2_x + btn_w,
|
||||
board_y + (square_width + btn_h) / 2.,
|
||||
@@ -152,14 +162,14 @@ impl Game {
|
||||
0.30 * btn_h,
|
||||
&self.resources,
|
||||
);
|
||||
w_counter!(self, counter_moves).initialize_drawables(
|
||||
w_counter!(self, counter_moves).place(
|
||||
Rect::new(
|
||||
right_column_3_x,
|
||||
board_y + square_width + (2. * square_width - 2. * btn_h) / 2.,
|
||||
btn_w,
|
||||
2. * btn_h,
|
||||
),
|
||||
30.,
|
||||
0.50 * btn_h,
|
||||
&self.resources,
|
||||
);
|
||||
}
|
||||
|
||||
+174
-69
@@ -1,7 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::{Game, GameMode, Settings, constants};
|
||||
use crate::{
|
||||
game::{self, Command, w_board, w_button, w_counter},
|
||||
resources::*,
|
||||
game::{self, Command},
|
||||
resources::{self, *},
|
||||
widgets::*,
|
||||
};
|
||||
use macroquad::prelude::*;
|
||||
@@ -11,80 +13,175 @@ use sol_lib::{
|
||||
};
|
||||
|
||||
impl Game {
|
||||
pub async fn new() -> Self {
|
||||
let resources = resources::init().await;
|
||||
let game_mode = GameMode::Medium;
|
||||
let settings = Settings {
|
||||
volume: constants::VOLUME,
|
||||
max_age: 3,
|
||||
max_pieces: 2,
|
||||
..Default::default()
|
||||
};
|
||||
let puzzle = generate_new_puzzle(game_mode, &settings);
|
||||
let game_mode = GameMode::Medium;
|
||||
let show_rules = false;
|
||||
|
||||
let mut widgets = HashMap::new();
|
||||
|
||||
let w_label_heading = LabelWidget::new(constants::HEADING_TEXT);
|
||||
let label_heading = add_widget(&mut widgets, Widget::Label(w_label_heading));
|
||||
|
||||
let w_label_pieces = LabelWidget::new(constants::PIECES_LABEL_TEXT);
|
||||
let label_pieces = add_widget(&mut widgets, Widget::Label(w_label_pieces));
|
||||
|
||||
let w_label_max_age = LabelWidget::new(constants::AGE_LABEL_TEXT);
|
||||
let label_max_age = add_widget(&mut widgets, Widget::Label(w_label_max_age));
|
||||
|
||||
let mut w_counter_pieces =
|
||||
CounterWidget::new(2, 7, settings.max_pieces, false, UiColor::Yellow);
|
||||
w_counter_pieces.on_increment = |c| Command::UpdateMaxPieceCount(c.current);
|
||||
w_counter_pieces.on_decrement = |c| Command::UpdateMaxPieceCount(c.current);
|
||||
let counter_pieces = add_widget(&mut widgets, Widget::Counter(w_counter_pieces));
|
||||
|
||||
let mut w_counter_moves =
|
||||
CounterWidget::new(1, 7, settings.max_age, false, UiColor::Yellow);
|
||||
w_counter_moves.on_increment = |c| Command::UpdateMaxAge(c.current);
|
||||
w_counter_moves.on_decrement = |c| Command::UpdateMaxAge(c.current);
|
||||
let counter_moves = add_widget(&mut widgets, Widget::Counter(w_counter_moves));
|
||||
|
||||
let mut w_btn_reset = ButtonWidget::new(
|
||||
true,
|
||||
UiColor::Yellow,
|
||||
constants::RESET_BUTTON_TEXT,
|
||||
SoundKind::Button,
|
||||
);
|
||||
w_btn_reset.on_click = |_| Command::ResetBoard;
|
||||
let btn_reset = add_widget(&mut widgets, Widget::Button(w_btn_reset));
|
||||
|
||||
let mut w_btn_next = ButtonWidget::new(
|
||||
false,
|
||||
UiColor::Green,
|
||||
constants::NEXT_BUTTON_TEXT,
|
||||
SoundKind::Button,
|
||||
);
|
||||
w_btn_next.on_click = |_| Command::NextPuzzle;
|
||||
let btn_next = add_widget(&mut widgets, Widget::Button(w_btn_next));
|
||||
|
||||
let mut w_btn_rules = ButtonWidget::new(
|
||||
true,
|
||||
UiColor::Brown,
|
||||
constants::RULES_BUTTON_TEXT,
|
||||
SoundKind::Button,
|
||||
);
|
||||
w_btn_rules.on_click = |_| Command::ToggleRules;
|
||||
let btn_rules = add_widget(&mut widgets, Widget::Button(w_btn_rules));
|
||||
|
||||
let mut w_btn_generate = ButtonWidget::new(
|
||||
false,
|
||||
UiColor::Pink,
|
||||
constants::GENERATE_BUTTON_TEXT,
|
||||
SoundKind::Button,
|
||||
);
|
||||
w_btn_generate.on_click = |_| Command::NewCustomPuzzle;
|
||||
let btn_generate = add_widget(&mut widgets, Widget::Button(w_btn_generate));
|
||||
|
||||
let mut game_mode_btns = HashMap::new();
|
||||
|
||||
let mut w_game_mode_easy_btn = ButtonWidget::new(
|
||||
true,
|
||||
UiColor::Yellow,
|
||||
constants::EASY_BUTTON_TEXT,
|
||||
SoundKind::Mode,
|
||||
);
|
||||
w_game_mode_easy_btn.on_click = |_| Command::SwitchGameMode(GameMode::Easy);
|
||||
game_mode_btns.insert(
|
||||
GameMode::Easy,
|
||||
add_widget(&mut widgets, Widget::Button(w_game_mode_easy_btn)),
|
||||
);
|
||||
|
||||
let mut w_game_mode_medium_btn = ButtonWidget::new(
|
||||
true,
|
||||
UiColor::Yellow,
|
||||
constants::MEDIUM_BUTTON_TEXT,
|
||||
SoundKind::Mode,
|
||||
);
|
||||
w_game_mode_medium_btn.on_click = |_| Command::SwitchGameMode(GameMode::Medium);
|
||||
game_mode_btns.insert(
|
||||
GameMode::Medium,
|
||||
add_widget(&mut widgets, Widget::Button(w_game_mode_medium_btn)),
|
||||
);
|
||||
|
||||
let mut w_game_mode_hard_btn = ButtonWidget::new(
|
||||
true,
|
||||
UiColor::Yellow,
|
||||
constants::HARD_BUTTON_TEXT,
|
||||
SoundKind::Mode,
|
||||
);
|
||||
w_game_mode_hard_btn.on_click = |_| Command::SwitchGameMode(GameMode::Hard);
|
||||
game_mode_btns.insert(
|
||||
GameMode::Hard,
|
||||
add_widget(&mut widgets, Widget::Button(w_game_mode_hard_btn)),
|
||||
);
|
||||
|
||||
let mut w_game_mode_custom_btn = ButtonWidget::new(
|
||||
true,
|
||||
UiColor::Blue,
|
||||
constants::CUSTOM_BUTTON_TEXT,
|
||||
SoundKind::Mode,
|
||||
);
|
||||
w_game_mode_custom_btn.on_click = |_| Command::SwitchGameMode(GameMode::Custom);
|
||||
game_mode_btns.insert(
|
||||
GameMode::Custom,
|
||||
add_widget(&mut widgets, Widget::Button(w_game_mode_custom_btn)),
|
||||
);
|
||||
|
||||
let active_game_mode_btn = game_mode_btns.get(&game_mode).unwrap();
|
||||
game::button(&mut widgets, *active_game_mode_btn).is_active = false;
|
||||
|
||||
let mut w_board = BoardWidget::new(puzzle.board.size, puzzle.board.clone());
|
||||
w_board.on_board_state_changed = |s| Command::UpdateBoard(s.new_board_state);
|
||||
let board = add_widget(&mut widgets, Widget::Board(w_board));
|
||||
|
||||
let mut w_controls = ControlsWidget::new();
|
||||
w_controls.add(KeyCode::Q, Command::Quit);
|
||||
w_controls.add(KeyCode::Escape, Command::HideRules);
|
||||
w_controls.add(KeyCode::D, Command::ToggleDebug);
|
||||
add_widget(&mut widgets, Widget::Controls(w_controls));
|
||||
|
||||
Game {
|
||||
puzzle,
|
||||
board,
|
||||
resources,
|
||||
settings,
|
||||
game_mode,
|
||||
game_mode_btns,
|
||||
btn_reset,
|
||||
btn_next,
|
||||
btn_rules,
|
||||
show_rules,
|
||||
widgets,
|
||||
counter_pieces,
|
||||
counter_moves,
|
||||
btn_generate,
|
||||
label_pieces,
|
||||
label_max_age,
|
||||
label_heading,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, interaction: Interaction) {
|
||||
let command = self.get_command(interaction);
|
||||
let command = self.map_to_command(interaction);
|
||||
self.update_state(command);
|
||||
}
|
||||
|
||||
fn get_command(&mut self, interaction: Interaction) -> Command {
|
||||
|
||||
fn map_to_command(&mut self, interaction: Interaction) -> Command {
|
||||
for (_, widget) in &mut self.widgets {
|
||||
let cmd = widget.update(&interaction, &self.resources, &self.settings);
|
||||
let ret_cmd = match cmd {
|
||||
Command::NoInteraction => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
if ret_cmd {
|
||||
return cmd;
|
||||
if let Some(command) = widget.update(&interaction, &self.resources, &self.settings) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
|
||||
let board_interaction =
|
||||
w_board!(self, board).handle_input(&interaction, &self.resources, &self.settings);
|
||||
if let Some(new_board_state) = board_interaction.new_board_state {
|
||||
return Command::UpdateBoard(new_board_state);
|
||||
}
|
||||
|
||||
if w_button!(self, btn_reset)
|
||||
.handle_input(&interaction, &self.resources, &self.settings)
|
||||
.clicked
|
||||
{
|
||||
return Command::ResetBoard;
|
||||
}
|
||||
|
||||
if w_button!(self, btn_next)
|
||||
.handle_input(&interaction, &self.resources, &self.settings)
|
||||
.clicked
|
||||
{
|
||||
return Command::NextPuzzle;
|
||||
}
|
||||
|
||||
for (mode, btn) in &mut self.game_mode_btns {
|
||||
if game::button(&mut self.widgets, *btn)
|
||||
.handle_input(&interaction, &self.resources, &self.settings)
|
||||
.clicked
|
||||
{
|
||||
return Command::SwitchGameMode(*mode);
|
||||
}
|
||||
}
|
||||
|
||||
if w_button!(self, btn_rules)
|
||||
.handle_input(&interaction, &self.resources, &self.settings)
|
||||
.clicked
|
||||
{
|
||||
return Command::ToggleRules;
|
||||
}
|
||||
|
||||
if w_button!(self, btn_generate)
|
||||
.handle_input(&interaction, &self.resources, &self.settings)
|
||||
.clicked
|
||||
{
|
||||
return Command::NewCustomPuzzle;
|
||||
}
|
||||
|
||||
if interaction.keys_released.contains(&KeyCode::Escape) {
|
||||
return Command::HideRules;
|
||||
}
|
||||
|
||||
if interaction.keys_released.contains(&KeyCode::D) {
|
||||
return Command::ToggleDebug;
|
||||
}
|
||||
|
||||
if interaction.keys_released.contains(&KeyCode::Q) {
|
||||
return Command::Quit;
|
||||
}
|
||||
|
||||
return Command::NoInteraction;
|
||||
}
|
||||
|
||||
@@ -177,7 +274,15 @@ impl Game {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_new_puzzle(mode: GameMode, settings: &Settings) -> Puzzle {
|
||||
fn add_widget(widgets: &mut HashMap<WidgetId, Widget>, w: Widget) -> WidgetId {
|
||||
let id = rand::rand() as u64;
|
||||
let widget_id = WidgetId(id);
|
||||
widgets.insert(widget_id, w);
|
||||
|
||||
widget_id
|
||||
}
|
||||
|
||||
fn generate_new_puzzle(mode: GameMode, settings: &Settings) -> Puzzle {
|
||||
let piece_count = match mode {
|
||||
GameMode::Easy => 3,
|
||||
GameMode::Medium => 5,
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ use miniquad::date;
|
||||
|
||||
use game::constants;
|
||||
|
||||
use crate::widgets::Interaction;
|
||||
use crate::{game::Game, widgets::Interaction};
|
||||
|
||||
fn window_conf() -> Conf {
|
||||
let window_title = {
|
||||
@@ -31,7 +31,7 @@ fn window_conf() -> Conf {
|
||||
async fn main() {
|
||||
rand::srand(date::now() as u64);
|
||||
let background_color = Color::from_rgba(196, 195, 208, 255);
|
||||
let mut game = game::new_game().await;
|
||||
let mut game = Game::new().await;
|
||||
loop {
|
||||
clear_background(background_color);
|
||||
|
||||
|
||||
+134
-8
@@ -1,16 +1,16 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
mod board;
|
||||
use std::collections::HashSet;
|
||||
mod button;
|
||||
mod controls;
|
||||
mod counter;
|
||||
mod label;
|
||||
|
||||
pub use board::*;
|
||||
|
||||
mod button;
|
||||
pub use button::*;
|
||||
|
||||
mod label;
|
||||
pub use label::*;
|
||||
|
||||
mod counter;
|
||||
pub use controls::*;
|
||||
pub use counter::*;
|
||||
pub use label::*;
|
||||
|
||||
use macroquad::{
|
||||
audio::{self, Sound},
|
||||
@@ -18,6 +18,11 @@ use macroquad::{
|
||||
};
|
||||
use quad_snd::PlaySoundParams;
|
||||
|
||||
use crate::{
|
||||
game::{Command, Settings},
|
||||
resources::Resources,
|
||||
};
|
||||
|
||||
pub struct Interaction {
|
||||
pub mouse_pos: Circle,
|
||||
pub keys_released: HashSet<KeyCode>,
|
||||
@@ -25,6 +30,127 @@ pub struct Interaction {
|
||||
pub mouse_released: HashSet<MouseButton>,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Hash, Default)]
|
||||
pub struct WidgetId(pub u64);
|
||||
|
||||
pub enum Widget {
|
||||
Label(LabelWidget),
|
||||
Counter(CounterWidget),
|
||||
Button(ButtonWidget),
|
||||
Board(BoardWidget),
|
||||
Controls(ControlsWidget),
|
||||
}
|
||||
|
||||
impl Widget {
|
||||
pub fn draw(&mut self, resources: &Resources, settings: &Settings) {
|
||||
match self {
|
||||
Widget::Label(label) => label.draw(&resources),
|
||||
Widget::Counter(counter) => counter.draw(&resources),
|
||||
Widget::Button(btn) => btn.draw(&resources),
|
||||
Widget::Board(board) => board.draw(&resources, &settings),
|
||||
Widget::Controls(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(
|
||||
&mut self,
|
||||
interaction: &Interaction,
|
||||
resources: &Resources,
|
||||
settings: &Settings,
|
||||
) -> Option<Command> {
|
||||
match self {
|
||||
Widget::Label(_) => None,
|
||||
Widget::Counter(c) => handle_counter_input(interaction, c, resources, settings),
|
||||
Widget::Button(b) => handle_button_input(interaction, b, resources, settings),
|
||||
Widget::Board(b) => handle_board_input(interaction, b, resources, settings),
|
||||
Widget::Controls(c) => c.handle_input(interaction),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_board_input(
|
||||
interaction: &Interaction,
|
||||
b: &mut BoardWidget,
|
||||
resources: &Resources,
|
||||
settings: &Settings,
|
||||
) -> Option<Command> {
|
||||
let board_interaction = b.handle_input(interaction, resources, settings);
|
||||
let Some(board_interaction) = board_interaction else {
|
||||
return None;
|
||||
};
|
||||
|
||||
Some((b.on_board_state_changed)(board_interaction))
|
||||
}
|
||||
|
||||
fn handle_counter_input(
|
||||
interaction: &Interaction,
|
||||
counter: &mut CounterWidget,
|
||||
resources: &Resources,
|
||||
settings: &Settings,
|
||||
) -> Option<Command> {
|
||||
let counter_interaction = counter.handle_input(interaction, resources, settings);
|
||||
let Some(interaction_type) = counter_interaction.interaction_type else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let command = match interaction_type {
|
||||
CounterInteractionType::Increment => (counter.on_increment)(counter_interaction),
|
||||
CounterInteractionType::Decrement => (counter.on_decrement)(counter_interaction),
|
||||
};
|
||||
|
||||
Some(command)
|
||||
}
|
||||
|
||||
fn handle_button_input(
|
||||
interaction: &Interaction,
|
||||
button: &mut ButtonWidget,
|
||||
resources: &Resources,
|
||||
settings: &Settings,
|
||||
) -> Option<Command> {
|
||||
let Some(ButtonInteraction { clicked: true }) =
|
||||
button.handle_input(interaction, resources, settings)
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
|
||||
return Some((button.on_click)(button));
|
||||
}
|
||||
|
||||
macro_rules! get_widget_fn {
|
||||
($name:ident, $ret:ty, $variant:path) => {
|
||||
pub fn $name(widgets: &mut HashMap<WidgetId, Widget>, id: WidgetId) -> &mut $ret {
|
||||
match widgets.get_mut(&id) {
|
||||
Some(w) => match w {
|
||||
$variant(v) => return v,
|
||||
_ => panic!("Widget with id {} not found", id.0),
|
||||
},
|
||||
None => panic!("Widget with id {} not found", id.0),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
get_widget_fn!(label, LabelWidget, Widget::Label);
|
||||
get_widget_fn!(button, ButtonWidget, Widget::Button);
|
||||
get_widget_fn!(counter, CounterWidget, Widget::Counter);
|
||||
get_widget_fn!(board, BoardWidget, Widget::Board);
|
||||
|
||||
macro_rules! widget_accessor {
|
||||
($name:ident, $fn:ident) => {
|
||||
macro_rules! $name {
|
||||
($this:expr, $widget_id:ident) => {
|
||||
game::$fn(&mut $this.widgets, $this.$widget_id)
|
||||
};
|
||||
}
|
||||
pub(crate) use $name;
|
||||
};
|
||||
}
|
||||
|
||||
widget_accessor!(w_button, button);
|
||||
widget_accessor!(w_label, label);
|
||||
widget_accessor!(w_counter, counter);
|
||||
widget_accessor!(w_board, board);
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum UiColor {
|
||||
|
||||
+67
-53
@@ -2,7 +2,7 @@ use core::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use crate::{
|
||||
game::{Settings, constants},
|
||||
game::{Command, Settings, constants},
|
||||
resources::{Resources, SoundKind},
|
||||
widgets::*,
|
||||
};
|
||||
@@ -11,12 +11,12 @@ use sol_lib::{
|
||||
generator::Puzzle,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BoardWidget {
|
||||
current_board: Board,
|
||||
square_width: f32,
|
||||
pub num_squares: usize, // this is a constant = 4 for now.
|
||||
pub show_rules: bool,
|
||||
pub on_board_state_changed: fn(BoardInteraction) -> Command,
|
||||
current_board: Board,
|
||||
square_width: f32,
|
||||
rules_font_size: f32,
|
||||
board_rect: Rect,
|
||||
squares: Vec<GameSquare>,
|
||||
@@ -24,23 +24,18 @@ pub struct BoardWidget {
|
||||
}
|
||||
|
||||
pub struct BoardInteraction {
|
||||
pub new_board_state: Option<BoardState>,
|
||||
pub new_board_state: BoardState,
|
||||
}
|
||||
|
||||
impl BoardWidget {
|
||||
pub fn initialize_state(num_squares: usize, current_board: Board) -> BoardWidget {
|
||||
pub fn new(num_squares: usize, current_board: Board) -> BoardWidget {
|
||||
let mut board = BoardWidget::default();
|
||||
board.num_squares = num_squares;
|
||||
board.current_board = current_board;
|
||||
board
|
||||
}
|
||||
|
||||
pub fn initialize_drawables(
|
||||
&mut self,
|
||||
square_width: f32,
|
||||
board_rect: Rect,
|
||||
rules_font_size: f32,
|
||||
) {
|
||||
pub fn place(&mut self, square_width: f32, board_rect: Rect, rules_font_size: f32) {
|
||||
self.square_width = square_width;
|
||||
self.board_rect = board_rect;
|
||||
self.rules_font_size = rules_font_size;
|
||||
@@ -169,49 +164,18 @@ 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();
|
||||
let hover_square = self.squares.iter().find(|s| {
|
||||
let c = Circle::new(mx, my, 0.0);
|
||||
if c.overlaps_rect(&s.rect) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
debug_lines.push(format!("Game State: {}", self.state));
|
||||
debug_lines.push(format!("Board State: {}", self.current_board.game_state));
|
||||
if let Some(hover_square) = hover_square {
|
||||
debug_lines.push(format!("Hover: [ {}, {} ]", hover_square.i, hover_square.j));
|
||||
}
|
||||
self.add_debug_info(debug_lines);
|
||||
}
|
||||
|
||||
fn add_debug_info(&self, lines: Vec<String>) {
|
||||
let mut y = 20.0;
|
||||
for line in lines {
|
||||
draw_text(&line, 10.0, y, 20.0, BLACK);
|
||||
y += 25.0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_input(
|
||||
&mut self,
|
||||
interaction: &Interaction,
|
||||
resources: &Resources,
|
||||
settings: &Settings,
|
||||
) -> BoardInteraction {
|
||||
) -> Option<BoardInteraction> {
|
||||
let mouse_pos = interaction.mouse_pos;
|
||||
if mouse_pos.overlaps_rect(&self.board_rect) == false {
|
||||
return BoardInteraction {
|
||||
new_board_state: None,
|
||||
};
|
||||
return None;
|
||||
}
|
||||
|
||||
let old_board_state = self.current_board.state;
|
||||
if is_mouse_button_released(MouseButton::Left) {
|
||||
let current_state = self.state.clone();
|
||||
let new_state = match current_state {
|
||||
@@ -247,10 +211,44 @@ impl BoardWidget {
|
||||
self.state = new_state;
|
||||
}
|
||||
|
||||
let board_state = &self.current_board.game_state;
|
||||
return BoardInteraction {
|
||||
new_board_state: Some(*board_state),
|
||||
};
|
||||
if old_board_state == self.current_board.state {
|
||||
return None;
|
||||
}
|
||||
|
||||
let board_state = self.current_board.state;
|
||||
return Some(BoardInteraction {
|
||||
new_board_state: board_state,
|
||||
});
|
||||
}
|
||||
|
||||
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();
|
||||
let hover_square = self.squares.iter().find(|s| {
|
||||
let c = Circle::new(mx, my, 0.0);
|
||||
if c.overlaps_rect(&s.rect) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
debug_lines.push(format!("Game State: {}", self.state));
|
||||
debug_lines.push(format!("Board State: {}", self.current_board.state));
|
||||
if let Some(hover_square) = hover_square {
|
||||
debug_lines.push(format!("Hover: [ {}, {} ]", hover_square.i, hover_square.j));
|
||||
}
|
||||
self.add_debug_info(debug_lines);
|
||||
}
|
||||
|
||||
fn add_debug_info(&self, lines: Vec<String>) {
|
||||
let mut y = 20.0;
|
||||
for line in lines {
|
||||
draw_text(&line, 10.0, y, 20.0, BLACK);
|
||||
y += 25.0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self, puzzle: &Puzzle) {
|
||||
@@ -337,11 +335,11 @@ impl BoardWidget {
|
||||
let m = m.expect("legal move should be found");
|
||||
self.current_board.make_move(m.clone());
|
||||
|
||||
if self.current_board.game_state == BoardState::Won
|
||||
|| self.current_board.game_state == BoardState::Lost
|
||||
if self.current_board.state == BoardState::Won
|
||||
|| self.current_board.state == BoardState::Lost
|
||||
{
|
||||
self.reset_squares();
|
||||
if self.current_board.game_state == BoardState::Won {
|
||||
if self.current_board.state == BoardState::Won {
|
||||
play_sound_once(resources.sound(&SoundKind::Win), settings.volume);
|
||||
} else {
|
||||
play_sound_once(resources.sound(&SoundKind::Loss), settings.volume);
|
||||
@@ -431,3 +429,19 @@ struct PieceDrawTextureParams<'a> {
|
||||
texture: &'a Texture2D,
|
||||
draw_text_params: DrawTextureParams,
|
||||
}
|
||||
|
||||
impl Default for BoardWidget {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
on_board_state_changed: |_| Command::NoInteraction,
|
||||
num_squares: Default::default(),
|
||||
show_rules: Default::default(),
|
||||
current_board: Default::default(),
|
||||
square_width: Default::default(),
|
||||
rules_font_size: Default::default(),
|
||||
board_rect: Default::default(),
|
||||
squares: Default::default(),
|
||||
state: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+33
-21
@@ -12,6 +12,7 @@ pub struct ButtonWidget {
|
||||
rect: Rect,
|
||||
shadow_width: f32,
|
||||
sound: SoundKind,
|
||||
font_size: FontSize,
|
||||
pub on_click: fn(&mut ButtonWidget) -> Command,
|
||||
}
|
||||
|
||||
@@ -20,15 +21,17 @@ pub struct ButtonInteraction {
|
||||
}
|
||||
|
||||
impl ButtonInteraction {
|
||||
fn not_clicked() -> Self {
|
||||
Self { clicked: false }
|
||||
}
|
||||
|
||||
fn clicked() -> Self {
|
||||
Self { clicked: true }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum FontSize {
|
||||
Fixed(f32),
|
||||
Fill,
|
||||
}
|
||||
|
||||
impl ButtonWidget {
|
||||
pub fn new(is_active: bool, color: UiColor, text: impl Into<String>, sound: SoundKind) -> Self {
|
||||
Self {
|
||||
@@ -41,8 +44,9 @@ impl ButtonWidget {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn place(&mut self, rect: Rect) {
|
||||
pub fn place(&mut self, rect: Rect, font_size: FontSize) {
|
||||
self.rect = rect;
|
||||
self.font_size = font_size;
|
||||
}
|
||||
|
||||
pub fn draw(&self, resources: &Resources) {
|
||||
@@ -86,19 +90,26 @@ impl ButtonWidget {
|
||||
};
|
||||
|
||||
let font = resources.font();
|
||||
let target_w = self.rect.w * 0.9;
|
||||
let target_h = self.rect.h;
|
||||
let mut font_size = 20;
|
||||
let mut dims = measure_text(&text, Some(&font), font_size, 1.0);
|
||||
loop {
|
||||
if dims.width <= target_w && dims.height <= target_h {
|
||||
break;
|
||||
let font_size = match self.font_size {
|
||||
FontSize::Fixed(s) => s as u16,
|
||||
FontSize::Fill => {
|
||||
let target_w = self.rect.w * 0.9;
|
||||
let target_h = self.rect.h;
|
||||
let mut font_size = 22;
|
||||
loop {
|
||||
font_size -= 2;
|
||||
let dims = measure_text(&text, Some(&font), font_size as u16, 1.0);
|
||||
|
||||
if dims.width <= target_w && dims.height <= target_h {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
font_size
|
||||
}
|
||||
};
|
||||
|
||||
font_size -= 2;
|
||||
dims = measure_text(&text, Some(&font), font_size as u16, 1.0);
|
||||
}
|
||||
|
||||
let dims = measure_text(&text, Some(&font), font_size, 1.0);
|
||||
let button_draw_offset = self.get_button_draw_offset();
|
||||
let text_params = TextParams {
|
||||
font_size,
|
||||
@@ -130,17 +141,17 @@ impl ButtonWidget {
|
||||
interaction: &Interaction,
|
||||
resources: &Resources,
|
||||
settings: &Settings,
|
||||
) -> ButtonInteraction {
|
||||
) -> Option<ButtonInteraction> {
|
||||
if !self.is_active {
|
||||
self.is_down = false;
|
||||
return ButtonInteraction::not_clicked();
|
||||
return None;
|
||||
}
|
||||
|
||||
let mouse = interaction.mouse_pos;
|
||||
if interaction.mouse_pressed.contains(&MouseButton::Left) {
|
||||
if mouse.overlaps_rect(&self.rect) {
|
||||
self.is_down = true;
|
||||
return ButtonInteraction::not_clicked();
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,13 +161,13 @@ impl ButtonWidget {
|
||||
let volume = settings.volume;
|
||||
play_sound_once(&click_sound, volume);
|
||||
self.is_down = false;
|
||||
return ButtonInteraction::clicked();
|
||||
return Some(ButtonInteraction::clicked());
|
||||
}
|
||||
|
||||
self.is_down = false;
|
||||
}
|
||||
|
||||
ButtonInteraction::not_clicked()
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,6 +181,7 @@ impl Default for ButtonWidget {
|
||||
color: UiColor::Grey,
|
||||
text: String::new(),
|
||||
sound: SoundKind::Click,
|
||||
font_size: FontSize::Fill,
|
||||
on_click: |_| Command::NoInteraction,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use macroquad::input::KeyCode;
|
||||
|
||||
use crate::{game::Command, widgets::Interaction};
|
||||
|
||||
pub struct ControlsWidget {
|
||||
key_release_bindings: HashMap<KeyCode, Command>,
|
||||
}
|
||||
|
||||
impl ControlsWidget {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
key_release_bindings: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, key: KeyCode, command: Command) {
|
||||
self.key_release_bindings.insert(key, command);
|
||||
}
|
||||
|
||||
pub fn handle_input(&self, interaction: &Interaction) -> Option<Command> {
|
||||
for (key, command) in &self.key_release_bindings {
|
||||
if interaction.keys_released.contains(&key) {
|
||||
return Some(*command);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
+16
-36
@@ -77,12 +77,7 @@ impl CounterWidget {
|
||||
self.decrement.is_active = is_active;
|
||||
}
|
||||
|
||||
pub fn initialize_drawables(
|
||||
&mut self,
|
||||
total_area: Rect,
|
||||
font_size: f32,
|
||||
resources: &Resources,
|
||||
) {
|
||||
pub fn place(&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;
|
||||
@@ -94,10 +89,10 @@ impl CounterWidget {
|
||||
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.place(increment_rect);
|
||||
self.increment.place(increment_rect, FontSize::Fill);
|
||||
|
||||
let decrement_rect = Rect::new(btn_x, decrement_y, btn_w, btn_h);
|
||||
self.decrement.place(decrement_rect);
|
||||
self.decrement.place(decrement_rect, FontSize::Fill);
|
||||
|
||||
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);
|
||||
@@ -112,25 +107,27 @@ impl CounterWidget {
|
||||
resources: &Resources,
|
||||
settings: &Settings,
|
||||
) -> CounterWidgetInteraction {
|
||||
if self
|
||||
if let Some(interaction) = self
|
||||
.increment
|
||||
.handle_input(&interaction, &resources, &settings)
|
||||
.clicked
|
||||
{
|
||||
if self.current < self.max {
|
||||
self.current += 1;
|
||||
return CounterWidgetInteraction::increment(self.current);
|
||||
if interaction.clicked {
|
||||
if self.current < self.max {
|
||||
self.current += 1;
|
||||
return CounterWidgetInteraction::increment(self.current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self
|
||||
if let Some(interaction) = self
|
||||
.decrement
|
||||
.handle_input(&interaction, &resources, &settings)
|
||||
.clicked
|
||||
{
|
||||
if self.current > self.min {
|
||||
self.current -= 1;
|
||||
return CounterWidgetInteraction::decrement(self.current);
|
||||
if interaction.clicked {
|
||||
if self.current > self.min {
|
||||
self.current -= 1;
|
||||
return CounterWidgetInteraction::decrement(self.current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,24 +138,7 @@ impl CounterWidget {
|
||||
self.increment.draw(resources);
|
||||
self.decrement.draw(resources);
|
||||
|
||||
let font = resources.font();
|
||||
let mut min_dim = self.visual_rect.w.min(self.visual_rect.h);
|
||||
let mut font_size = self.font_size as u16;
|
||||
loop {
|
||||
if min_dim <= self.visual_rect.w * 0.5 {
|
||||
break;
|
||||
}
|
||||
|
||||
let dims = measure_text(
|
||||
&self.current.to_string(),
|
||||
Some(&font),
|
||||
font_size as u16,
|
||||
1.0,
|
||||
);
|
||||
min_dim = dims.width.min(dims.height);
|
||||
font_size -= 1;
|
||||
}
|
||||
|
||||
let font_size = self.font_size as u16;
|
||||
draw_text_ex(
|
||||
&self.current.to_string(),
|
||||
self.visual_rect.x + (self.visual_rect.w - self.visual_dims.width) / 2.,
|
||||
|
||||
@@ -11,14 +11,14 @@ pub struct LabelWidget {
|
||||
}
|
||||
|
||||
impl LabelWidget {
|
||||
pub fn initialize_state(text: &str) -> Self {
|
||||
pub fn new(text: &str) -> Self {
|
||||
Self {
|
||||
text: text.to_string(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize_drawables(&mut self, rect: Rect, font_size: f32, resources: &Resources) {
|
||||
pub fn place(&mut self, rect: Rect, font_size: f32, resources: &Resources) {
|
||||
self.rect = rect;
|
||||
self.font_size = font_size;
|
||||
self.text_dimensions =
|
||||
|
||||
Reference in New Issue
Block a user