ui: rework so Nodes now use transforms and z-sort happens

This commit is contained in:
Carter Anderson 2020-06-25 10:13:00 -07:00
parent 75429f4639
commit 1ef4fbf005
18 changed files with 185 additions and 168 deletions

View File

@ -77,14 +77,12 @@ pub fn run_on_hierarchy_subworld<T>(
pub fn run_on_hierarchy_subworld_mut<T>(
world: &mut SubWorld,
entity: Entity,
input: T,
run: &mut dyn FnMut(&mut SubWorld, Entity, T) -> Option<T>,
child_result_action: &mut dyn FnMut(T, T) -> T,
) -> Option<T>
where
T: Copy,
{
parent_result: Option<&mut T>,
mut previous_result: Option<T>,
run: &mut dyn FnMut(&mut SubWorld, Entity, Option<&mut T>, Option<T>) -> Option<T>,
) -> Option<T> where T: Clone {
// TODO: not a huge fan of this pattern. are there ways to do recursive updates in legion without allocations?
// TODO: the problem above might be resolvable with world splitting
let children = match world.get_component::<Children>(entity) {
Some(children) => Some(
children
@ -95,21 +93,21 @@ where
None => None,
};
let result = run(world, entity, input);
if let Some(mut result) = result {
if let Some(children) = children {
for child in children {
let child_result =
run_on_hierarchy_subworld_mut(world, child, result, run, child_result_action);
if let Some(child_result) = child_result {
result = child_result_action(result, child_result)
}
}
let mut parent_result = run(world, entity, parent_result, previous_result);
previous_result = None;
if let Some(children) = children {
for child in children {
previous_result = run_on_hierarchy_subworld_mut(
world,
child,
parent_result.as_mut(),
previous_result,
run,
);
}
Some(result)
} else {
None
previous_result = parent_result;
}
previous_result
}

View File

@ -65,7 +65,7 @@ impl OrthographicCameraEntity {
..Default::default()
},
orthographic_projection: OrthographicProjection {
window_origin: WindowOrigin::BottomLeft,
window_origin: WindowOrigin::Center,
..Default::default()
},
visible_entities: Default::default(),

View File

@ -1,7 +1,6 @@
mod color_material;
mod dynamic_texture_atlas_builder;
pub mod entity;
mod quad;
mod rect;
mod render;
mod sprite;
@ -10,7 +9,6 @@ mod texture_atlas_builder;
pub use color_material::*;
pub use dynamic_texture_atlas_builder::*;
pub use quad::*;
pub use rect::*;
pub use render::*;
pub use sprite::*;

View File

@ -1,11 +0,0 @@
use bevy_core::bytes::Bytes;
use bevy_render::render_resource::{RenderResource, RenderResources};
use glam::Vec2;
#[repr(C)]
#[derive(Default, Clone, Copy, Debug, RenderResources, RenderResource, Bytes)]
#[render_resources(from_self)]
pub struct Quad {
pub position: Vec2,
pub size: Vec2,
pub z_index: f32,
}

View File

@ -1,4 +1,4 @@
use crate::{ColorMaterial, Quad, TextureAtlas, TextureAtlasSprite, Sprite};
use crate::{ColorMaterial, TextureAtlas, TextureAtlasSprite, Sprite};
use bevy_asset::{Assets, Handle};
use bevy_render::{
base_render_graph,
@ -110,7 +110,6 @@ pub fn build_sprite_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor
pub mod node {
pub const COLOR_MATERIAL: &'static str = "color_material";
pub const QUAD: &'static str = "quad";
pub const SPRITE: &'static str = "sprite";
pub const SPRITE_SHEET: &'static str = "sprite_sheet";
pub const SPRITE_SHEET_SPRITE: &'static str = "sprite_sheet_sprite";
@ -129,9 +128,6 @@ impl SpriteRenderGraphBuilder for RenderGraph {
self.add_node_edge(node::COLOR_MATERIAL, base_render_graph::node::MAIN_PASS)
.unwrap();
self.add_system_node(node::QUAD, RenderResourcesNode::<Quad>::new(false));
self.add_node_edge(node::QUAD, base_render_graph::node::MAIN_PASS)
.unwrap();
self.add_system_node(node::SPRITE, RenderResourcesNode::<Sprite>::new(true));
self.add_node_edge(node::SPRITE, base_render_graph::node::MAIN_PASS)
.unwrap();

View File

@ -2,28 +2,52 @@ use super::Node;
use crate::{render::UI_PIPELINE_HANDLE, widget::Label};
use bevy_asset::Handle;
use bevy_derive::EntityArchetype;
use bevy_render::{draw::Draw, mesh::Mesh, pipeline::RenderPipelines};
use bevy_sprite::{ColorMaterial, Quad, QUAD_HANDLE};
use bevy_render::{draw::Draw, mesh::Mesh, pipeline::{PipelineSpecialization, RenderPipelines, DynamicBinding, RenderPipeline}};
use bevy_sprite::{ColorMaterial, QUAD_HANDLE};
use bevy_transform::prelude::{Translation, Transform, Rotation, Scale};
#[derive(EntityArchetype)]
pub struct UiEntity {
pub node: Node,
pub quad: Quad,
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
pub material: Handle<ColorMaterial>,
pub draw: Draw,
pub render_pipelines: RenderPipelines,
pub transform: Transform,
pub translation: Translation,
pub rotation: Rotation,
pub scale: Scale,
}
impl Default for UiEntity {
fn default() -> Self {
UiEntity {
mesh: QUAD_HANDLE,
render_pipelines: RenderPipelines::from_handles(&[UI_PIPELINE_HANDLE]),
render_pipelines: RenderPipelines::from_pipelines(vec![RenderPipeline::specialized(
UI_PIPELINE_HANDLE,
PipelineSpecialization {
dynamic_bindings: vec![
// Transform
DynamicBinding {
bind_group: 1,
binding: 0,
},
// Node_size
DynamicBinding {
bind_group: 1,
binding: 1,
},
],
..Default::default()
},
)]),
node: Default::default(),
quad: Default::default(),
material: Default::default(),
draw: Default::default(),
transform: Default::default(),
translation: Default::default(),
rotation: Default::default(),
scale: Default::default(),
}
}
}
@ -31,9 +55,12 @@ impl Default for UiEntity {
#[derive(EntityArchetype)]
pub struct LabelEntity {
pub node: Node,
pub quad: Quad,
pub draw: Draw,
pub label: Label,
pub transform: Transform,
pub translation: Translation,
pub rotation: Rotation,
pub scale: Scale,
}
impl Default for LabelEntity {
@ -41,8 +68,14 @@ impl Default for LabelEntity {
LabelEntity {
label: Label::default(),
node: Default::default(),
quad: Default::default(),
draw: Default::default(),
draw: Draw {
is_transparent: true,
..Default::default()
},
transform: Default::default(),
translation: Default::default(),
rotation: Default::default(),
scale: Default::default(),
}
}
}

View File

@ -22,7 +22,7 @@ pub struct UiPlugin;
impl AppPlugin for UiPlugin {
fn build(&self, app: &mut AppBuilder) {
app.add_system_to_stage(stage::POST_UPDATE, ui_update_system())
app.add_system_to_stage(stage::POST_UPDATE, ui_update_system.system())
.add_system_to_stage(stage::POST_UPDATE, Label::label_system.system())
.add_system_to_stage(bevy_render::stage::DRAW, Label::draw_label_system.system());

View File

@ -1,6 +1,7 @@
use super::{Anchors, Margins};
use bevy_sprite::Quad;
use glam::Vec2;
use bevy_transform::prelude::Translation;
use bevy_render::render_resource::RenderResources;
use glam::{Vec2, Vec3};
#[derive(Debug, Clone)]
enum MarginGrowDirection {
@ -8,41 +9,37 @@ enum MarginGrowDirection {
Positive,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default, RenderResources)]
pub struct Node {
pub size: Vec2,
#[render_resources(ignore)]
pub position: Vec2,
#[render_resources(ignore)]
pub anchors: Anchors,
#[render_resources(ignore)]
pub margins: Margins,
}
impl Default for Node {
fn default() -> Self {
impl Node {
pub fn new(anchors: Anchors, margins: Margins) -> Self {
Node {
position: Vec2::default(),
anchors: Anchors::default(),
margins: Margins::default(),
anchors,
margins,
..Default::default()
}
}
}
impl Node {
pub fn new(position: Vec2, anchors: Anchors, margins: Margins) -> Self {
pub fn positioned(position: Vec2, anchors: Anchors, margins: Margins) -> Self {
Node {
position,
anchors,
margins,
..Default::default()
}
}
pub fn update(
&mut self,
quad: &mut Quad,
parent_size: Vec2,
parent_position: Vec2,
z_index: f32,
) {
pub fn update(&mut self, translation: &mut Translation, z_offset: f32, parent_size: Vec2) {
let (quad_x, quad_width) = Self::compute_dimension_properties(
self.position.x(),
self.margins.left,
self.margins.right,
self.anchors.left,
@ -50,7 +47,6 @@ impl Node {
parent_size.x(),
);
let (quad_y, quad_height) = Self::compute_dimension_properties(
self.position.y(),
self.margins.bottom,
self.margins.top,
self.anchors.bottom,
@ -58,13 +54,11 @@ impl Node {
parent_size.y(),
);
quad.size = Vec2::new(quad_width, quad_height);
quad.position = Vec2::new(quad_x, quad_y) + parent_position;
quad.z_index = z_index;
self.size = Vec2::new(quad_width, quad_height);
translation.0 = self.position.extend(0.0) + Vec3::new(quad_x, quad_y, z_offset) - (parent_size / 2.0).extend(0.0);
}
fn compute_dimension_properties(
offset: f32,
margin0: f32,
margin1: f32,
anchor0: f32,
@ -85,23 +79,22 @@ impl Node {
MarginGrowDirection::Negative
};
let p0 = Self::compute_quad_position(offset, margin0, anchor_p0, p0_grow_direction);
let p1 = Self::compute_quad_position(offset, margin1, anchor_p1, p1_grow_direction);
let p0 = Self::compute_anchored_position(margin0, anchor_p0, p0_grow_direction);
let p1 = Self::compute_anchored_position(margin1, anchor_p1, p1_grow_direction);
let final_width = p1 - p0;
let p = (p0 + p1) / 2.0;
(p, final_width.abs())
}
fn compute_quad_position(
position: f32,
fn compute_anchored_position(
margin: f32,
anchor_position: f32,
grow_direction: MarginGrowDirection,
) -> f32 {
match grow_direction {
MarginGrowDirection::Negative => position + anchor_position - margin,
MarginGrowDirection::Positive => position + anchor_position + margin,
MarginGrowDirection::Negative => anchor_position - margin,
MarginGrowDirection::Positive => anchor_position + margin,
}
}
}

View File

@ -2,11 +2,12 @@ use bevy_asset::{Assets, Handle};
use bevy_render::{
base_render_graph,
pipeline::{state_descriptors::*, PipelineDescriptor},
render_graph::{nodes::{PassNode, CameraNode}, RenderGraph},
render_graph::{nodes::{PassNode, CameraNode, RenderResourcesNode}, RenderGraph},
shader::{Shader, ShaderStage, ShaderStages},
texture::TextureFormat, ActiveCameras,
};
use legion::prelude::Resources;
use crate::Node;
pub const UI_PIPELINE_HANDLE: Handle<PipelineDescriptor> =
Handle::from_u128(323432002226399387835192542539754486265);
@ -58,6 +59,7 @@ pub fn build_ui_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor {
pub mod node {
pub const UI_CAMERA: &'static str = "ui_camera";
pub const NODE: &'static str = "node";
}
pub mod camera {
@ -78,6 +80,9 @@ impl UiRenderGraphBuilder for RenderGraph {
self.add_system_node(node::UI_CAMERA, CameraNode::new(camera::UI_CAMERA));
self.add_node_edge(node::UI_CAMERA, base_render_graph::node::MAIN_PASS)
.unwrap();
self.add_system_node(node::NODE, RenderResourcesNode::<Node>::new(true));
self.add_node_edge(node::NODE, base_render_graph::node::MAIN_PASS)
.unwrap();
let mut active_cameras = resources.get_mut::<ActiveCameras>().unwrap();
let main_pass_node: &mut PassNode = self.get_node_mut(base_render_graph::node::MAIN_PASS).unwrap();
main_pass_node.add_camera(camera::UI_CAMERA);

View File

@ -9,8 +9,8 @@ layout(set = 2, binding = 0) uniform ColorMaterial_color {
};
# ifdef COLORMATERIAL_TEXTURE
layout(set = 3, binding = 0) uniform texture2D ColorMaterial_texture;
layout(set = 3, binding = 1) uniform sampler ColorMaterial_texture_sampler;
layout(set = 2, binding = 1) uniform texture2D ColorMaterial_texture;
layout(set = 2, binding = 2) uniform sampler ColorMaterial_texture_sampler;
# endif
void main() {

View File

@ -10,15 +10,15 @@ layout(set = 0, binding = 0) uniform UiCamera {
mat4 ViewProj;
};
layout(set = 1, binding = 0) uniform Quad {
vec2 Quad_Position;
vec2 Quad_Size;
float Quad_ZIndex;
layout(set = 1, binding = 0) uniform Transform {
mat4 Object;
};
layout(set = 1, binding = 1) uniform Node_size {
vec2 NodeSize;
};
void main() {
v_Uv = Vertex_Uv;
vec3 position = Vertex_Position * vec3(Quad_Size, 0.0);
position = position + vec3(Quad_Position, Quad_ZIndex);
gl_Position = ViewProj * vec4(position, 1.0);
vec3 position = Vertex_Position * vec3(NodeSize, 0.0);
gl_Position = ViewProj * Object * vec4(position, 1.0);
}

View File

@ -1,74 +1,81 @@
use super::Node;
use bevy_core::transform::run_on_hierarchy_subworld_mut;
use bevy_sprite::Quad;
use bevy_transform::prelude::{Children, Parent};
use bevy_transform::prelude::{Children, Parent, Translation};
use bevy_window::Windows;
use glam::Vec2;
use legion::{prelude::*, systems::SubWorld};
pub const UI_Z_STEP: f32 = 0.001;
pub fn ui_update_system() -> Box<dyn Schedulable> {
SystemBuilder::new("ui_update")
.read_resource::<Windows>()
.with_query(<Read<Node>>::query().filter(!component::<Parent>()))
.write_component::<Node>()
.write_component::<Quad>()
.read_component::<Children>()
.build(move |_, world, windows, node_query| {
if let Some(window) = windows.get_primary() {
let mut window_quad = Quad {
size: Vec2::new(window.width as f32, window.height as f32),
position: Vec2::new(0.0, 0.0),
z_index: 999.0,
};
for entity in node_query
.iter_entities(world)
.map(|(e, _)| e)
.collect::<Vec<Entity>>()
{
let result = run_on_hierarchy_subworld_mut(
world,
entity,
window_quad.clone(),
&mut update_node_entity,
&mut process_child_result,
);
if let Some(result) = result {
window_quad.z_index = result.z_index;
}
}
}
})
#[derive(Clone)]
pub struct Rect {
pub z: f32,
pub size: Vec2,
}
fn update_node_entity(world: &mut SubWorld, entity: Entity, parent_quad: Quad) -> Option<Quad> {
pub fn ui_update_system(
world: &mut SubWorld,
windows: Res<Windows>,
node_query: &mut Query<(Write<Node>, Write<Translation>)>,
_parent_query: &mut Query<Read<Parent>>,
_children_query: &mut Query<Read<Children>>,
) {
let window_size = if let Some(window) = windows.get_primary() {
Vec2::new(window.width as f32, window.height as f32)
} else {
return;
};
let orphan_nodes = node_query
.iter_entities_mut(world)
// TODO: replace this filter with a legion query filter (when SimpleQuery gets support for filters)
.filter(|(entity, _)| world.get_component::<Parent>(*entity).is_none())
.map(|(e, _)| e)
.collect::<Vec<Entity>>();
let mut window_rect = Rect {
z: 0.0,
size: window_size,
};
let mut previous_sibling_result = Some(Rect {
z: 999.0,
size: window_size,
});
for entity in orphan_nodes {
previous_sibling_result = run_on_hierarchy_subworld_mut(
world,
entity,
Some(&mut window_rect),
previous_sibling_result,
&mut update_node_entity,
);
}
}
fn update_node_entity(world: &mut SubWorld, entity: Entity, parent_rect: Option<&mut Rect>, previous_rect: Option<Rect>) -> Option<Rect> {
// TODO: Somehow remove this unsafe
unsafe {
if let Some(mut node) = world.get_component_mut_unchecked::<Node>(entity) {
if let Some(mut quad) = world.get_component_mut_unchecked::<Quad>(entity) {
if let Some(mut translation) = world.get_component_mut_unchecked::<Translation>(entity)
{
let parent_rect = parent_rect.unwrap();
let mut z = parent_rect.z;
if let Some(previous_rect) = previous_rect {
z = previous_rect.z
};
z -= UI_Z_STEP;
node.update(
&mut quad,
parent_quad.size,
parent_quad.position,
parent_quad.z_index,
&mut translation,
z - parent_rect.z,
parent_rect.size,
);
return Some(Quad {
size: quad.size,
position: quad.position - quad.size / 2.0,
z_index: quad.z_index - UI_Z_STEP,
return Some(Rect {
size: node.size,
z,
});
}
}
}
None
}
fn process_child_result(_parent_result: Quad, child_result: Quad) -> Quad {
// "earlier" children are sorted behind "later" children
let mut result = child_result.clone();
result.z_index -= UI_Z_STEP;
result
}
}

View File

@ -1,3 +1,4 @@
use crate::Node;
use bevy_asset::{Assets, Handle};
use bevy_render::{
draw::{Draw, DrawContext, Drawable},
@ -5,9 +6,9 @@ use bevy_render::{
texture::Texture,
Color,
};
use bevy_sprite::{ComMut, Quad, TextureAtlas};
use bevy_sprite::{ComMut, TextureAtlas};
use bevy_text::{DrawableText, Font, FontAtlasSet, TextStyle};
use glam::Vec3;
use bevy_transform::prelude::Transform;
use legion::prelude::{Com, Res, ResMut};
pub struct Label {
@ -44,7 +45,7 @@ impl Label {
});
// TODO: this call results in one or more TextureAtlases, whose render resources are created in the RENDER_GRAPH_SYSTEMS
// stage. That logic runs _before_ the DRAW stage, which means we cant call add_glyphs_to_atlas in the draw stage
// without or render resources being a frame behind. Therefore glyph atlasing either needs its own system or the TextureAtlas
// without our render resources being a frame behind. Therefore glyph atlasing either needs its own system or the TextureAtlas
// resource generation needs to happen AFTER the render graph systems. maybe draw systems should execute within the
// render graph so ordering like this can be taken into account? Maybe the RENDER_GRAPH_SYSTEMS stage should be removed entirely
// in favor of node.update()? Regardless, in the immediate short term the current approach is fine.
@ -66,9 +67,12 @@ impl Label {
mut asset_render_resource_bindings: ResMut<AssetRenderResourceBindings>,
mut draw: ComMut<Draw>,
label: Com<Label>,
quad: Com<Quad>,
node: Com<Node>,
transform: Com<Transform>,
) {
let position = quad.position - quad.size / 2.0;
// let position = transform.0 - quad.size / 2.0;
let position = transform.value.w_axis().truncate() - (node.size / 2.0).extend(0.0);
let mut drawable_text = DrawableText::new(
fonts.get(&label.font).unwrap(),
font_atlas_sets
@ -77,7 +81,7 @@ impl Label {
&texture_atlases,
&mut render_resource_bindings,
&mut asset_render_resource_bindings,
Vec3::new(position.x(), position.y(), quad.z_index),
position,
&label.style,
&label.text,
);

View File

@ -73,7 +73,6 @@ fn setup(
// texture
.add_entity(LabelEntity {
node: Node::new(
math::vec2(0.0, 0.0),
Anchors::TOP_LEFT,
Margins::new(0.0, 250.0, 0.0, 60.0),
),

View File

@ -29,7 +29,6 @@ fn setup(command_buffer: &mut CommandBuffer, asset_server: Res<AssetServer>) {
// texture
.add_entity(LabelEntity {
node: Node::new(
math::vec2(0.0, 0.0),
Anchors::TOP_LEFT,
Margins::new(0.0, 250.0, 0.0, 60.0),
),

View File

@ -60,7 +60,6 @@ fn setup(
// left vertical fill
.add_entity(UiEntity {
node: Node::new(
math::vec2(0.0, 0.0),
Anchors::LEFT_FULL,
Margins::new(10.0, 200.0, 10.0, 10.0),
),
@ -70,7 +69,6 @@ fn setup(
.add_children(|builder| {
builder.add_entity(LabelEntity {
node: Node::new(
math::vec2(0.0, 0.0),
Anchors::TOP_LEFT,
Margins::new(10.0, 200.0, 40.0, 10.0),
),
@ -88,7 +86,6 @@ fn setup(
// right vertical fill
.add_entity(UiEntity {
node: Node::new(
math::vec2(0.0, 0.0),
Anchors::RIGHT_FULL,
Margins::new(10.0, 100.0, 100.0, 100.0),
),
@ -97,7 +94,7 @@ fn setup(
})
// render order test: reddest in the back, whitest in the front
.add_entity(UiEntity {
node: Node::new(
node: Node::positioned(
math::vec2(75.0, 60.0),
Anchors::CENTER,
Margins::new(0.0, 100.0, 0.0, 100.0),
@ -106,7 +103,7 @@ fn setup(
..Default::default()
})
.add_entity(UiEntity {
node: Node::new(
node: Node::positioned(
math::vec2(50.0, 35.0),
Anchors::CENTER,
Margins::new(0.0, 100.0, 0.0, 100.0),
@ -115,7 +112,7 @@ fn setup(
..Default::default()
})
.add_entity(UiEntity {
node: Node::new(
node: Node::positioned(
math::vec2(100.0, 85.0),
Anchors::CENTER,
Margins::new(0.0, 100.0, 0.0, 100.0),
@ -124,7 +121,7 @@ fn setup(
..Default::default()
})
.add_entity(UiEntity {
node: Node::new(
node: Node::positioned(
math::vec2(150.0, 135.0),
Anchors::CENTER,
Margins::new(0.0, 100.0, 0.0, 100.0),
@ -134,7 +131,7 @@ fn setup(
})
// parenting
.add_entity(UiEntity {
node: Node::new(
node: Node::positioned(
math::vec2(210.0, 0.0),
Anchors::BOTTOM_LEFT,
Margins::new(0.0, 200.0, 10.0, 210.0),
@ -145,7 +142,6 @@ fn setup(
.add_children(|builder| {
builder.add_entity(UiEntity {
node: Node::new(
math::vec2(0.0, 0.0),
Anchors::FULL,
Margins::new(20.0, 20.0, 20.0, 20.0),
),
@ -155,7 +151,7 @@ fn setup(
})
// alpha test
.add_entity(UiEntity {
node: Node::new(
node: Node::positioned(
math::vec2(200.0, 185.0),
Anchors::CENTER,
Margins::new(0.0, 100.0, 0.0, 100.0),
@ -166,7 +162,6 @@ fn setup(
// texture
.add_entity(UiEntity {
node: Node::new(
math::vec2(0.0, 0.0),
Anchors::CENTER_TOP,
Margins::new(-250.0, 250.0, 510.0 * aspect, 10.0),
),

View File

@ -29,13 +29,14 @@ fn setup(command_buffer: &mut CommandBuffer, mut materials: ResMut<Assets<ColorM
let count = 1000;
for i in 0..count {
// 2d camera
let cur = Vec2::new(1.0, 1.0) * 1.0 + prev;
let cur = Vec2::new(1.0, 1.0) + prev;
builder.add_entity(UiEntity {
node: Node::new(
math::vec2(75.0, 75.0) + cur,
Anchors::new(0.5, 0.5, 0.5, 0.5),
Margins::new(0.0, 100.0, 0.0, 100.0),
),
node: Node {
position: Vec2::new(75.0, 75.0) + cur,
anchors: Anchors::new(0.5, 0.5, 0.5, 0.5),
margins: Margins::new(0.0, 100.0, 0.0, 100.0),
..Default::default()
},
material: materials.add(Color::rgb(0.0 + i as f32 / count as f32, 0.1, 0.1).into()),
..Default::default()
});

View File

@ -33,7 +33,7 @@ pub use crate::{
scene::{Scene, SceneSpawner},
sprite::{
entity::{SpriteEntity, SpriteSheetEntity},
ColorMaterial, Quad, Sprite, TextureAtlas, TextureAtlasSprite,
ColorMaterial, Sprite, TextureAtlas, TextureAtlasSprite,
},
text::{Font, TextStyle},
transform::prelude::*,