Random cards

This commit is contained in:
Tobias Berger 2024-04-09 19:41:22 +02:00
parent b931079a71
commit c9438aa49d
Signed by: toby
GPG key ID: 2D05EFAB764D6A88
4 changed files with 133 additions and 28 deletions

23
Cargo.lock generated
View file

@ -95,6 +95,7 @@ name = "ants"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"nannou", "nannou",
"rand_derive2",
] ]
[[package]] [[package]]
@ -1580,6 +1581,16 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "proc_macro2_helper"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79528bef70da112116feb5ecb6b64f1394e5360660d6474a760789ea07885501"
dependencies = [
"proc-macro2",
"syn 2.0.58",
]
[[package]] [[package]]
name = "profiling" name = "profiling"
version = "1.0.15" version = "1.0.15"
@ -1657,6 +1668,18 @@ dependencies = [
"getrandom 0.2.14", "getrandom 0.2.14",
] ]
[[package]]
name = "rand_derive2"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e07d80c051ce2007c5cbb87ae0a6be7c5e5345cb03e06717b64ed5c426cbfb3"
dependencies = [
"proc-macro2",
"proc_macro2_helper",
"quote",
"syn 2.0.58",
]
[[package]] [[package]]
name = "rand_hc" name = "rand_hc"
version = "0.2.0" version = "0.2.0"

View file

@ -27,3 +27,6 @@ codegen-units = 1
[dependencies.nannou] [dependencies.nannou]
version = "0.19" version = "0.19"
[dependencies.rand_derive2]
version = "0.1"

View file

@ -1,12 +1,17 @@
#![warn(clippy::all, clippy::pedantic, clippy::nursery)] #![warn(clippy::all, clippy::pedantic, clippy::nursery)]
mod card;
pub(crate) mod rect_helper; pub(crate) mod rect_helper;
use std::sync::RwLock;
use crate::rect_helper::RectHelper; use crate::rect_helper::RectHelper;
use card::Card;
use nannou::{ use nannou::{
image::{self, ImageFormat}, image::{self, ImageFormat},
prelude::*, prelude::*,
text::Font, text::Font,
winit::window::CursorIcon,
}; };
fn main() { fn main() {
@ -22,7 +27,8 @@ struct Model {
font: Font, font: Font,
texture: wgpu::Texture, texture: wgpu::Texture,
ups: f64, ups: f64,
ant_count: u8, just_clicked: RwLock<bool>,
hand: [Card; HAND_CARD_COUNT],
} }
impl Model { impl Model {
@ -56,53 +62,101 @@ impl Model {
))) )))
.expect("Failed to load font"), .expect("Failed to load font"),
ups: 0f64, ups: 0f64,
ant_count: 1, just_clicked: RwLock::new(false),
hand: random(),
} }
} }
} }
fn update(_app: &App, model: &mut Model, update: Update) { fn update(_app: &App, model: &mut Model, update: Update) {
model.ups = (1f64 / update.since_last.as_secs_f64()).round(); model.ups = (1f64 / update.since_last.as_secs_f64()).round();
let new_ant_count = ((update.since_start.as_secs() + 1) % 12)
.try_into()
.expect("Failed to convert number to u8");
if model.ant_count != new_ant_count {
model.ant_count = new_ant_count;
}
} }
// Handle events related to the window and update the model if necessary // Handle events related to the window and update the model if necessary
fn event(_app: &App, _model: &mut Model, event: WindowEvent) { fn event(_app: &App, model: &mut Model, event: WindowEvent) {
match event {
MousePressed(MouseButton::Left) => {
let mut just_clicked = model.just_clicked.write().expect("click handler poisoned");
if !*just_clicked {
*just_clicked = true;
}
}
MouseReleased(MouseButton::Left) => {
let mut just_clicked = model.just_clicked.write().expect("click handler poisoned");
if *just_clicked {
*just_clicked = false;
}
}
KeyPressed(Key::R) => {
model.hand = random();
}
_ => {}
}
drop(event); drop(event);
} }
const HAND_COUNT: usize = 8; const HAND_CARD_COUNT: usize = 8;
const HAND_ASPECT_WIDTH: f32 = 1f32;
const HAND_ASPECT_HEIGHT: f32 = 2f32;
// Draw the state of your `Model` into the given `Frame` here. // Draw the state of your `Model` into the given `Frame` here.
fn view(app: &App, model: &Model, frame: Frame) { fn view(app: &App, model: &Model, frame: Frame) {
let window = app.window(model.window).unwrap(); let window = app.window(model.window).unwrap();
window.set_cursor_icon(CursorIcon::Default);
frame.clear(BLACK); frame.clear(BLACK);
let mut can_click = *model.just_clicked.read().expect("click handler poisoned");
let mouse = &app.mouse;
let mouse_position = if mouse.window == Some(model.window) {
Some(mouse.position())
} else {
None
};
let draw = app.draw(); let draw = app.draw();
let rect = window.rect().bottom_part(0.2); let window_rect = window.rect();
draw.rect().wh(rect.wh()).xy(rect.xy()).color(RED).finish(); let hand_bounds = window_rect.bottom_part(0.3);
let rect = window.rect().left_part(0.2); #[allow(clippy::cast_precision_loss)]
draw.rect().wh(rect.wh()).xy(rect.xy()).color(BLUE).finish(); let hand_rect = Rect::from_x_y_w_h(
let rect = window.rect().right_part(0.2); hand_bounds.x(),
draw.rect() hand_bounds.y(),
.wh(rect.wh()) HAND_CARD_COUNT as f32 * HAND_ASPECT_WIDTH,
.xy(rect.xy()) HAND_ASPECT_HEIGHT,
.color(YELLOW) )
.finish(); .fit_into(&hand_bounds)
let rect = window.rect().top_part(0.2); .align_bottom_of(hand_bounds);
draw.rect()
.wh(rect.wh())
.xy(rect.xy())
.color(GREEN)
.finish();
for rect in rect.split_horizontal::<HAND_COUNT>() { for (idx, rect) in hand_rect
draw.texture(&model.texture).xy(rect.xy()).wh(rect.wh()); .split_horizontal::<HAND_CARD_COUNT>()
.iter()
.enumerate()
{
#[allow(clippy::cast_precision_loss)]
draw.rect()
.xy(rect.xy())
.wh(rect.wh())
.color(model.hand[idx].color());
let image_rect = Rect::from_x_y_w_h(rect.x(), rect.y(), 1401f32, 1061f32)
.fit_into(rect)
.align_bottom_of(*rect);
draw.texture(&model.texture)
.xy(image_rect.xy())
.wh(image_rect.wh());
if matches!(mouse_position, Some(mouse_position) if rect.contains(mouse_position)) {
window.set_cursor_icon(CursorIcon::Hand);
if can_click {
println!(
"Click! {idx} {:?} {:?}",
model.hand[idx],
model.hand[idx].color()
);
can_click = false;
}
}
} }
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
@ -113,6 +167,8 @@ fn view(app: &App, model: &Model, frame: Frame) {
.left_justify(); .left_justify();
} }
*model.just_clicked.write().expect("click handler poisoned") = false;
draw.to_frame(app, &frame).unwrap(); draw.to_frame(app, &frame).unwrap();
drop(frame); drop(frame);
} }

View file

@ -1,6 +1,8 @@
use nannou::geom::Rect; use nannou::geom::Rect;
pub trait RectHelper { pub trait RectHelper {
fn fit_into(&self, bounds: &Rect<f32>) -> Rect<f32>;
fn bottom_half(&self) -> Rect<f32>; fn bottom_half(&self) -> Rect<f32>;
fn bottom_part(&self, part: f32) -> Rect<f32>; fn bottom_part(&self, part: f32) -> Rect<f32>;
@ -20,6 +22,27 @@ pub trait RectHelper {
} }
impl RectHelper for Rect<f32> { impl RectHelper for Rect<f32> {
fn fit_into(&self, bounds: &Rect<f32>) -> Self {
let content_aspect_ratio = self.w() / self.h();
let bounds_aspect_ratio = bounds.w() / bounds.h();
if bounds_aspect_ratio > content_aspect_ratio {
Self::from_x_y_w_h(
self.x(),
self.y(),
self.w() * bounds.h() / self.h(),
bounds.h(),
)
} else {
Self::from_x_y_w_h(
self.x(),
self.y(),
bounds.w(),
self.h() * bounds.w() / self.w(),
)
}
}
fn bottom_half(&self) -> Self { fn bottom_half(&self) -> Self {
Self::from_corners(self.mid_left(), self.bottom_right()) Self::from_corners(self.mid_left(), self.bottom_right())
} }