Placeholder castle
This commit is contained in:
parent
78e4dedf21
commit
e64742a159
4 changed files with 165 additions and 110 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -1599,9 +1599,9 @@ checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.35"
|
version = "1.0.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
BIN
assets/images/castle.png
Normal file
BIN
assets/images/castle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
154
src/main.rs
154
src/main.rs
|
@ -2,7 +2,8 @@
|
||||||
#![allow(
|
#![allow(
|
||||||
clippy::cast_possible_truncation,
|
clippy::cast_possible_truncation,
|
||||||
clippy::cast_sign_loss,
|
clippy::cast_sign_loss,
|
||||||
clippy::too_many_lines
|
clippy::too_many_lines,
|
||||||
|
clippy::module_name_repetitions
|
||||||
)]
|
)]
|
||||||
|
|
||||||
mod card;
|
mod card;
|
||||||
|
@ -24,15 +25,48 @@ use player::{Player, Stats};
|
||||||
fn main() {
|
fn main() {
|
||||||
nannou::app(Model::init)
|
nannou::app(Model::init)
|
||||||
.update(update)
|
.update(update)
|
||||||
.loop_mode(LoopMode::RefreshSync)
|
.loop_mode(LoopMode::Wait)
|
||||||
.run();
|
.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 {
|
struct Model {
|
||||||
// Store the window ID so we can refer to this specific window later if needed.
|
// Store the window ID so we can refer to this specific window later if needed.
|
||||||
window: WindowId,
|
window: WindowId,
|
||||||
font: Font,
|
font: Font,
|
||||||
texture: wgpu::Texture,
|
textures: Textures,
|
||||||
ups: f64,
|
ups: f64,
|
||||||
just_clicked: RwLock<bool>,
|
just_clicked: RwLock<bool>,
|
||||||
red_hand: RwLock<[Card; HAND_CARD_COUNT]>,
|
red_hand: RwLock<[Card; HAND_CARD_COUNT]>,
|
||||||
|
@ -53,20 +87,9 @@ impl Model {
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.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 {
|
Self {
|
||||||
window,
|
window,
|
||||||
texture,
|
textures: Textures::load(app),
|
||||||
font: Font::from_bytes(include_bytes!(concat!(
|
font: Font::from_bytes(include_bytes!(concat!(
|
||||||
env!("CARGO_MANIFEST_DIR"),
|
env!("CARGO_MANIFEST_DIR"),
|
||||||
"/assets/fonts/Monocraft/Monocraft-NF.ttf"
|
"/assets/fonts/Monocraft/Monocraft-NF.ttf"
|
||||||
|
@ -136,22 +159,37 @@ const HAND_CARD_COUNT: usize = 8;
|
||||||
const HAND_ASPECT_WIDTH: f32 = 1f32;
|
const HAND_ASPECT_WIDTH: f32 = 1f32;
|
||||||
const HAND_ASPECT_HEIGHT: f32 = 2f32;
|
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 player_panel(model: &Model, draw: &Draw, bounds: Rect, player: Player) {
|
||||||
fn player_panel(
|
let part_bounds = bounds.part_horizontal(match player {
|
||||||
draw: &Draw,
|
Player::Red => 0.8,
|
||||||
bounds: Rect,
|
Player::Black => 0.2,
|
||||||
player_stats: &RwLock<Stats>,
|
});
|
||||||
player: Player,
|
let [castle_bounds, status_bounds] = match player {
|
||||||
font: Font,
|
Player::Red => part_bounds,
|
||||||
) {
|
Player::Black => [part_bounds[1], part_bounds[0]],
|
||||||
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),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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 {
|
let status = match player {
|
||||||
Player::Red => format!(
|
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",
|
"{:<3} Builders\n{:<5} Bricks\n{:<3} Soldiers\n{:<4} Weapons\n{:<7} Magi\n{:<3} Crystals\n{:<5} Castle\n{:<6} Fence",
|
||||||
|
@ -176,16 +214,33 @@ fn player_panel(
|
||||||
player_stats.fence,
|
player_stats.fence,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
drop(player_stats);
|
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)]
|
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
|
||||||
let drawing = draw
|
let drawing = draw
|
||||||
.text(&status)
|
.text(&status)
|
||||||
.xy(rect.xy())
|
.xy(status_rect.xy())
|
||||||
.wh(rect.wh())
|
.wh(status_rect.wh())
|
||||||
.color(WHITE)
|
.color(WHITE)
|
||||||
.font_size((rect.h() * 0.02f32).trunc() as u32)
|
.font_size(font_size)
|
||||||
.align_text_middle_y()
|
.align_text_middle_y()
|
||||||
.font(font)
|
.font(model.font.clone())
|
||||||
.color(match player {
|
.color(match player {
|
||||||
Player::Red => RED,
|
Player::Red => RED,
|
||||||
Player::Black => WHITE,
|
Player::Black => WHITE,
|
||||||
|
@ -213,14 +268,14 @@ fn hand(
|
||||||
HAND_CARD_COUNT as f32 * HAND_ASPECT_WIDTH,
|
HAND_CARD_COUNT as f32 * HAND_ASPECT_WIDTH,
|
||||||
HAND_ASPECT_HEIGHT,
|
HAND_ASPECT_HEIGHT,
|
||||||
)
|
)
|
||||||
.fit_into(&bounds)
|
.fit_into(bounds)
|
||||||
.align_bottom_of(bounds);
|
.align_bottom_of(bounds);
|
||||||
|
|
||||||
let current_player = *model
|
let current_player = *model
|
||||||
.current_player
|
.current_player
|
||||||
.read()
|
.read()
|
||||||
.expect("current player poisoned");
|
.expect("current player poisoned");
|
||||||
for (idx, rect) in hand_rect
|
for (idx, &rect) in hand_rect
|
||||||
.split_horizontal::<HAND_CARD_COUNT>()
|
.split_horizontal::<HAND_CARD_COUNT>()
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
@ -239,11 +294,11 @@ fn hand(
|
||||||
let image_rect = Rect::from_x_y_w_h(
|
let image_rect = Rect::from_x_y_w_h(
|
||||||
rect.x(),
|
rect.x(),
|
||||||
rect.y(),
|
rect.y(),
|
||||||
model.texture.width() as f32,
|
model.textures.ant.width() as f32,
|
||||||
model.texture.height() as f32,
|
model.textures.ant.height() as f32,
|
||||||
)
|
)
|
||||||
.fit_into(rect)
|
.fit_into(rect)
|
||||||
.align_bottom_of(*rect);
|
.align_bottom_of(rect);
|
||||||
|
|
||||||
draw.text(&format!(
|
draw.text(&format!(
|
||||||
"{:?}\n{}{}",
|
"{:?}\n{}{}",
|
||||||
|
@ -275,7 +330,7 @@ fn hand(
|
||||||
.font(model.font.clone())
|
.font(model.font.clone())
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
draw.texture(&model.texture)
|
draw.texture(&model.textures.ant)
|
||||||
.xy(image_rect.xy())
|
.xy(image_rect.xy())
|
||||||
.wh(image_rect.wh())
|
.wh(image_rect.wh())
|
||||||
.finish();
|
.finish();
|
||||||
|
@ -339,22 +394,11 @@ fn view(app: &App, model: &Model, frame: Frame) {
|
||||||
|
|
||||||
let window_rect = window.rect();
|
let window_rect = window.rect();
|
||||||
|
|
||||||
let player_one_bounds = window_rect.left_part(0.2);
|
let [player_one_rect, player_two_rect] = window_rect.split_horizontal::<2>();
|
||||||
player_panel(
|
let player_one_bounds = player_one_rect;
|
||||||
&draw,
|
player_panel(model, &draw, player_one_bounds, Player::Black);
|
||||||
player_one_bounds,
|
let player_two_bounds = player_two_rect;
|
||||||
model.stats_of(Player::Black),
|
player_panel(model, &draw, player_two_bounds, Player::Red);
|
||||||
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 hand_bounds = window_rect.bottom_part(0.3);
|
let hand_bounds = window_rect.bottom_part(0.3);
|
||||||
hand(
|
hand(
|
||||||
|
|
|
@ -1,28 +1,31 @@
|
||||||
use nannou::geom::Rect;
|
use nannou::{geom::Rect, math::num_traits::Float};
|
||||||
|
|
||||||
pub trait RectHelper {
|
pub trait RectHelper<S: Float> {
|
||||||
fn fit_into(&self, bounds: &Rect<f32>) -> Rect<f32>;
|
fn fit_into(self, bounds: Rect<S>) -> Rect<S>;
|
||||||
|
|
||||||
fn bottom_half(&self) -> Rect<f32>;
|
fn bottom_half(self) -> Rect<S>;
|
||||||
fn bottom_part(&self, part: f32) -> Rect<f32>;
|
fn bottom_part(self, part: S) -> Rect<S>;
|
||||||
|
|
||||||
fn top_half(&self) -> Rect<f32>;
|
fn top_half(self) -> Rect<S>;
|
||||||
fn top_part(&self, part: f32) -> Rect<f32>;
|
fn top_part(self, part: S) -> Rect<S>;
|
||||||
|
|
||||||
fn left_half(&self) -> Rect<f32>;
|
fn left_half(self) -> Rect<S>;
|
||||||
fn left_part(&self, part: f32) -> Rect<f32>;
|
fn left_part(self, part: S) -> Rect<S>;
|
||||||
|
|
||||||
fn right_half(&self) -> Rect<f32>;
|
fn right_half(self) -> Rect<S>;
|
||||||
fn right_part(&self, part: f32) -> Rect<f32>;
|
fn right_part(self, part: S) -> Rect<S>;
|
||||||
|
|
||||||
fn split_horizontal<const N: usize>(&self) -> [Rect<f32>; N];
|
fn part_horizontal(self, part: S) -> [Rect<S>; 2];
|
||||||
fn split_vertical<const N: usize>(&self) -> [Rect<f32>; N];
|
fn part_vertical(self, part: S) -> [Rect<S>; 2];
|
||||||
fn split_horizontal_vec(&self, num: usize) -> Vec<Rect<f32>>;
|
|
||||||
fn split_vertical_vec(&self, num: usize) -> Vec<Rect<f32>>;
|
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> {
|
impl RectHelper<f32> for Rect<f32> {
|
||||||
fn fit_into(&self, bounds: &Rect<f32>) -> Self {
|
fn fit_into(self, bounds: Self) -> Self {
|
||||||
let content_aspect_ratio = self.w() / self.h();
|
let content_aspect_ratio = self.w() / self.h();
|
||||||
let bounds_aspect_ratio = bounds.w() / bounds.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())
|
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));
|
debug_assert!((0f32..=1f32).contains(&part));
|
||||||
Self::from_corner_points(
|
Self::from_corner_points(
|
||||||
[self.left(), self.bottom()],
|
[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())
|
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));
|
debug_assert!((0f32..=1f32).contains(&part));
|
||||||
Self::from_corner_points(
|
Self::from_corner_points(
|
||||||
[self.left(), self.top()],
|
[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())
|
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));
|
debug_assert!((0f32..=1f32).contains(&part));
|
||||||
Self::from_corner_points(
|
Self::from_corner_points(
|
||||||
[self.left(), self.bottom()],
|
[self.left(), self.bottom()],
|
||||||
|
@ -79,11 +82,11 @@ impl RectHelper for Rect<f32> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn right_half(&self) -> Self {
|
fn right_half(self) -> Self {
|
||||||
Self::from_corners(self.top_left(), self.mid_bottom())
|
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));
|
debug_assert!((0f32..=1f32).contains(&part));
|
||||||
Self::from_corner_points(
|
Self::from_corner_points(
|
||||||
[self.right(), self.bottom()],
|
[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)]
|
#[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 mut subdivisions = [unsafe { std::mem::zeroed() }; N];
|
||||||
|
|
||||||
let subdivided_width = self.w() / N as f32;
|
let subdivided_width = self.w() / N as f32;
|
||||||
|
@ -108,7 +119,7 @@ impl RectHelper for Rect<f32> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[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 mut subdivisions = Vec::with_capacity(num);
|
||||||
|
|
||||||
let subdivided_width = self.w() / num as f32;
|
let subdivided_width = self.w() / num as f32;
|
||||||
|
@ -124,7 +135,7 @@ impl RectHelper for Rect<f32> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[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 mut subdivisions = [unsafe { std::mem::zeroed() }; N];
|
||||||
|
|
||||||
let subdivided_height = self.h() / N as f32;
|
let subdivided_height = self.h() / N as f32;
|
||||||
|
@ -140,7 +151,7 @@ impl RectHelper for Rect<f32> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[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 mut subdivisions = Vec::with_capacity(num);
|
||||||
|
|
||||||
let subdivided_height = self.h() / num as f32;
|
let subdivided_height = self.h() / num as f32;
|
||||||
|
|
Loading…
Reference in a new issue