-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
Adding a progress-bar widget #6517
Conversation
@bzm3r review plz! |
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.
Specific feedback about this widget:
- genuinely useful
- needs to be more robust to misconfiguration and alternate use cases: vertical orientation, LTR, etc
- needs a name that encourages devs to use it as e.g. a life bar.
ProgressBar
maybe? - needs an example demonstrating how to use and position it in screen space (yeah I know this currently sucks)
General thoughts:
- the "spawn complex trees of widgets" pattern is miserable. So much boilerplate, so hard to parse
- updating the value of data within components is great
- I worry about the poor scaling of O(n) change detection systems every frame for elements that rarely change. A push-based model feels more natural for thing like buttons
- differentiating widgets of the same type is going to get annoying without general-purpose relations unless you use an event-based architecture (which is annoying in its own ways)
- widgets really feel like they belong in their own
bevy_widgets
crate? - I really want to be able to disable / not include systems for widgets I'm not using in my game: the random perf loss every single frame bothers me
We should also setup a new category of examples for widgets IMO. Should these two things happen in this PR, or somewhere else? |
- Start cleanup
I think in this PR: it's already going to be controversial, so let's do this right from the start. |
- Add direction parameter
@@ -67,6 +68,7 @@ bevy_scene = ["bevy_internal/bevy_scene"] | |||
bevy_sprite = ["bevy_internal/bevy_sprite"] | |||
bevy_text = ["bevy_internal/bevy_text"] | |||
bevy_ui = ["bevy_internal/bevy_ui"] | |||
bevy_widget = ["bevy_internal/bevy_widget"] |
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 don't really know if this is the correct setup, please let me know how to adjust.
/// Maps a value from one range of values to a new range of values. | ||
pub fn map_range(value: f32, old_range: (f32, f32), new_range: (f32, f32)) -> f32 { | ||
(value - old_range.0) / (old_range.1 - old_range.0) * (new_range.1 - new_range.0) + new_range.0 | ||
} |
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.
Added this to bevy_math: Couldn't find anything that was already providing the same functionality but I may be mistaken.
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.
How do we make this discoverable for others down the line?
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.
How do we make this discoverable for others down the line?
Perhaps as an extension to either scalars or Range
values, such that we can have either value.map_range(a..b, c..d)
or (a..b).map_range(c..d, value)
? In the former case the intervals are more intuitive (a..b
is clearly the "old" range of value
), whereas in the latter the arguments would be reversed, such that a..b
becomes the output range.
// ui camera | ||
commands.spawn(Camera2dBundle::default()); | ||
|
||
// background that fills the entire viewport |
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.
Is this necessary? Why not just use the default clear color of bevy? I'm not really against this, but just trying to see where the example could be simplified a little.
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 guess you need the root node to take the whole screen to center the progress bar?
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.
Yes. Previously we have been using auto-margin to centre elements on the page. This is not the best practice, see #6535. In order to centre the element you need the parent element to cover the whole area.
The root / background does not strictly need a background colour, I added it for stylistic choices but can remove it if desired.
I'd like to see support for generics for min, max, progress values if that is reasonable. (Most of my use of progress bars are based on {u,i}N values) This implementation should likely be coordinating with the proposed UI slider widget WRT internal representation of progress. |
I'm not too versed in generic rust yet, so I'm not entirely sure how that would look but if you'd provide a code snippet of what that would look like, I'm happy to include it :) |
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 like this.
/// Maps a value from one range of values to a new range of values. | ||
pub fn map_range(value: f32, old_range: (f32, f32), new_range: (f32, f32)) -> f32 { | ||
(value - old_range.0) / (old_range.1 - old_range.0) * (new_range.1 - new_range.0) + new_range.0 | ||
} |
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.
How do we make this discoverable for others down the line?
|
||
impl Plugin for WidgetPlugin { | ||
fn build(&self, app: &mut App) { | ||
app.register_type::<ProgressBarWidget>() |
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'm not sure about ProgressBar
as a name. The core widget here seems to be much more general than just a bar for progress.
A rough idea for a more general/useful name: ResourceMeter
? Not sold on that idea, but it is more general?
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.
In general UI terminology, the name of the widget is usually "ProgressBar".
- https://material.angular.io/components/progress-bar/overview
- https://react-bootstrap.github.io/components/progress/
- https://docs.unity3d.com/ScriptReference/UIElements.ProgressBar.html
- https://docs.unrealengine.com/4.27/en-US/API/Runtime/UMG/Components/UProgressBar/
- https://docs.godotengine.org/en/stable/classes/class_progressbar.html
A loading screen, a health bar, mana bar, XP bar, various resource trackers you find in games are just specific implementations of that widget.
/// Creates a new [`ProgressBarWidget`]. | ||
pub fn new(progress: f32, min: f32, max: f32) -> Self { | ||
if min > max { | ||
panic!("Min should not be larger than max"); |
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.
Would it be sufficient to just put an assert here? assert(!(min > max), "Min should not be larger than max")
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.
Yeah that might be a better option
Backlog cleanup: closing due to inactivity, and in light of the significant development effort surrounding Bevy editor which will be surfacing any amount of new UI/widgets. |
Objective
Solution
2022-11-07.22-47-29.mp4
NodeBundle
with aProgressBarWidget
-component attached, that has a childNodeBundle
with aProgressBarInner
-component.Changelog
Added
Notes