#rust #bevy
#Ржавчина #стайка
Вопрос:
Я довольно новичок в rust и новичок в bevy. Я понимаю, что это первые дни, и мне очень нравится bevy, но, честно говоря, я нахожу, что примеров и документов немного не хватает.
Я использую в /examples/ui/button.rs
качестве отправной точки. И я хочу добавить кучу кнопок вместо одной.
Я ищу способ отличить, какая кнопка была нажата.
Я понимаю, что мог бы добавить систему для каждой кнопки, но это не может быть правильным способом на любом языке.
Итак, я начал добавлять маркеры (как предлагает bevy-cheatsheet).
commands
.spawn(ButtonComponents { /* cut for brevity */ })
.with_children(|parent| {
parent
.spawn(TextComponents { /* cut for brevity */ })
.with(Marker1);
});
Но как мне тогда проверить, с каким маркером была создана кнопка?
fn button_system(
button_materials: Res<ButtonMaterials>,
mut interaction_query: Query<(
amp;Button,
Mutated<Interaction>,
amp;mut Handle<ColorMaterial>,
amp;Children,
)>,
text_query: Query<amp;mut Text>,
) {
for (_button, interaction, mut material, children) in amp;mut interaction_query.iter() {
let mut text = text_query.get_mut::<Text>(children[0]).unwrap();
match *interaction {
Interaction::Clicked => {
// This obviously doesn't work, just to illustrate what I'm looking for.
match text.spawned_with {
Marker1 => doSomething(),
Marker2 => doBarrelRoll(),
_ => unreachable!()
}
}
Interaction::Hovered => {
text.value = "Hover".to_string();
*material = button_materials.hovered.clone();
}
Interaction::None => {
text.value = "Button".to_string();
*material = button_materials.normal.clone();
}
}
}
}
Любые подсказки приветствуются, спасибо!
Редактировать: И теперь я в замешательстве, потому что это действительно работает для кнопки 1 (но сбой button2):
Interaction::Clicked => {
let marker = text_query.get::<_>(children[0]).unwrap();
match *marker {
Marker1 => println!("marker 1"),
_ => unreachable!(),
}
}
Но это даже не создает:
let marker = text_query.get::<_>(children[0]).unwrap();
match *marker {
Marker1 => println!("marker 1"),
Marker2 => println!("marker 2"),
_ => unreachable!(),
}
Это ошибка:
| expected struct `Marker1`, found struct `Marker2`
| `Marker2` is interpreted as a unit struct, not a new binding
| help: introduce a new binding instead: `other_marker2`
Ответ №1:
Хорошо, я нашел ответ, но если у вас есть что-то более элегантное, я был бы рад узнать и сделать это вместо правильного ответа!
Interaction::Clicked => {
if let Ok(_) = text_query.get::<Marker1>(children[0]) {
println!("marker 1")
}
if let Ok(_) = text_query.get::<Marker2>(children[0]) {
println!("marker 2")
}
if let Ok(_) = text_query.get::<Marker3>(children[0]) {
doBarrelRoll()
}
...
}
После комментария Даниэля Кулманса я получил что-то вроде этого:
#[derive(PartialEq)] // needed for comparison
pub enum Buttons {
MyFirstButton,
MySecondButton,
}
struct MyButton {
target: Buttons,
}
И…
commands
.spawn(ButtonComponents { /* cut for brevity */ })
.with_children(|parent| {
parent
.spawn(TextComponents { /* cut for brevity */ })
.with(MyButton { target: Buttons });
});
И…
Interaction::Clicked => {
if let Ok(btn) = text_query.get_mut::<MyButton>(children[0]) {
match btn.target {
Buttons::MyFirstButton => {
...
},
Buttons::MySecondButton => {
...
},
_ => unreachable!(),
}
}
}
Комментарии:
1. Я понятия не имею, как работает bevy, но я предполагаю, что вы должны использовать не пустую структуру маркера, а структуру, содержащую целое число, которое сообщает вам, какая кнопка была нажата.
2. @danielkullmann Super! я думаю, это привело меня к достойному решению.
Ответ №2:
Хотя я почти на два года опоздал с обсуждением, сегодня я столкнулся с той же проблемой и думаю, что нашел хорошее решение. Я черпал вдохновение из оригинального сообщения @ ippi, где они использовали пустые структуры маркеров. Эти структуры также описаны здесь: https://bevy-cheatbook.github.io/programming/queries.html .
Итак, давайте предположим, что у нас есть две кнопки в пользовательском интерфейсе. Кнопка запуска и кнопка выхода. Сначала мы добавляем структуры маркеров для обеих кнопок:
#[derive(Component)]
struct StartButtonMarker;
#[derive(Component)]
struct QuitButtonMarker;
Во-вторых, мы создаем обе кнопки с их соответствующими структурами маркеров, добавленными к ним в качестве компонентов (с использованием insert
).
commands.spawn_bundle(ButtonBundle { /* snip */ }).insert(StartButtonMarker);
commands.spawn_bundle(ButtonBundle { /* snip */ }).insert(QuitButtonMarker);
Теперь в нашей системе мы можем запрашивать оба маркера как необязательные значения (используя Option<T>
тип). Затем мы можем проверить, существует ли маркер для объекта, используя is_some
функцию в экземпляре опции:
fn update(
mut query: Query<
(
amp;Interaction,
(Option<amp;StartButtonMarker>, Option<amp;QuitButtonMarker>),
),
(Changed<Interaction>, With<Button>),
>,
) {
for (interaction, (marker_start, marker_quit)) in amp;mut query {
if *interaction == Interaction::Clicked {
if marker_start.is_some() {
println!("Start button pressed");
}
if marker_quit.is_some() {
println!("Quit button pressed");
}
}
}
}