This is probably a super basic thing as I'm very new to this but I'm kinda stumped. So far I only played around a bit with Bevy UI stuff. I saw in examples how you can use Interaction of buttons to affect them. But I added some UI (a node with some content) and want to update that UI on some custom trigger. I can implement the trigger in another system, but then I don't have access to the UI components I added in that system. How can I specify this node to modify it in my trigger system? Any query I can think of could only select all nodes, not this in particular. Do I need to spawn some custom entity containing the node instead of a vanilla node? Do I need to store a reference to the node in a resource?
#How to modify entity on custom trigger
19 messages · Page 1 of 1 (latest)
i think you are thinking of Observers
create an Event, create a system that has the FIRST paramenter as Trigger<Event>, and when creating the entity of the UI node also use .observe(system_name)
#[derive(Event)]
struct UiEvent;
fn system_on_ui_event(trigger: Trigger<UiEvent>, ...) {
...
}
fn create_ui_node(mut commands: Commands) {
commands.spawn(Node { ... }).observe(system_on_ui_event);
}
fn trigger_ui_event(mut commands: Commands, ...) {
if <condition> {
commands.trigger(UiEvent);
}
}
Remember that you can also always create marker components, add them to your Ui nodes, and query for them that way.
If your nodes are unique, storing the Entity id in resource is not a bad idea. But if you can have mulitple of such nodes and need general logic for them, then marker components will be better.
For some reason my observer system doesn't get called
#[derive(Eq, PartialEq)]
enum Sidebar {
Closed,
Open,
}
#[derive(Event)]
struct SidebarEvent(Sidebar);
fn build_gui(mut commands: Commands) {
let mut menu = commands.spawn(NodeBundle {...});
menu.observe(sidebar_observer);
}
fn sidebar_observer(
trigger: Trigger<SidebarEvent>,
mut style_query: Query<&mut Style>,
) {
if let Ok(mut style) = style_query.get_mut(trigger.entity()) {
if trigger.event().0 == Sidebar::Open {
println!("Sidebar opening!");
style.display = Display::Block;
} else {
println!("Sidebar closing!");
style.display = Display::None;
}
} else {
println!("Can't find sidebar :( ({:?})", trigger.entity())
}
}
fn cursor_pos_system(
mut mouse_motion_events: EventReader<CursorMoved>,
mut commands: Commands
) {
for ev in mouse_motion_events.read() {
if ev.position.y < 50.0 {
println!("Sending Open event");
commands.trigger(SidebarEvent(Sidebar::Open))
}
if ev.position.y > 350.0 {
println!("Sending Closed event");
commands.trigger(SidebarEvent(Sidebar::Closed))
}
}
}
fn build(&self, app: &mut App) {
app.add_systems(Startup, build_gui);
app.add_systems(Update, cursor_pos_system);
}
I'm getting the output from cursor_pos_system but none from sidebar_observer
I did it with a resource now. Figured a marker component wouldn't make much sense as all the logic makes assumptions about the position and size of the sidebar.
#[derive(Default, Resource)]
struct SidebarRes {
entity: Option<Entity>,
open: bool,
}
fn update_sidebar(
mut sidebar: ResMut<SidebarRes>,
mut style_query: Query<&mut Style>,
mut mouse_motion_events: EventReader<CursorMoved>,
) {
for ev in mouse_motion_events.read() {
let margin: f32 = 20.0;
if ev.position.y < margin && !sidebar.open {
if let Ok(mut style) = style_query.get_mut(sidebar.entity.unwrap()) {
style.display = Display::Block;
sidebar.open = true;
}
}
if ev.position.y > SIDEBAR_HEIGHT + margin && sidebar.open {
if let Ok(mut style) = style_query.get_mut(sidebar.entity.unwrap()) {
style.display = Display::None;
sidebar.open = false;
}
}
}
}
Next up, I'll try to figure out if I can animate the transition...
I haven't used an observer on entities yet, so I didn't know if you had to pass the entity or not
Then you need to use .trigger_with_targets and pass the menu's Entity
But looking at your code I think you can do it by using a button node and checking it the button is hovered
And translate the menu if the button is hovered or not
Not translate, change the display
For transitions, make sure to animate Style property. Don't change transforms directly as Style owns those and you will see constant glitches and fights between Style setup and your manual changes. I made small entry about it with some code here: #showcase message
Importnat note on the Resource approach: When you do query like Query<&mut Style> you are blocking any other system using Style components form executing in parallel(since you have option to mutable borrow any entity with that component). Adding marker components allow Bevy to figure out disjoint sets and run them in parallel.
It doesn't matter now for you, but it's good to have that in mind for times when you will work on more intensive parts of your game.
You're saying there that bevy ui is currently somewhat limited or tedious? Would you recommend using a different UI lib if I need a lot of UI in my game? I saw that egui has bevy support.
I think I'll rewrite the same sidebar I did here in bevy_egui to test it
I wouldn't say that. You just need to be aware how it works and not everything is yet documented. But exploring other options is always a good idea.
I'm referring to
I wanted to do it differently but discovered it would be very hard with current UI in Bevy so I backtracked to this simpler version