Replies: 2 comments
-
I like this idea quite a lot :). This makes spawning nested-widgets much easier. The problem is still that all your data needs to be available up front at the top-level widget, and conditional widgets. Imagine you had a widget like the following, to encapsulate between two widgets containing all the sub-widgets for your game UI or main menu UI, depending on whether the game has started or not: commands.spawn(node())
.conditional_child(game_started, game_blueprint, menu_blueprint) Conditionally spawning a child is doable here. What we could do is spawn both, and then hide one, and toggle the visibility between the two at runtime each frame with a system. That's how some of the existing bevy UI stuff I've seen works. The other is how to get data into and out of each widget. If you have some ECS data you'd like to display in your game's UI (e.g., the players current score) how do you get that into game_blueprint each frame? Along the same lines, how do you modify ECS data when a button is clicked? One option is sending events to a system. My conclusion is that widgets kind of need to act like systems. They need the ability to remove/insert/toggle visibility of their children each frame, to send events and trigger other system runs, to read ECS data, etc. |
Beta Was this translation helpful? Give feedback.
-
I find this somewhat related: https://www.reddit.com/r/bevy/comments/12qa1yw/having_trouble_returning_a_bundle_from_a_function/ |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi, It seems like the situation with spawning children did not improve for a while, so I'd like to point at some problems and discuss some possible solutions to that.
The major takes for me are:
Let's say you want to spawn some buttons using vanilla Bevy UI. A button consists of a
ButtonBundle
and aTextBundle
which is a child of the entity withButtonBundle
.Generally you can express that with this code:
That is well, great, not terrible... in case if you only have 1-3 buttons in your app, but if you have dozens of similar buttons whose only difference is their text this is starting to bloat the codebase. You can try to use loops of course, but there are some other problems with this API, let's move further:
What if you want your UI related stuff to live in another module so you can reuse and share your button spawning logic across whole app or maybe even different apps?
Sure, let's do it by implementing
Helper functions
The code seems to be a bit better, you can reuse your
create_button
function, but there are a couple of problems with that, and the main one is...Composability & reusability
What if you wanted to spawn a button that is child of some other entity? take for example
NodeBundle
. You can not directly do that. Well, you could returnEntity
fromcreate_bundle
, or even&mut EntityCommands
but that would require more code (and I didn't really figured out a way of doing that) and then add children in your host code, or you could useset_parent
and pass your parent around somehow (e.g. in anOption
) but that is more code, and more code is not great. Another thing you can't do with it is to 'merge' it with components of another entity (like you would usinginsert
)Another problem is that using commands in this way does not feels quite right... I mean you generally use it in builder fashion, but here you need to pass a mutable reference to it to a function that does some stuff, that is not perfect.
Analysis
as of Bevy 0.10 we have
Commands
:spawn(bundle) -> EntityCommands
,spawn_empty() -> EntityCommands
,add(command)
...EntityCommands
:insert(bundle) -> Self
,remove(bundle) -> Self
,with_children(|ChildBuilder|...) -> Self
add(entity_command) -> Self
ChildBuilder
:spawn(bundle) -> EntityCommands
,spawn_empty() -> EntityCommands
,add_command(command) -> Self
Possible solutions
Ideally I'd like the API to look like this:
these 'constructor' or 'blueprint' functions (I'm not sure how we want to name them) might look like so:
Here blueprint is some object that provide subset of commands API so you can easily use it inside your function without worrying much about the lifetimes and stuff.
Note, that blueprint's
spawn
method is a bit more likechild_or_spawn
because when this blueprint gets added using toplevel commands it will simply spawn a new entity, but when called in chain on existing entity it will be added as a child entity:Conclusion
Current state of
Commands
does not play well with reusing logic of creating nested entity structures, I wish that we can improve it.P.S. all of it is quite opinionated, I'm happy to hear what you thing about it, what could be improved and how all of that could be implemented.
Beta Was this translation helpful? Give feedback.
All reactions