Placeholder castle

This commit is contained in:
Tobias Berger 2024-04-11 14:15:59 +02:00
parent 78e4dedf21
commit e64742a159
Signed by: toby
GPG key ID: 2D05EFAB764D6A88
4 changed files with 165 additions and 110 deletions

4
Cargo.lock generated
View file

@ -1599,9 +1599,9 @@ checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58"
[[package]]
name = "quote"
version = "1.0.35"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]

BIN
assets/images/castle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View file

@ -2,7 +2,8 @@
#![allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::too_many_lines
clippy::too_many_lines,
clippy::module_name_repetitions
)]
mod card;
@ -24,15 +25,48 @@ use player::{Player, Stats};
fn main() {
nannou::app(Model::init)
.update(update)
.loop_mode(LoopMode::RefreshSync)
.loop_mode(LoopMode::Wait)
.run();
}
struct Textures {
ant: wgpu::Texture,
castle: wgpu::Texture,
}
impl Textures {
fn load(app: &App) -> Self {
let ant = wgpu::Texture::from_image(
app,
&image::load_from_memory_with_format(
include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/assets/images/ant.png"
)),
ImageFormat::Png,
)
.expect("Failed to load image"),
);
let castle = wgpu::Texture::from_image(
app,
&image::load_from_memory_with_format(
include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/assets/images/castle.png"
)),
ImageFormat::Png,
)
.expect("Failed to load image"),
);
Self { ant, castle }
}
}
struct Model {
// Store the window ID so we can refer to this specific window later if needed.
window: WindowId,
font: Font,
texture: wgpu::Texture,
textures: Textures,
ups: f64,
just_clicked: RwLock<bool>,
red_hand: RwLock<[Card; HAND_CARD_COUNT]>,
@ -53,20 +87,9 @@ impl Model {
.build()
.unwrap();
let texture = wgpu::Texture::from_image(
app,
&image::load_from_memory_with_format(
include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/assets/images/ant.png"
)),
ImageFormat::Png,
)
.expect("Failed to load image"),
);
Self {
window,
texture,
textures: Textures::load(app),
font: Font::from_bytes(include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/assets/fonts/Monocraft/Monocraft-NF.ttf"
@ -136,56 +159,88 @@ 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.
fn player_panel(
draw: &Draw,
bounds: Rect,
player_stats: &RwLock<Stats>,
player: Player,
font: Font,
) {
let rect = Rect::from_x_y_w_h(bounds.x(), bounds.y(), 1f32, 5f32).fit_into(&bounds);
let rect = match player {
Player::Red => rect.align_right_of(bounds),
Player::Black => rect.align_left_of(bounds),
fn player_panel(model: &Model, draw: &Draw, bounds: Rect, player: Player) {
let part_bounds = bounds.part_horizontal(match player {
Player::Red => 0.8,
Player::Black => 0.2,
});
let [castle_bounds, status_bounds] = match player {
Player::Red => part_bounds,
Player::Black => [part_bounds[1], part_bounds[0]],
};
let player_stats = player_stats.read().expect("player stats poisoned");
let castle_bounds = castle_bounds.top_part(0.7);
let castle_rect = Rect::from_x_y_w_h(
castle_bounds.x(),
castle_bounds.y(),
model.textures.castle.width() as f32,
model.textures.castle.height() as f32,
)
.fit_into(castle_bounds);
draw.texture(&model.textures.castle)
.xy(castle_rect.xy())
.wh(castle_rect.wh())
.finish();
let status_rect = status_bounds
.align_left_of(status_bounds)
.align_middle_y_of(status_bounds);
let player_stats = *model
.stats_of(player)
.read()
.expect("player stats poisoned");
let status = match player {
Player::Red => format!(
"{:<3} Builders\n{:<5} Bricks\n{:<3} Soldiers\n{:<4} Weapons\n{:<7} Magi\n{:<3} Crystals\n{:<5} Castle\n{:<6} Fence",
player_stats.builders,
player_stats.bricks,
player_stats.soldiers,
player_stats.weapons,
player_stats.magi,
player_stats.crystals,
player_stats.castle,
player_stats.fence,
),
Player::Black => format!(
"Builders {:>3}\nBricks {:>5}\nSoldiers {:>3}\nWeapons {:>4}\nMagi {:>7}\nCrystals {:>3}\nCastle {:>5}\nFence {:>6}",
player_stats.builders,
player_stats.bricks,
player_stats.soldiers,
player_stats.weapons,
player_stats.magi,
player_stats.crystals,
player_stats.castle,
player_stats.fence,
)
};
drop(player_stats);
Player::Red => format!(
"{:<3} Builders\n{:<5} Bricks\n{:<3} Soldiers\n{:<4} Weapons\n{:<7} Magi\n{:<3} Crystals\n{:<5} Castle\n{:<6} Fence",
player_stats.builders,
player_stats.bricks,
player_stats.soldiers,
player_stats.weapons,
player_stats.magi,
player_stats.crystals,
player_stats.castle,
player_stats.fence,
),
Player::Black => format!(
"Builders {:>3}\nBricks {:>5}\nSoldiers {:>3}\nWeapons {:>4}\nMagi {:>7}\nCrystals {:>3}\nCastle {:>5}\nFence {:>6}",
player_stats.builders,
player_stats.bricks,
player_stats.soldiers,
player_stats.weapons,
player_stats.magi,
player_stats.crystals,
player_stats.castle,
player_stats.fence,
)
};
let character_size = model
.font
.glyph('A')
.standalone()
.get_data()
.expect("No glyph found")
.extents
.unwrap();
let character_width = character_size.width();
let character_height = character_size.height();
let character_aspect_ratio = character_width as f32 / character_height as f32;
let font_size = f32::min(
status_bounds.w() / 12f32 / character_aspect_ratio,
status_bounds.h() / 8f32,
) as u32;
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let drawing = draw
.text(&status)
.xy(rect.xy())
.wh(rect.wh())
.xy(status_rect.xy())
.wh(status_rect.wh())
.color(WHITE)
.font_size((rect.h() * 0.02f32).trunc() as u32)
.font_size(font_size)
.align_text_middle_y()
.font(font)
.font(model.font.clone())
.color(match player {
Player::Red => RED,
Player::Black => WHITE,
@ -213,14 +268,14 @@ fn hand(
HAND_CARD_COUNT as f32 * HAND_ASPECT_WIDTH,
HAND_ASPECT_HEIGHT,
)
.fit_into(&bounds)
.fit_into(bounds)
.align_bottom_of(bounds);
let current_player = *model
.current_player
.read()
.expect("current player poisoned");
for (idx, rect) in hand_rect
for (idx, &rect) in hand_rect
.split_horizontal::<HAND_CARD_COUNT>()
.iter()
.enumerate()
@ -239,11 +294,11 @@ fn hand(
let image_rect = Rect::from_x_y_w_h(
rect.x(),
rect.y(),
model.texture.width() as f32,
model.texture.height() as f32,
model.textures.ant.width() as f32,
model.textures.ant.height() as f32,
)
.fit_into(rect)
.align_bottom_of(*rect);
.align_bottom_of(rect);
draw.text(&format!(
"{:?}\n{}{}",
@ -275,7 +330,7 @@ fn hand(
.font(model.font.clone())
.finish();
draw.texture(&model.texture)
draw.texture(&model.textures.ant)
.xy(image_rect.xy())
.wh(image_rect.wh())
.finish();
@ -339,22 +394,11 @@ fn view(app: &App, model: &Model, frame: Frame) {
let window_rect = window.rect();
let player_one_bounds = window_rect.left_part(0.2);
player_panel(
&draw,
player_one_bounds,
model.stats_of(Player::Black),
Player::Black,
model.font.clone(),
);
let player_two_bounds = window_rect.right_part(0.2);
player_panel(
&draw,
player_two_bounds,
model.stats_of(Player::Red),
Player::Red,
model.font.clone(),
);
let [player_one_rect, player_two_rect] = window_rect.split_horizontal::<2>();
let player_one_bounds = player_one_rect;
player_panel(model, &draw, player_one_bounds, Player::Black);
let player_two_bounds = player_two_rect;
player_panel(model, &draw, player_two_bounds, Player::Red);
let hand_bounds = window_rect.bottom_part(0.3);
hand(

View file

@ -1,28 +1,31 @@
use nannou::geom::Rect;
use nannou::{geom::Rect, math::num_traits::Float};
pub trait RectHelper {
fn fit_into(&self, bounds: &Rect<f32>) -> Rect<f32>;
pub trait RectHelper<S: Float> {
fn fit_into(self, bounds: Rect<S>) -> Rect<S>;
fn bottom_half(&self) -> Rect<f32>;
fn bottom_part(&self, part: f32) -> Rect<f32>;
fn bottom_half(self) -> Rect<S>;
fn bottom_part(self, part: S) -> Rect<S>;
fn top_half(&self) -> Rect<f32>;
fn top_part(&self, part: f32) -> Rect<f32>;
fn top_half(self) -> Rect<S>;
fn top_part(self, part: S) -> Rect<S>;
fn left_half(&self) -> Rect<f32>;
fn left_part(&self, part: f32) -> Rect<f32>;
fn left_half(self) -> Rect<S>;
fn left_part(self, part: S) -> Rect<S>;
fn right_half(&self) -> Rect<f32>;
fn right_part(&self, part: f32) -> Rect<f32>;
fn right_half(self) -> Rect<S>;
fn right_part(self, part: S) -> Rect<S>;
fn split_horizontal<const N: usize>(&self) -> [Rect<f32>; N];
fn split_vertical<const N: usize>(&self) -> [Rect<f32>; N];
fn split_horizontal_vec(&self, num: usize) -> Vec<Rect<f32>>;
fn split_vertical_vec(&self, num: usize) -> Vec<Rect<f32>>;
fn part_horizontal(self, part: S) -> [Rect<S>; 2];
fn part_vertical(self, part: S) -> [Rect<S>; 2];
fn split_horizontal<const N: usize>(self) -> [Rect<S>; N];
fn split_vertical<const N: usize>(self) -> [Rect<S>; N];
fn split_horizontal_vec(self, num: usize) -> Vec<Rect<S>>;
fn split_vertical_vec(self, num: usize) -> Vec<Rect<S>>;
}
impl RectHelper for Rect<f32> {
fn fit_into(&self, bounds: &Rect<f32>) -> Self {
impl RectHelper<f32> for Rect<f32> {
fn fit_into(self, bounds: Self) -> Self {
let content_aspect_ratio = self.w() / self.h();
let bounds_aspect_ratio = bounds.w() / bounds.h();
@ -43,11 +46,11 @@ impl RectHelper for Rect<f32> {
}
}
fn bottom_half(&self) -> Self {
fn bottom_half(self) -> Self {
Self::from_corners(self.mid_left(), self.bottom_right())
}
fn bottom_part(&self, part: f32) -> Self {
fn bottom_part(self, part: f32) -> Self {
debug_assert!((0f32..=1f32).contains(&part));
Self::from_corner_points(
[self.left(), self.bottom()],
@ -55,11 +58,11 @@ impl RectHelper for Rect<f32> {
)
}
fn top_half(&self) -> Self {
fn top_half(self) -> Self {
Self::from_corners(self.top_left(), self.mid_right())
}
fn top_part(&self, part: f32) -> Self {
fn top_part(self, part: f32) -> Self {
debug_assert!((0f32..=1f32).contains(&part));
Self::from_corner_points(
[self.left(), self.top()],
@ -67,11 +70,11 @@ impl RectHelper for Rect<f32> {
)
}
fn left_half(&self) -> Self {
fn left_half(self) -> Self {
Self::from_corners(self.top_left(), self.mid_bottom())
}
fn left_part(&self, part: f32) -> Self {
fn left_part(self, part: f32) -> Self {
debug_assert!((0f32..=1f32).contains(&part));
Self::from_corner_points(
[self.left(), self.bottom()],
@ -79,11 +82,11 @@ impl RectHelper for Rect<f32> {
)
}
fn right_half(&self) -> Self {
Self::from_corners(self.top_left(), self.mid_bottom())
fn right_half(self) -> Self {
Self::from_corners(self.mid_top(), self.bottom_right())
}
fn right_part(&self, part: f32) -> Self {
fn right_part(self, part: f32) -> Self {
debug_assert!((0f32..=1f32).contains(&part));
Self::from_corner_points(
[self.right(), self.bottom()],
@ -91,8 +94,16 @@ impl RectHelper for Rect<f32> {
)
}
fn part_horizontal(self, part: f32) -> [Self; 2] {
[self.left_part(part), self.right_part(1f32 - part)]
}
fn part_vertical(self, part: f32) -> [Self; 2] {
[self.bottom_part(part), self.top_part(1f32 - part)]
}
#[allow(clippy::cast_precision_loss)]
fn split_horizontal<const N: usize>(&self) -> [Self; N] {
fn split_horizontal<const N: usize>(self) -> [Self; N] {
let mut subdivisions = [unsafe { std::mem::zeroed() }; N];
let subdivided_width = self.w() / N as f32;
@ -108,7 +119,7 @@ impl RectHelper for Rect<f32> {
}
#[allow(clippy::cast_precision_loss)]
fn split_horizontal_vec(&self, num: usize) -> Vec<Self> {
fn split_horizontal_vec(self, num: usize) -> Vec<Self> {
let mut subdivisions = Vec::with_capacity(num);
let subdivided_width = self.w() / num as f32;
@ -124,7 +135,7 @@ impl RectHelper for Rect<f32> {
}
#[allow(clippy::cast_precision_loss)]
fn split_vertical<const N: usize>(&self) -> [Self; N] {
fn split_vertical<const N: usize>(self) -> [Self; N] {
let mut subdivisions = [unsafe { std::mem::zeroed() }; N];
let subdivided_height = self.h() / N as f32;
@ -140,7 +151,7 @@ impl RectHelper for Rect<f32> {
}
#[allow(clippy::cast_precision_loss)]
fn split_vertical_vec(&self, num: usize) -> Vec<Self> {
fn split_vertical_vec(self, num: usize) -> Vec<Self> {
let mut subdivisions = Vec::with_capacity(num);
let subdivided_height = self.h() / num as f32;