-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add overflow_debug
example
#8198
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
ee2c30c
Add basic `overflow_debug` example
doup 1360f68
Toggle animation with space
doup 2407634
Apply suggestions from code review
cart b49ba6c
Update examples readme
cart cc73370
Merge remote-tracking branch 'origin/main' into pr/doup/8198
cart File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,303 @@ | ||
//! Tests how different transforms behave when clipped with `Overflow::Hidden` | ||
use bevy::prelude::*; | ||
use std::f32::consts::{FRAC_PI_2, PI, TAU}; | ||
|
||
const CONTAINER_SIZE: f32 = 150.0; | ||
const HALF_CONTAINER_SIZE: f32 = CONTAINER_SIZE / 2.0; | ||
const LOOP_LENGTH: f32 = 4.0; | ||
|
||
fn main() { | ||
App::new() | ||
.add_plugins(DefaultPlugins) | ||
// TODO: Remove once #8144 is fixed | ||
.insert_resource(GizmoConfig { | ||
enabled: false, | ||
..default() | ||
}) | ||
.insert_resource(AnimationState { | ||
playing: false, | ||
paused_at: 0.0, | ||
paused_total: 0.0, | ||
t: 0.0, | ||
}) | ||
.add_systems(Startup, setup) | ||
.add_systems( | ||
Update, | ||
( | ||
toggle_overflow, | ||
next_container_size, | ||
update_transform::<Move>, | ||
update_transform::<Scale>, | ||
update_transform::<Rotate>, | ||
update_animation, | ||
), | ||
) | ||
.run(); | ||
} | ||
|
||
#[derive(Resource)] | ||
struct AnimationState { | ||
playing: bool, | ||
paused_at: f32, | ||
paused_total: f32, | ||
t: f32, | ||
} | ||
|
||
#[derive(Component)] | ||
struct Container(u8); | ||
|
||
trait UpdateTransform { | ||
fn update(&self, t: f32, transform: &mut Transform); | ||
} | ||
|
||
#[derive(Component)] | ||
struct Move; | ||
|
||
impl UpdateTransform for Move { | ||
fn update(&self, t: f32, transform: &mut Transform) { | ||
transform.translation.x = (t * TAU - FRAC_PI_2).sin() * HALF_CONTAINER_SIZE; | ||
transform.translation.y = -(t * TAU - FRAC_PI_2).cos() * HALF_CONTAINER_SIZE; | ||
} | ||
} | ||
|
||
#[derive(Component)] | ||
struct Scale; | ||
|
||
impl UpdateTransform for Scale { | ||
fn update(&self, t: f32, transform: &mut Transform) { | ||
transform.scale.x = 1.0 + 0.5 * (t * TAU).cos().max(0.0); | ||
transform.scale.y = 1.0 + 0.5 * (t * TAU + PI).cos().max(0.0); | ||
} | ||
} | ||
|
||
#[derive(Component)] | ||
struct Rotate; | ||
|
||
impl UpdateTransform for Rotate { | ||
fn update(&self, t: f32, transform: &mut Transform) { | ||
transform.rotation = Quat::from_axis_angle(Vec3::Z, ((t * TAU).cos() * 45.0).to_radians()); | ||
} | ||
} | ||
|
||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { | ||
// Camera | ||
commands.spawn(Camera2dBundle::default()); | ||
|
||
commands | ||
.spawn(NodeBundle { | ||
style: Style { | ||
size: Size::width(Val::Percent(100.)), | ||
flex_direction: FlexDirection::Column, | ||
..default() | ||
}, | ||
..default() | ||
}) | ||
.with_children(|parent| { | ||
parent | ||
.spawn(NodeBundle { | ||
style: Style { | ||
size: Size::height(Val::Px(32.)), | ||
align_items: AlignItems::Center, | ||
justify_content: JustifyContent::Center, | ||
..default() | ||
}, | ||
background_color: Color::DARK_GRAY.into(), | ||
..default() | ||
}) | ||
.with_children(|parent| { | ||
parent.spawn(TextBundle::from_section( | ||
vec![ | ||
"Toggle Overflow (O)", | ||
"Next Container Size (S)", | ||
"Toggle Animation (space)", | ||
] | ||
.join(" · "), | ||
TextStyle { | ||
font: asset_server.load("fonts/FiraSans-Bold.ttf"), | ||
font_size: 18.0, | ||
color: Color::WHITE, | ||
}, | ||
)); | ||
}); | ||
|
||
parent | ||
.spawn(NodeBundle { | ||
style: Style { | ||
flex_grow: 1., | ||
flex_direction: FlexDirection::Column, | ||
..default() | ||
}, | ||
..default() | ||
}) | ||
.with_children(|parent| { | ||
spawn_row(parent, |parent| { | ||
spawn_image(parent, &asset_server, Move); | ||
spawn_image(parent, &asset_server, Scale); | ||
spawn_image(parent, &asset_server, Rotate); | ||
}); | ||
|
||
spawn_row(parent, |parent| { | ||
spawn_text(parent, &asset_server, Move); | ||
spawn_text(parent, &asset_server, Scale); | ||
spawn_text(parent, &asset_server, Rotate); | ||
}); | ||
}); | ||
}); | ||
} | ||
|
||
fn spawn_row(parent: &mut ChildBuilder, spawn_children: impl FnOnce(&mut ChildBuilder)) { | ||
parent | ||
.spawn(NodeBundle { | ||
style: Style { | ||
size: Size::width(Val::Percent(50.)), | ||
align_items: AlignItems::Center, | ||
justify_content: JustifyContent::SpaceEvenly, | ||
..default() | ||
}, | ||
..default() | ||
}) | ||
.with_children(spawn_children); | ||
} | ||
|
||
fn spawn_image( | ||
parent: &mut ChildBuilder, | ||
asset_server: &Res<AssetServer>, | ||
update_transform: impl UpdateTransform + Component, | ||
) { | ||
spawn_container(parent, update_transform, |parent| { | ||
parent.spawn(ImageBundle { | ||
image: UiImage::new(asset_server.load("branding/bevy_logo_dark_big.png")), | ||
style: Style { | ||
size: Size::height(Val::Px(100.)), | ||
position_type: PositionType::Absolute, | ||
top: Val::Px(-50.), | ||
left: Val::Px(-200.), | ||
..default() | ||
}, | ||
..default() | ||
}); | ||
}); | ||
} | ||
|
||
fn spawn_text( | ||
parent: &mut ChildBuilder, | ||
asset_server: &Res<AssetServer>, | ||
update_transform: impl UpdateTransform + Component, | ||
) { | ||
spawn_container(parent, update_transform, |parent| { | ||
parent.spawn(TextBundle::from_section( | ||
"Bevy", | ||
TextStyle { | ||
font: asset_server.load("fonts/FiraSans-Bold.ttf"), | ||
font_size: 120.0, | ||
color: Color::WHITE, | ||
}, | ||
)); | ||
}); | ||
} | ||
|
||
fn spawn_container( | ||
parent: &mut ChildBuilder, | ||
update_transform: impl UpdateTransform + Component, | ||
spawn_children: impl FnOnce(&mut ChildBuilder), | ||
) { | ||
let mut transform = Transform::default(); | ||
|
||
update_transform.update(0.0, &mut transform); | ||
|
||
parent | ||
.spawn(( | ||
NodeBundle { | ||
style: Style { | ||
size: Size::new(Val::Px(CONTAINER_SIZE), Val::Px(CONTAINER_SIZE)), | ||
align_items: AlignItems::Center, | ||
justify_content: JustifyContent::Center, | ||
overflow: Overflow::Hidden, | ||
..default() | ||
}, | ||
background_color: Color::DARK_GRAY.into(), | ||
..default() | ||
}, | ||
Container(0), | ||
)) | ||
.with_children(|parent| { | ||
parent | ||
.spawn(( | ||
NodeBundle { | ||
style: Style { | ||
align_items: AlignItems::Center, | ||
justify_content: JustifyContent::Center, | ||
top: Val::Px(transform.translation.x), | ||
left: Val::Px(transform.translation.y), | ||
..default() | ||
}, | ||
transform, | ||
..default() | ||
}, | ||
update_transform, | ||
)) | ||
.with_children(spawn_children); | ||
}); | ||
} | ||
|
||
fn update_animation( | ||
mut animation: ResMut<AnimationState>, | ||
time: Res<Time>, | ||
keys: Res<Input<KeyCode>>, | ||
) { | ||
let time = time.elapsed_seconds(); | ||
|
||
if keys.just_pressed(KeyCode::Space) { | ||
animation.playing = !animation.playing; | ||
|
||
if !animation.playing { | ||
animation.paused_at = time; | ||
} else { | ||
animation.paused_total += time - animation.paused_at; | ||
} | ||
} | ||
|
||
if animation.playing { | ||
animation.t = (time - animation.paused_total) % LOOP_LENGTH / LOOP_LENGTH; | ||
} | ||
} | ||
|
||
fn update_transform<T: UpdateTransform + Component>( | ||
animation: Res<AnimationState>, | ||
mut containers: Query<(&mut Transform, &mut Style, &T)>, | ||
) { | ||
for (mut transform, mut style, update_transform) in &mut containers { | ||
update_transform.update(animation.t, &mut transform); | ||
|
||
style.left = Val::Px(transform.translation.x); | ||
style.top = Val::Px(transform.translation.y); | ||
} | ||
} | ||
|
||
fn toggle_overflow(keys: Res<Input<KeyCode>>, mut containers: Query<&mut Style, With<Container>>) { | ||
if keys.just_pressed(KeyCode::O) { | ||
for mut style in &mut containers { | ||
style.overflow = match style.overflow { | ||
Overflow::Visible => Overflow::Hidden, | ||
Overflow::Hidden => Overflow::Visible, | ||
}; | ||
} | ||
} | ||
} | ||
|
||
fn next_container_size( | ||
keys: Res<Input<KeyCode>>, | ||
mut containers: Query<(&mut Style, &mut Container)>, | ||
) { | ||
if keys.just_pressed(KeyCode::S) { | ||
for (mut style, mut container) in &mut containers { | ||
container.0 = (container.0 + 1) % 3; | ||
|
||
style.size = match container.0 { | ||
1 => Size::new(Val::Px(CONTAINER_SIZE), Val::Px(30.)), | ||
2 => Size::new(Val::Px(30.), Val::Px(CONTAINER_SIZE)), | ||
_ => Size::new(Val::Px(CONTAINER_SIZE), Val::Px(CONTAINER_SIZE)), | ||
}; | ||
} | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe needs some comments here because the plan has been to move away from using the
Transform
hierarchy for UI nodes. Also, the layout only supports rectangular axis-aligned UI nodes so modifying theTransform
on nodes with children especially can just end up in a mess. So users need to be warned against naively applying arbitrary rotations and scaling like they would with sprites and expecting it to just work.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, I know
transform
should be derived from style… but didn't find any other way to change scale/rotation. I wanted to force scale/rotation (translation it's used to update top/left) to see how it behaves.Although, now that I think about it… maybe it doesn't make any sense to put these in the example if it's not a current feature. Or… it could be used to fix scale/rotation? Although, probably this should be done at shader/stencil/mask/whatever… level; using textures and composition and not by cutting geometry. (?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been working on #8240 which fixes some of the problems, but I'm not too sure about the API though.
It's not necessarily a problem that the example cases don't all display correctly, we could just put a WIP label or something. Users need to be aware that the clipping is very basic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually thinking about it this will be really good to adapt to use as a test case for the UI Transform PR if you don't mind 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, I had a surgery a couple of days ago, I don't think I'll check the PRs anytime soon. Please fork it and do as you wish.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think its reasonable to merge this as-is. Just make whatever changes are needed in #8240.