From 264e25cfe7b8a573543d14461062864e2878b1a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Mon, 4 Apr 2022 22:09:59 +0000 Subject: [PATCH] can specify an anchor for a sprite (#3463) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Objective - Fixes #1616, fixes #2225 - Let user specify an anchor for a sprite ## Solution - Add an enum for an anchor point for most common values, with a variant for a custom point - Defaults to Center to not change current behaviour Co-authored-by: François <8672791+mockersf@users.noreply.github.com> --- crates/bevy_sprite/src/render/mod.rs | 5 ++- crates/bevy_sprite/src/sprite.rs | 44 +++++++++++++++++++++++++ crates/bevy_sprite/src/texture_atlas.rs | 4 ++- crates/bevy_text/src/text2d.rs | 3 +- 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 7e8cbe98577b27..577f9da4d855fb 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -184,6 +184,7 @@ pub struct ExtractedSprite { pub image_handle_id: HandleId, pub flip_x: bool, pub flip_y: bool, + pub anchor: Vec2, } #[derive(Default)] @@ -248,6 +249,7 @@ pub fn extract_sprites( flip_x: sprite.flip_x, flip_y: sprite.flip_y, image_handle_id: handle.id, + anchor: sprite.anchor.as_vec(), }); } for (visibility, atlas_sprite, transform, texture_atlas_handle) in atlas_query.iter() { @@ -266,6 +268,7 @@ pub fn extract_sprites( flip_x: atlas_sprite.flip_x, flip_y: atlas_sprite.flip_y, image_handle_id: texture_atlas.texture.id, + anchor: atlas_sprite.anchor.as_vec(), }); } } @@ -489,7 +492,7 @@ pub fn queue_sprites( let positions = QUAD_VERTEX_POSITIONS.map(|quad_pos| { extracted_sprite .transform - .mul_vec3((quad_pos * quad_size).extend(0.)) + .mul_vec3(((quad_pos - extracted_sprite.anchor) * quad_size).extend(0.)) .into() }); diff --git a/crates/bevy_sprite/src/sprite.rs b/crates/bevy_sprite/src/sprite.rs index 78911e5760bdf8..e18c9f4ab4d3ad 100644 --- a/crates/bevy_sprite/src/sprite.rs +++ b/crates/bevy_sprite/src/sprite.rs @@ -15,4 +15,48 @@ pub struct Sprite { /// An optional custom size for the sprite that will be used when rendering, instead of the size /// of the sprite's image pub custom_size: Option, + /// [`Anchor`] point of the sprite in the world + pub anchor: Anchor, +} + +/// How a sprite is positioned relative to its [`Transform`](bevy_transform::components::Transform). +/// It defaults to `Anchor::Center`. +#[derive(Debug, Clone, Reflect)] +#[doc(alias = "pivot")] +pub enum Anchor { + 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), +} + +impl Default for Anchor { + fn default() -> Self { + Anchor::Center + } +} + +impl Anchor { + 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, + } + } } diff --git a/crates/bevy_sprite/src/texture_atlas.rs b/crates/bevy_sprite/src/texture_atlas.rs index 5eae1350fae636..c290f45416a1fd 100644 --- a/crates/bevy_sprite/src/texture_atlas.rs +++ b/crates/bevy_sprite/src/texture_atlas.rs @@ -1,4 +1,4 @@ -use crate::Rect; +use crate::{Anchor, Rect}; use bevy_asset::Handle; use bevy_ecs::component::Component; use bevy_math::Vec2; @@ -30,6 +30,7 @@ pub struct TextureAtlasSprite { /// An optional custom size for the sprite that will be used when rendering, instead of the size /// of the sprite's image in the atlas pub custom_size: Option, + pub anchor: Anchor, } impl Default for TextureAtlasSprite { @@ -40,6 +41,7 @@ impl Default for TextureAtlasSprite { flip_x: false, flip_y: false, custom_size: None, + anchor: Anchor::default(), } } } diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 86bb4c998f0803..9bab65aa982970 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -10,7 +10,7 @@ use bevy_ecs::{ use bevy_math::{Size, Vec3}; use bevy_reflect::Reflect; use bevy_render::{texture::Image, view::Visibility, RenderWorld}; -use bevy_sprite::{ExtractedSprite, ExtractedSprites, TextureAtlas}; +use bevy_sprite::{Anchor, ExtractedSprite, ExtractedSprites, TextureAtlas}; use bevy_transform::prelude::{GlobalTransform, Transform}; use bevy_window::{WindowId, Windows}; @@ -116,6 +116,7 @@ pub fn extract_text2d_sprite( image_handle_id: handle.id, flip_x: false, flip_y: false, + anchor: Anchor::Center.as_vec(), }); } }