diff --git a/CHANGELOG.md b/CHANGELOG.md index d9346d1..cfdcfba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - `inverse_transform_vector` - `invert_x` - `invert_y` +* Added `HexLayout::with_rect_size` to construct hexagons matching sprite dimensions (#194) * Added `hex_edge_corners` utility method (#170) ### Mesh generation (#170) @@ -32,8 +33,8 @@ * (**BREAKING**) `HexOffsetMode` now has only 2 variants `Even` and `Odd` * (**BREAKING**) `Hex::to_offset_coordinates` and `Hex::from_offset_coordinates` take a new `HexOrientation` parameter (#189) - * Orientation matrices are now `glam::Mat2` (#191) - * Added `world_unit_vector` methods to `EdgeDirection` and `VertexDirection` (#190) +* Added `world_unit_vector` methods to `EdgeDirection` and `VertexDirection` (#190) +* Orientation matrices are now `glam::Mat2` (#191) ## 0.19.1 diff --git a/examples/sprite_sheet.rs b/examples/sprite_sheet.rs index aa819b2..de1606a 100644 --- a/examples/sprite_sheet.rs +++ b/examples/sprite_sheet.rs @@ -2,7 +2,8 @@ use bevy::{prelude::*, utils::HashMap, window::PrimaryWindow}; use glam::uvec2; use hexx::{shapes, *}; -const HEX_SIZE: Vec2 = Vec2::splat(20.0); +// 10% of the real individual texture sizes +const SPRITE_SIZE: Vec2 = Vec2::new(24.0, 28.0); pub fn main() { App::new() @@ -38,12 +39,7 @@ fn setup_grid( let atlas_layout = TextureAtlasLayout::from_grid(uvec2(120, 140), 7, 6, Some(uvec2(2, 2)), None); let atlas_layout = atlas_layouts.add(atlas_layout); - let layout = HexLayout { - orientation: HexOrientation::Pointy, - scale: HEX_SIZE, - ..default() - }; - let sprite_size = layout.rect_size(); + let layout = HexLayout::new(HexOrientation::Pointy).with_rect_size(SPRITE_SIZE); let entities = shapes::pointy_rectangle([-14, 14, -16, 16]) .enumerate() .map(|(i, coord)| { @@ -52,7 +48,7 @@ fn setup_grid( let entity = commands .spawn(( Sprite { - custom_size: Some(sprite_size), + custom_size: Some(SPRITE_SIZE), image: texture.clone(), texture_atlas: Some(TextureAtlas { index, diff --git a/src/layout.rs b/src/layout.rs index b95feaf..38c0537 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -45,6 +45,15 @@ use glam::Vec2; /// // Invert the y axis, which will now go down. Will change `scale.y` to `-3.0` /// layout.invert_y(); /// ``` +/// +/// ## Working with Sprites +/// +/// If you intend to use the hexagonal grid to place images/sprites you may use +/// `HexLayout::with_rect_size` to make the hexagon scale fit the your sprite +/// dimensions. +/// +/// You can also retrieve the matching rect size from any layout using +/// `HexLayout::rect_size()` #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))] @@ -272,6 +281,23 @@ impl HexLayout { self } + #[inline] + #[must_use] + /// Specifies the world/pixel size of individual hexagons to match + /// the given `rect_size`. This is useful if you want hexagons + /// to match a sprite size + pub fn with_rect_size(self, rect_size: Vec2) -> Self { + const FLAT_RECT: Vec2 = Vec2::new(0.5, 1.0 / SQRT_3); + const POINTY_RECT: Vec2 = Vec2::new(1.0 / SQRT_3, 0.5); + + let scale = rect_size + * match self.orientation { + HexOrientation::Pointy => POINTY_RECT, + HexOrientation::Flat => FLAT_RECT, + }; + self.with_scale(scale) + } + #[must_use] #[inline] /// Specifies the world/pixel scale of individual hexagons. @@ -294,6 +320,8 @@ impl Default for HexLayout { #[cfg(test)] mod tests { + use approx::assert_relative_eq; + use super::*; #[test] @@ -357,4 +385,29 @@ mod tests { ] ); } + + #[test] + fn rect_size() { + let sizes = [ + Vec2::ZERO, + Vec2::ONE, + Vec2::X, + Vec2::Y, + Vec2::NEG_ONE, + Vec2::NEG_X, + Vec2::NEG_Y, + Vec2::new(10.0, 5.0), + Vec2::new(-10.0, 31.1), + Vec2::new(110.0, 25.0), + Vec2::new(-210.54, -54.0), + ]; + for size in sizes { + for orientation in [HexOrientation::Flat, HexOrientation::Pointy] { + let layout = HexLayout::new(orientation).with_rect_size(size); + let rect = layout.rect_size(); + assert_relative_eq!(rect.x, size.x, epsilon = 0.00001); + assert_relative_eq!(rect.y, size.y, epsilon = 0.00001); + } + } + } } diff --git a/src/orientation.rs b/src/orientation.rs index 1c5bceb..847d01d 100644 --- a/src/orientation.rs +++ b/src/orientation.rs @@ -2,9 +2,10 @@ use glam::{vec2, Mat2, Vec2}; use std::ops::Deref; pub(crate) const SQRT_3: f32 = 1.732_050_8; +pub(crate) const HALF_SQRT_3: f32 = SQRT_3 / 2.0; // Mat2 shearing factor -const FORWARD_SHEAR: f32 = SQRT_3 / 2.0; +const FORWARD_SHEAR: f32 = HALF_SQRT_3; const INVERSE_SHEAR: f32 = -1.0 / 3.0; // Mat2 scale diagonal.