Newtype Anchor
(#18439)
# Objective The `Anchor` component doesn't need to be a enum. The variants are just mapped to `Vec2`s so it could be changed to a newtype with associated const values, saving the space needed for the discriminator by the enum. Also there was no benefit I think in hiding the underlying `Vec2` representation of `Anchor`s. Suggested by @atlv24. Fixes #18459 Fixes #18460 ## Solution Change `Anchor` to a struct newtyping a `Vec2`, and its variants into associated constants. ## Migration Guide The anchor component has been changed from an enum to a struct newtyping a `Vec2`. The `Custom` variant has been removed, instead to construct a custom `Anchor` use its tuple constructor: ```rust Sprite { anchor: Anchor(Vec2::new(0.25, 0.4)), ..default() } ``` The other enum variants have been replaced with corresponding constants: * `Anchor::BottomLeft` to `Anchor::BOTTOM_LEFT` * `Anchor::Center` to `Anchor::CENTER` * `Anchor::TopRight` to `Anchor::TOP_RIGHT` * .. and so on for the remaining variants
This commit is contained in:
parent
9ae7aa4399
commit
84b09b9398
@ -331,7 +331,7 @@ mod test {
|
||||
.world_mut()
|
||||
.spawn(Sprite {
|
||||
rect: Some(Rect::new(0., 0., 0.5, 1.)),
|
||||
anchor: Anchor::TopRight,
|
||||
anchor: Anchor::TOP_RIGHT,
|
||||
image: image_handle,
|
||||
..default()
|
||||
})
|
||||
|
@ -1,5 +1,6 @@
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use bevy_color::Color;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{component::Component, reflect::ReflectComponent};
|
||||
use bevy_image::{Image, TextureAtlas, TextureAtlasLayout};
|
||||
use bevy_math::{Rect, UVec2, Vec2};
|
||||
@ -240,42 +241,38 @@ pub enum ScalingMode {
|
||||
FitEnd,
|
||||
}
|
||||
|
||||
/// How a sprite is positioned relative to its [`Transform`].
|
||||
/// It defaults to `Anchor::Center`.
|
||||
#[derive(Component, Debug, Clone, Copy, PartialEq, Default, Reflect)]
|
||||
/// Normalized (relative to its size) offset of a 2d renderable entity from its [`Transform`].
|
||||
#[derive(Component, Debug, Clone, Copy, PartialEq, Deref, DerefMut, Reflect)]
|
||||
#[reflect(Component, Default, Debug, PartialEq, Clone)]
|
||||
#[doc(alias = "pivot")]
|
||||
pub enum Anchor {
|
||||
#[default]
|
||||
Center,
|
||||
BottomLeft,
|
||||
BottomCenter,
|
||||
BottomRight,
|
||||
CenterLeft,
|
||||
CenterRight,
|
||||
TopLeft,
|
||||
TopCenter,
|
||||
TopRight,
|
||||
/// Custom anchor point. Top left is `(-0.5, 0.5)`, center is `(0.0, 0.0)`. The value will
|
||||
/// be scaled with the sprite size.
|
||||
Custom(Vec2),
|
||||
}
|
||||
pub struct Anchor(pub Vec2);
|
||||
|
||||
impl Anchor {
|
||||
pub const BOTTOM_LEFT: Self = Self(Vec2::new(-0.5, -0.5));
|
||||
pub const BOTTOM_CENTER: Self = Self(Vec2::new(0.0, -0.5));
|
||||
pub const BOTTOM_RIGHT: Self = Self(Vec2::new(0.5, -0.5));
|
||||
pub const CENTER_LEFT: Self = Self(Vec2::new(-0.5, 0.0));
|
||||
pub const CENTER: Self = Self(Vec2::ZERO);
|
||||
pub const CENTER_RIGHT: Self = Self(Vec2::new(0.5, 0.0));
|
||||
pub const TOP_LEFT: Self = Self(Vec2::new(-0.5, 0.5));
|
||||
pub const TOP_CENTER: Self = Self(Vec2::new(0.0, 0.5));
|
||||
pub const TOP_RIGHT: Self = Self(Vec2::new(0.5, 0.5));
|
||||
|
||||
pub fn as_vec(&self) -> Vec2 {
|
||||
match self {
|
||||
Anchor::Center => Vec2::ZERO,
|
||||
Anchor::BottomLeft => Vec2::new(-0.5, -0.5),
|
||||
Anchor::BottomCenter => Vec2::new(0.0, -0.5),
|
||||
Anchor::BottomRight => Vec2::new(0.5, -0.5),
|
||||
Anchor::CenterLeft => Vec2::new(-0.5, 0.0),
|
||||
Anchor::CenterRight => Vec2::new(0.5, 0.0),
|
||||
Anchor::TopLeft => Vec2::new(-0.5, 0.5),
|
||||
Anchor::TopCenter => Vec2::new(0.0, 0.5),
|
||||
Anchor::TopRight => Vec2::new(0.5, 0.5),
|
||||
Anchor::Custom(point) => *point,
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Anchor {
|
||||
fn default() -> Self {
|
||||
Self::CENTER
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec2> for Anchor {
|
||||
fn from(value: Vec2) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -358,7 +355,7 @@ mod tests {
|
||||
|
||||
let sprite = Sprite {
|
||||
image,
|
||||
anchor: Anchor::BottomLeft,
|
||||
anchor: Anchor::BOTTOM_LEFT,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@ -380,7 +377,7 @@ mod tests {
|
||||
|
||||
let sprite = Sprite {
|
||||
image,
|
||||
anchor: Anchor::TopRight,
|
||||
anchor: Anchor::TOP_RIGHT,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@ -402,7 +399,7 @@ mod tests {
|
||||
|
||||
let sprite = Sprite {
|
||||
image,
|
||||
anchor: Anchor::BottomLeft,
|
||||
anchor: Anchor::BOTTOM_LEFT,
|
||||
flip_x: true,
|
||||
..Default::default()
|
||||
};
|
||||
@ -425,7 +422,7 @@ mod tests {
|
||||
|
||||
let sprite = Sprite {
|
||||
image,
|
||||
anchor: Anchor::TopRight,
|
||||
anchor: Anchor::TOP_RIGHT,
|
||||
flip_y: true,
|
||||
..Default::default()
|
||||
};
|
||||
@ -449,7 +446,7 @@ mod tests {
|
||||
let sprite = Sprite {
|
||||
image,
|
||||
rect: Some(Rect::new(1.5, 3.0, 3.0, 9.5)),
|
||||
anchor: Anchor::BottomLeft,
|
||||
anchor: Anchor::BOTTOM_LEFT,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@ -473,7 +470,7 @@ mod tests {
|
||||
|
||||
let sprite = Sprite {
|
||||
image,
|
||||
anchor: Anchor::BottomLeft,
|
||||
anchor: Anchor::BOTTOM_LEFT,
|
||||
texture_atlas: Some(TextureAtlas {
|
||||
layout: texture_atlas,
|
||||
index: 0,
|
||||
@ -501,7 +498,7 @@ mod tests {
|
||||
|
||||
let sprite = Sprite {
|
||||
image,
|
||||
anchor: Anchor::BottomLeft,
|
||||
anchor: Anchor::BOTTOM_LEFT,
|
||||
texture_atlas: Some(TextureAtlas {
|
||||
layout: texture_atlas,
|
||||
index: 0,
|
||||
|
@ -213,7 +213,7 @@ pub fn extract_text2d_sprite(
|
||||
image_handle_id: atlas_info.texture.id(),
|
||||
flip_x: false,
|
||||
flip_y: false,
|
||||
anchor: Anchor::Center.as_vec(),
|
||||
anchor: Anchor::CENTER.as_vec(),
|
||||
original_entity,
|
||||
scaling_mode: None,
|
||||
});
|
||||
|
@ -132,7 +132,7 @@ fn setup_sprites(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
TextLayout::new_with_justify(JustifyText::Center),
|
||||
TextFont::from_font_size(15.),
|
||||
Transform::from_xyz(0., -0.5 * rect.size.y - 10., 0.),
|
||||
bevy::sprite::Anchor::TopCenter,
|
||||
bevy::sprite::Anchor::TOP_CENTER,
|
||||
));
|
||||
});
|
||||
}
|
||||
@ -278,7 +278,7 @@ fn setup_texture_atlas(
|
||||
TextLayout::new_with_justify(JustifyText::Center),
|
||||
TextFont::from_font_size(15.),
|
||||
Transform::from_xyz(0., -0.5 * sprite_sheet.size.y - 10., 0.),
|
||||
bevy::sprite::Anchor::TopCenter,
|
||||
bevy::sprite::Anchor::TOP_CENTER,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ fn spawn_sprites(
|
||||
text_style,
|
||||
TextLayout::new_with_justify(JustifyText::Center),
|
||||
Transform::from_xyz(0., -0.5 * size.y - 10., 0.0),
|
||||
bevy::sprite::Anchor::TopCenter,
|
||||
bevy::sprite::Anchor::TOP_CENTER,
|
||||
)],
|
||||
));
|
||||
position.x += 0.5 * size.x + gap;
|
||||
|
@ -129,10 +129,10 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
))
|
||||
.with_children(|commands| {
|
||||
for (text_anchor, color) in [
|
||||
(Anchor::TopLeft, Color::Srgba(LIGHT_SALMON)),
|
||||
(Anchor::TopRight, Color::Srgba(LIGHT_GREEN)),
|
||||
(Anchor::BottomRight, Color::Srgba(LIGHT_BLUE)),
|
||||
(Anchor::BottomLeft, Color::Srgba(LIGHT_YELLOW)),
|
||||
(Anchor::TOP_LEFT, Color::Srgba(LIGHT_SALMON)),
|
||||
(Anchor::TOP_RIGHT, Color::Srgba(LIGHT_GREEN)),
|
||||
(Anchor::BOTTOM_RIGHT, Color::Srgba(LIGHT_BLUE)),
|
||||
(Anchor::BOTTOM_LEFT, Color::Srgba(LIGHT_YELLOW)),
|
||||
] {
|
||||
commands
|
||||
.spawn((
|
||||
|
@ -38,16 +38,15 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
.spawn((Transform::default(), Visibility::default()))
|
||||
.with_children(|commands| {
|
||||
for (anchor_index, anchor) in [
|
||||
Anchor::TopLeft,
|
||||
Anchor::TopCenter,
|
||||
Anchor::TopRight,
|
||||
Anchor::CenterLeft,
|
||||
Anchor::Center,
|
||||
Anchor::CenterRight,
|
||||
Anchor::BottomLeft,
|
||||
Anchor::BottomCenter,
|
||||
Anchor::BottomRight,
|
||||
Anchor::Custom(Vec2::new(0.5, 0.5)),
|
||||
Anchor::TOP_LEFT,
|
||||
Anchor::TOP_CENTER,
|
||||
Anchor::TOP_RIGHT,
|
||||
Anchor::CENTER_LEFT,
|
||||
Anchor::CENTER,
|
||||
Anchor::CENTER_RIGHT,
|
||||
Anchor::BOTTOM_LEFT,
|
||||
Anchor::BOTTOM_CENTER,
|
||||
Anchor::BOTTOM_RIGHT,
|
||||
]
|
||||
.iter()
|
||||
.enumerate()
|
||||
|
@ -101,7 +101,7 @@ fn setup(mut commands: Commands, args: Res<Args>) {
|
||||
Text2d::new(text_string),
|
||||
text_font.clone(),
|
||||
TextColor(RED.into()),
|
||||
bevy::sprite::Anchor::Center,
|
||||
bevy::sprite::Anchor::CENTER,
|
||||
TextBounds::new_horizontal(1000.),
|
||||
text_block,
|
||||
));
|
||||
|
@ -215,10 +215,10 @@ mod text {
|
||||
));
|
||||
|
||||
for anchor in [
|
||||
Anchor::TopLeft,
|
||||
Anchor::TopRight,
|
||||
Anchor::BottomRight,
|
||||
Anchor::BottomLeft,
|
||||
Anchor::TOP_LEFT,
|
||||
Anchor::TOP_RIGHT,
|
||||
Anchor::BOTTOM_RIGHT,
|
||||
Anchor::BOTTOM_LEFT,
|
||||
] {
|
||||
let mut text = commands.spawn((
|
||||
Text2d::new("L R\n"),
|
||||
@ -229,7 +229,7 @@ mod text {
|
||||
));
|
||||
text.with_children(|parent| {
|
||||
parent.spawn((
|
||||
TextSpan::new(format!("{anchor:?}\n")),
|
||||
TextSpan::new(format!("{}, {}\n", anchor.x, anchor.y)),
|
||||
TextFont::from_font_size(14.0),
|
||||
TextColor(palettes::tailwind::BLUE_400.into()),
|
||||
));
|
||||
|
@ -287,7 +287,7 @@ fn setup_sticks(
|
||||
(
|
||||
Text2d::default(),
|
||||
Transform::from_xyz(0., STICK_BOUNDS_SIZE + 2., 4.),
|
||||
Anchor::BottomCenter,
|
||||
Anchor::BOTTOM_CENTER,
|
||||
TextWithAxes { x_axis, y_axis },
|
||||
children![
|
||||
(TextSpan(format!("{:.3}", 0.)), style.clone()),
|
||||
|
Loading…
Reference in New Issue
Block a user