iyesgames / iyes_loopless Goto Github PK
View Code? Open in Web Editor NEWAlternatives to Bevy States, FixedTimestep, Run Criteria, that do not use "stage looping" and are composable
License: Other
Alternatives to Bevy States, FixedTimestep, Run Criteria, that do not use "stage looping" and are composable
License: Other
I attempted to update my project to Bevy 0.9, which was just released a few days ago, and the majority of the iyes_loopless functionality broke.
Specifically, it seems most of the new methods added to App
are not being found, like add_loopless_state
, add_exit_system
and add_enter_system
. These all have the very simple error in the form:
no method named `add_loopless_state` found for struct `bevy::prelude::App` in the current scope
It also can't find the run_in_state
method when I try to call it on one of my systems when adding it to the app. It works when called directly on a ConditionSet
(or at least I'm not seeing a compilation error on it yet). The error I get on this is much more complicated and hard to make sense of, given the extensive layered generics. This is an example:
the method `run_in_state` exists for fn item `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7> fn(bevy::prelude::Commands<'r, 's>, bevy::prelude::Query<'t0, 't1, (&'t2 mut ButtonInteraction, &'t3 PowerButton)>, bevy::prelude::Query<'t4, 't5, &'t6 mut PowerMenu>, bevy::prelude::Res<'t7, bevy::prelude::Input<bevy::prelude::KeyCode>>) {power_menu_ui_system}`, but its trait bounds were not satisfied
the following trait bounds were not satisfied:
`for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7> fn(bevy::prelude::Commands<'r, 's>, bevy::prelude::Query<'t0, 't1, (&'t2 mut ButtonInteraction, &'t3 PowerButton)>, bevy::prelude::Query<'t4, 't5, &'t6 mut PowerMenu>, bevy::prelude::Res<'t7, bevy::prelude::Input<bevy::prelude::KeyCode>>) {power_menu_ui_system}: bevy_ecs::system::function_system::IntoSystem<(), (), _>`
which is required by `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7> fn(bevy::prelude::Commands<'r, 's>, bevy::prelude::Query<'t0, 't1, (&'t2 mut ButtonInteraction, &'t3 PowerButton)>, bevy::prelude::Query<'t4, 't5, &'t6 mut PowerMenu>, bevy::prelude::Res<'t7, bevy::prelude::Input<bevy::prelude::KeyCode>>) {power_menu_ui_system}: iyes_loopless::condition::IntoConditionalSystem<_>`
`&for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7> fn(bevy::prelude::Commands<'r, 's>, bevy::prelude::Query<'t0, 't1, (&'t2 mut ButtonInteraction, &'t3 PowerButton)>, bevy::prelude::Query<'t4, 't5, &'t6 mut PowerMenu>, bevy::prelude::Res<'t7, bevy::prelude::Input<bevy::prelude::KeyCode>>) {power_menu_ui_system}: bevy_ecs::system::function_system::IntoSystem<(), (), _>`
which is required by `&for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7> fn(bevy::prelude::Commands<'r, 's>, bevy::prelude::Query<'t0, 't1, (&'t2 mut ButtonInteraction, &'t3 PowerButton)>, bevy::prelude::Query<'t4, 't5, &'t6 mut PowerMenu>, bevy::prelude::Res<'t7, bevy::prelude::Input<bevy::prelude::KeyCode>>) {power_menu_ui_system}: iyes_loopless::condition::IntoConditionalSystem<_>`
`&mut for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7> fn(bevy::prelude::Commands<'r, 's>, bevy::prelude::Query<'t0, 't1, (&'t2 mut ButtonInteraction, &'t3 PowerButton)>, bevy::prelude::Query<'t4, 't5, &'t6 mut PowerMenu>, bevy::prelude::Res<'t7, bevy::prelude::Input<bevy::prelude::KeyCode>>) {power_menu_ui_system}: bevy_ecs::system::function_system::IntoSystem<(), (), _>`
which is required by `&mut for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7> fn(bevy::prelude::Commands<'r, 's>, bevy::prelude::Query<'t0, 't1, (&'t2 mut ButtonInteraction, &'t3 PowerButton)>, bevy::prelude::Query<'t4, 't5, &'t6 mut PowerMenu>, bevy::prelude::Res<'t7, bevy::prelude::Input<bevy::prelude::KeyCode>>) {power_menu_ui_system}: iyes_loopless::condition::IntoConditionalSystem<_>`
Also, Bevy now requires all resources to explicitly #[derive(Resource)]
. This is breaking the NextState
resource.
Further, the trait bounds that ConditionalSet::with_system
uses seems to be broken, as every single system I try to add that way is now generating an error that it does not implement the required trait bounds. The error message is again a mess of layered generics that's hard to make sense of, but this is an example, pulled from one of my simplest systems:
the trait bound `for<'r, 's, 't0, 't1, 't2> fn(bevy::prelude::Res<'r, bevy::prelude::Time>, bevy::prelude::Query<'s, 't0, (&'t1 Drag, &'t2 mut Velocity)>) {drag_system}: bevy_ecs::system::function_system::IntoSystem<(), (), _>` is not satisfied
the trait `AddConditionalToSet<ConditionSystemSet, ()>` is implemented for `ConditionalSystemDescriptor`
required for `for<'r, 's, 't0, 't1, 't2> fn(bevy::prelude::Res<'r, bevy::prelude::Time>, bevy::prelude::Query<'s, 't0, (&'t1 Drag, &'t2 mut Velocity)>) {drag_system}` to implement `iyes_loopless::condition::IntoConditionalSystem<_>`
required for `for<'r, 's, 't0, 't1, 't2> fn(bevy::prelude::Res<'r, bevy::prelude::Time>, bevy::prelude::Query<'s, 't0, (&'t1 Drag, &'t2 mut Velocity)>) {drag_system}` to implement `AddConditionalToSet<ConditionSystemSet, _>`r
I'm sure there are other incompatibilities as well, but these are the ones I'm currently seeing.
Currently, conditions have to be applied to each individual system, resulting in a lot of repetitive boilerplate.
Investigate what could be done to make it possible to apply conditions to many systems at once.
Bevy's system labeling apis may be a source of inspiration.
Whenever I start up my game, I get a message in the console about how my states are missing downcasts. I have no idea what it means, and I'm not sure it causes problems.
I would love it if run_if could take Local Arguments in. With the below code I get the following error:
.add_system(self::gamelobby::lobby.run_if(show_lobby_screen))
use super::{UIState, UIStateRes};
pub struct LobbyStateRes{
pub selected_map: String
}
pub fn lobby(mut egui_context: ResMut<EguiContext>, mut ui_state: ResMut<UIStateRes>, mut maps_manifest: ResMut<MapManifest>, mut lobby_state: Local<LobbyStateRes>) {
Window::new("Game Lobby")
.anchor(Align2::CENTER_CENTER, egui::vec2(0.0, -50.0))
.show(egui_context.ctx_mut(), |ui| {
egui::ScrollArea::vertical().show(ui, |ui|{
for map in &maps_manifest.map_files{
let sel_map_btn = ui.radio_value(&mut lobby_state.selected_map, map.clone(), map);
}
});
let play_btn = ui.button("Launch Game");
if play_btn.clicked() && lobby_state.selected_map != *"".to_string(){ //Such unrust shall not stand!
ui_state.current_state = UIState::Game
}
let back_btn = ui.button("Main Menu");
if back_btn.clicked() {
ui_state.current_state = UIState::MainMenu;
}
});
}
[{
"resource": "/e:/rust/macrophage/src/ui/mod.rs",
"owner": "rustc",
"code": {
"value": "E0599",
"target": {
"$mid": 1,
"external": "https://doc.rust-lang.org/error-index.html#E0599",
"path": "/error-index.html",
"scheme": "https",
"authority": "doc.rust-lang.org",
"fragment": "E0599"
}
},
"severity": 8,
"message": "the method `run_if` exists for fn item `for<'r, 's, 't0, 't1> fn(bevy::prelude::ResMut<'r, bevy_egui::EguiContext>, bevy::prelude::ResMut<'s, ui::UIStateRes>, bevy::prelude::ResMut<'t0, util::MapManifest>, bevy::prelude::Local<'t1, ui::gamelobby::LobbyStateRes>) {ui::gamelobby::lobby}`, but its trait bounds were not satisfied\nthe following trait bounds were not satisfied:\n`for<'r, 's, 't0, 't1> fn(bevy::prelude::ResMut<'r, bevy_egui::EguiContext>, bevy::prelude::ResMut<'s, ui::UIStateRes>, bevy::prelude::ResMut<'t0, util::MapManifest>, bevy::prelude::Local<'t1, ui::gamelobby::LobbyStateRes>) {ui::gamelobby::lobby}: bevy::prelude::IntoSystem<(), (), _>`\nwhich is required by `for<'r, 's, 't0, 't1> fn(bevy::prelude::ResMut<'r, bevy_egui::EguiContext>, bevy::prelude::ResMut<'s, ui::UIStateRes>, bevy::prelude::ResMut<'t0, util::MapManifest>, bevy::prelude::Local<'t1, ui::gamelobby::LobbyStateRes>) {ui::gamelobby::lobby}: iyes_loopless::condition::IntoConditionalSystem<_>`\n`&for<'r, 's, 't0, 't1> fn(bevy::prelude::ResMut<'r, bevy_egui::EguiContext>, bevy::prelude::ResMut<'s, ui::UIStateRes>, bevy::prelude::ResMut<'t0, util::MapManifest>, bevy::prelude::Local<'t1, ui::gamelobby::LobbyStateRes>) {ui::gamelobby::lobby}: bevy::prelude::IntoSystem<(), (), _>`\nwhich is required by `&for<'r, 's, 't0, 't1> fn(bevy::prelude::ResMut<'r, bevy_egui::EguiContext>, bevy::prelude::ResMut<'s, ui::UIStateRes>, bevy::prelude::ResMut<'t0, util::MapManifest>, bevy::prelude::Local<'t1, ui::gamelobby::LobbyStateRes>) {ui::gamelobby::lobby}: iyes_loopless::condition::IntoConditionalSystem<_>`\n`&mut for<'r, 's, 't0, 't1> fn(bevy::prelude::ResMut<'r, bevy_egui::EguiContext>, bevy::prelude::ResMut<'s, ui::UIStateRes>, bevy::prelude::ResMut<'t0, util::MapManifest>, bevy::prelude::Local<'t1, ui::gamelobby::LobbyStateRes>) {ui::gamelobby::lobby}: bevy::prelude::IntoSystem<(), (), _>`\nwhich is required by `&mut for<'r, 's, 't0, 't1> fn(bevy::prelude::ResMut<'r, bevy_egui::EguiContext>, bevy::prelude::ResMut<'s, ui::UIStateRes>, bevy::prelude::ResMut<'t0, util::MapManifest>, bevy::prelude::Local<'t1, ui::gamelobby::LobbyStateRes>) {ui::gamelobby::lobby}: iyes_loopless::condition::IntoConditionalSystem<_>`",
"source": "rustc",
"startLineNumber": 45,
"startColumn": 44,
"endLineNumber": 45,
"endColumn": 50,
"relatedInformation": [
{
"startLineNumber": 45,
"startColumn": 21,
"endLineNumber": 45,
"endColumn": 43,
"message": "this is a function, perhaps you wish to call it",
"resource": "/e:/rust/macrophage/src/ui/mod.rs"
}
]
}]
My problem is that I need to be able to change the simulation speed of my game but it seems there is no way of changing the timestep after creating the FixedTimestepStage
.
.add_stage_before(
CoreStage::Update,
"Enviroment",
FixedTimestepStage::from_stage(Duration::from_millis( 1.0 / BASE_FPS), enviromentStage),
)
fn sync_game_speed(
game_speed: Res<GameSpeed>,
mut rapier_config: ResMut<RapierConfiguration>,
){
rapier_config.timestep_mode = TimestepMode::Interpolated { dt: 1.0 / BASE_FPS as f32, time_scale: game_speed.0, substeps: 1 }
<<HERE I NEED TO CHANGE THE FixedTimestepStage TO THE SAME SPEED AS THE PHYSICS>>
}
Is this possible to do? Or should one use somthing like:
.add_system_set(
ConditionSet::new()
.run_in_state(AppState::Gaming)
.run_if(shouldRunSimulationTick) <- manual accumulator that can be dependent on GameSpeed resource
.with_system(simulation_system1)
.with_system(simulation_system2...)
.into()
Implement some helper methods to easily add common Run Conditions.
.run_on_event::<Event>()
.run_if_resource_exists::<Res>()
.run_if_resource_equals(value)
.run_unless_resource_exists::<Res>()
.run_unless_resource_equals(value)
Because of how our fixed timestep and states implementations rely on the user adding custom stages, that nest other stages, it is difficult to make this play nicely with Bevy's Plugin API.
If a plugin needs to add stuff to happen on state transitions, or on fixed timestep, it has no way of accessing the actual SystemStage
s to add systems to. Labels don't help, because Bevy's SystemLabel
s are a top-level Schedule
thing, and cannot refer to nested stages.
The only way right now seems to be to sidestep the Plugin API altogether, and just use functions that take &mut SystemStage
(for whatever they need access to) instead.
This might not be solvable while our stuff is in an external crate, and I cannot think of a better design. I'm open to ideas.
TL;DR: Is there a way to add system sets to the stages of a FixedTimestepStage
that has been added to my App
elsewhere?
How I understand the documentation one adds the FixedTimestepStage
into the scheduler, e.g. before the CoreStage::Update
. Then FixedTimestepStage
has sub-stages which are executed at the time-step. In a sub-stage, I can use label
s to order the execution of my systems using before
or after
. But say I want to make a plugin that adds a system set to one of these sub-stages, to be able to have access to these labels, how do I do that?
More concretely: I'm looking after a design in which I can have a plugin handling A
components, one plugin handling B
, and then one plugin handling their interaction. The interaction should take place after A
and B
have both been updated, so I can label the ConditionSet
s I have defined for A
and B
, but to have access to those labels it appears that all systems needs to be part of the same sub-stage. That is I imagine to be able to do something along these lines
impl Plugin for InitFixedTimestepStage {
fn build(&self, app: &mut App) {
app.add_stage_before(
CoreStage::Update,
"ft_label",
FixedTimestepStage::new(Duration::from_secs_f32(TIME_STEP))
.add_stage_with_label( // suggested method
"interaction_label",
SystemStage::parallel() // adding empty stage to add systems to later
)
)
}
}
impl Plugin for UpdateComponentA {
fn build(&self, app: &mut App) {
app.schedule
.get_stage_mut("ft_label").unwrap()
.get_stage_mut("interaction_label").unwrap() // suggested method
.add_system_set(
ConditionSet::new()
.label("update_A")
.with_system(update_A)
.into()
);
}
}
// same for B... then:
impl Plugin for InteractionAB {
fn build(&self, app: &mut App) {
app.schedule
.get_stage_mut("ft_label").unwrap()
.get_stage_mut("interaction_label").unwrap() // suggested method
.add_system_set(
ConditionSet::new()
.after("update_A") // This label...
.after("update_B") // ... and this label is now available as we are in stage "interaction_label"
.label("interact_AB")
.with_system(interact_AB)
.into()
);
}
}
This would make the plugins more modular, otherwise I'd have to design large plugins that has access to all systems at once.
Or is there a way to do this that I'm just missing?
It seems I must manually bring in iyes_loopless::condition::IntoConditionalExclusiveSystem
to support exclusive systems with conditions, however this appears to cause an ambiguity problem with non-exclusive systems if I bring it into the same scope. This example demonstrates my issue:
use bevy::prelude::*;
use iyes_loopless::prelude::*;
use iyes_loopless::condition::IntoConditionalExclusiveSystem;
fn main() {
App::new()
.add_plugins(MinimalPlugins)
.add_loopless_state(DevState::Loading)
.add_enter_system(DevState::Loading, setup)
.add_system(ready
.run_in_state(DevState::Ready)
.run_unless_resource_exists::<Thing>()
)
.add_system(process
.run_in_state(DevState::Loading)
.run_if_resource_exists::<Thing>()
.at_end()
)
.run()
;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DevState {
Loading,
Ready,
}
#[derive(Debug, Clone, Copy)]
pub struct Thing(pub u32);
fn setup(mut commands: Commands) {
commands.insert_resource(Thing(1));
}
fn ready(mut commands: Commands) {
println!("ready");
commands.insert_resource(Thing(2));
}
fn process(mut world: &mut World) {
println!("removed {:?}", world.remove_resource::<Thing>());
world.insert_resource(NextState(DevState::Ready));
}
--> examples\test.rs:11:14
|
11 | .run_in_state(DevState::Loading)
| ^^^^^^^^^^^^ multiple `run_in_state` found
|
= note: candidate #1 is defined in an impl of the trait `iyes_loopless::condition::IntoConditionalSystem` for the type `S`
= note: candidate #2 is defined in an impl of the trait `IntoConditionalExclusiveSystem` for the type `S`
note: candidate #3 is defined in the trait `iyes_loopless::condition::ConditionHelpers`
--> C:\Users\s33n\.cargo\registry\src\github.com-1ecc6299db9ec823\iyes_loopless-0.5.1\src\condition.rs:366:5
|
366 | fn run_in_state<T: bevy_ecs::schedule::StateData>(self, state: T) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: disambiguate the associated function for candidate #1
|
10 | .add_system(iyes_loopless::condition::IntoConditionalSystem::run_in_state(ready, DevState::Loading)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
help: disambiguate the associated function for candidate #2
|
10 | .add_system(IntoConditionalExclusiveSystem::run_in_state(ready, DevState::Loading)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
help: disambiguate the associated function for candidate #3
|
10 | .add_system(iyes_loopless::condition::ConditionHelpers::run_in_state(ready, DevState::Loading)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
One option I see is to fully qualify the extension for each exclusive system I add. This works, but seems verbose and ugly:
.add_system(iyes_loopless::condition::IntoConditionalExclusiveSystem::run_in_state(process,DevState::Loading)
.run_if_resource_exists::<Thing>()
.at_end()
)
Another option I've found is to scope the exclusive trait. This at least preserves the look and feel of the builder API, but still feels quite verbose:
use bevy::prelude::*;
use iyes_loopless::prelude::*;
fn main() {
let mut app = App::new();
app.add_plugins(MinimalPlugins)
.add_loopless_state(DevState::Loading)
.add_enter_system(DevState::Loading, setup)
.add_system(ready
.run_in_state(DevState::Ready)
.run_unless_resource_exists::<Thing>()
)
;
// scope for exclusive systems
{
use iyes_loopless::condition::IntoConditionalExclusiveSystem;
app.add_system(process
.run_in_state(DevState::Loading)
.run_if_resource_exists::<Thing>()
.at_end()
);
}
app.run();
}
Any better options?
Compiling iyes_loopless v0.7.1
error[E0433]: failed to resolve: could not find `state` in the crate root
--> C:\Users\Johan\.cargo\registry\src\github.com-1ecc6299db9ec823\iyes_loopless-0.7.1\src\lib.rs:13:20
|
13 | pub use crate::state::schedule::ScheduleLooplessStateExt;
| ^^^^^ could not find `state` in the crate root
For more information about this error, try `rustc --explain E0433`.
error: could not compile `iyes_loopless` due to previous error
Error: cargo command failed
error: process didn't exit successfully: `target\debug\xtask.exe dist ultra_bevy` (exit code: 1)
\"[Finished running. Exit status: 0]\"
Using the .label
method of ConditionSet
, using either a string or a basic derived SystemLabel
, results in a compile-time error:
the method `label` exists for struct `ConditionSystemSet`, but its trait bounds were not satisfied
To reproduce, add a .label
call to a ConditionSet
.
Discussed previously in this Discord thread.
I've switched from bevy state system into loopless
, because there wasn't any information about "setup" systems in it, only loop, but I've found such implementation there. But after I found out such realization in bevy cheatbook (which I've not remarked somehow), I've also seen such thing as "stacks" which lets you make implementation of "pause" state etc. Does similar thing exists in loopless
, or I need to get back to bevy systems?
P.S.: Or is there another way to implement pause menu or smth like this? Thx
By setting NextState on first run in line 122 in state.rs
the initial state will be switched to itself, thus triggering the exit and enter stages. If exit and enter are expensive (e.g. procedural generation) it will cause needless processing.
Link:
Line 122 in cf8e61b
It would be cool to provide a "tick timers" implementation that works with our FixedTimestep. Timers/Stopwatches that count timesteps, instead of real time durations.
Implement an alternative to use instead of Bevy's SystemStage
, which:
I noticed that this plugin just use is_empty function to check if an event was fired. But we need to user iter().count()
because otherwise if an event was called in startup system - a function with such condition will run twice. See this issue in Bevy repo: bevyengine/bevy#5663
Hello, I have an issue with systems ordering within a ConditionSet
.
With a standard SystemSet
, this works:
.with_system_set(
SystemSet::new()
.label("update")
.with_system(movement::apply_velocity)
.with_system(movement::constrain_entities.after(movement::apply_velocity)),
)
But with a ConditionSet
this doesn't:
.with_system_set(
ConditionSet::new()
.label("update")
.run_if(state_is_in_game)
.with_system(movement::apply_velocity)
.with_system(movement::constrain_entities.after(movement::apply_velocity)) // Error on this line
.into(),
)
the trait bound
ParallelSystemDescriptor: IntoSystem<(), (), _>
is not satisfied
the traitAddConditionalToSet<ConditionSystemSet, ()>
is implemented forConditionalSystemDescriptor
required because of the requirements on the impl ofIntoConditionalSystem<_>
forParallelSystemDescriptor
required because of the requirements on the impl ofAddConditionalToSet<ConditionSystemSet, _>
forParallelSystemDescriptor
rustcE0277
If I use a .into()
after the .after()
, the error changes to
type annotations needed
cannot infer type of the type parameterS
declared on the associated functionwith_system
rustcE0282
mod.rs(52, 37): consider specifying the generic arguments:::<S, P>
Edit: I can use .chain()
for this specific case, but being able to use .after()
and .before()
within a ConditionSet
would be better
Implement combinators for more flexible logic:
.run_if_all
(just sugar for multiple .run_if
s).run_if_any
(OR logic combinator)In bevy you can have a system set run on state exit like so:
.add_system_set(
SystemSet::on_exit(GameState::MainMenu)
.label("spawn")
.with_system(spawn_player)
.with_system(spawn_enemies),
);
I couldnt find a way to do this with ConditionSet without having to add multiple exist systems
app
.add_exit_system(GameState::MainMenu, spawn_player)
.add_exit_system(GameState::MainMenu, spawn_enemies)
I don't know if it's expected, but it looks like we cannot use the before/after
functions inside a condition set?
If i try to run
.add_system_set(
ConditionSet::new()
.run_in_state(InGameState::Game)
.with_system(food_contact_event)
.with_system(grow_snake_event.after(food_contact_event))
.into()
);
I get the error:
the trait `IntoSystem<(), (), _>` is not implemented for `SystemDescriptor`
631 | S: AddConditionalToSet<ConditionSystemSet, P>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `ConditionSystemSet::with_system`
Looks like it's because some trait bounds are missing?
Maybe i'm approaching things incorrectly and there's a different way to do this.
I left the documentation with the following questions:
1
always run after stage 0
runs?After upgrade from 0.7 to 0.8 I started to get the following error:
thread 'main' panicked at 'State Transition Stage not found (assuming auto-added label)', /home/indy/.cargo/registry/src/github.com-1ecc6299db9ec823/iyes_loopless-0.8.0/src/state.rs:343:25
stack backtrace:
0: rust_begin_unwind
at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/std/src/panicking.rs:584:5
1: core::panicking::panic_fmt
at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/panicking.rs:142:14
2: core::panicking::panic_display
at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/panicking.rs:72:5
3: core::panicking::panic_str
at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/panicking.rs:56:5
4: core::option::expect_failed
at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/option.rs:1880:5
5: core::option::Option<T>::expect
at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/option.rs:738:21
6: <bevy_app::app::App as iyes_loopless::state::app::AppLooplessStateExt>::add_enter_system
at /home/indy/.cargo/registry/src/github.com-1ecc6299db9ec823/iyes_loopless-0.8.0/src/state.rs:343:25
7: <de_menu::mainmenu::MainMenuPlugin as bevy_app::plugin::Plugin>::build
at ./crates/menu/src/mainmenu.rs:16:9
8: bevy_app::plugin_group::PluginGroupBuilder::finish
at /home/indy/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_app-0.8.1/src/plugin_group.rs:135:21
9: bevy_app::app::App::add_plugins
at /home/indy/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_app-0.8.1/src/app.rs:810:9
10: de_game::main
at ./src/main.rs:27:5
11: core::ops::function::FnOnce::call_once
at /rustc/897e37553bba8b42751c67658967889d11ecd120/library/core/src/ops/function.rs:248:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Note that I do this in a plugin (which is executed first):
app.add_loopless_state(AppState::InMenu)
.add_loopless_state(GameState::None);
and this in another plugin (which executes later):
app.add_enter_system(AppState::InMenu, setup)
.add_exit_system(AppState::InMenu, cleanup)
Actually ... the NextState
resource doesn't have to keep being inserted/removed ... it can just be kept at all times. Just perform state transitions when its value is changed.
I have a barebones StatePlugin that crashes whenever I try to add_enter_system()
. I saw another opened issue mentioning that the API may have some issue with the Plugin architecture, so I tried moving the add_enter_system
to main
but did not work either.
this is the error I get:
thread 'main' panicked at 'State Transiton Stage not found (assuming auto-added label)', /{my_directory}/github.com-1ecc6299db9ec823/iyes_loopless-0.6.1/src/state.rs:306:18
Here's a snippet of my main.rs file
fn main() {
let mut app = App::new();
app.insert_resource(WindowDescriptor {
// some not relevant code
})
.add_plugins(DefaultPlugins)
.add_plugin(CameraPlugin)
.add_plugin(StatePlugin)
.add_plugin(UiPlugin)
.add_plugin(GamePlugin);
app.run();
}
and the StatePlugin file:
use bevy::prelude::*;
use iyes_loopless::prelude::*;
pub const STARTING_GAME_STATE: GameState = GameState::MainMenu;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum GameState {
MainMenu,
Options,
InGame,
}
pub struct StatePlugin;
impl Plugin for StatePlugin {
fn build(&self, app: &mut App) {
app
.add_loopless_state(STARTING_GAME_STATE)
.add_system(stage_key_bindings)
.add_enter_system(&GameState::InGame, setup_game); // adding this line crashes the game
}
}
// This works fine
fn stage_key_bindings(mut commands: Commands, kb_input: Res<Input<KeyCode>>) {
if kb_input.just_pressed(KeyCode::Escape) {
commands.insert_resource(NextState(GameState::MainMenu));
}
}
// Mockup reset_game function when entering a new game
fn setup_game(mut commands: Commands) {
dbg!("reset_game!");
commands.insert_resource(NextState(GameState::InGame));
}
What am I doing wrong? Thanks!
I'm trying to run a system after the physics update in rapier. I don't believe I can apply a label to a system that I'm not explicitly adding (I'm adding through a plugin).
Is there any way to run a system after a system that is added by a plugin?
Is there any particular reason why FixedTimestepInfo is only updated shortly before a FixedTimestepStage runs its system?
I'm working on interpolating my physics between rendered frames. I planned on using FixedTimestepInfo::accumulator as the interpolator in a render sync system, but to my disappointment this doesn't work.
Thanks for the great work!
I'm migrating a playground project to use this library and I have a set of systems that run using a fixed timer only during a state, previously using a SystemSet
. The systems run in a certain order using labels, but they don't have conditionals on them.
app
.add_system_set(
ConditionSet::new()
.after("FixedTimestep")
.run_in_state(AppState::Playing)
.with_system(snake_movement.label(SnakeMovement::Movement))
.with_system(
snake_eating
.label(SnakeMovement::Eating)
.after(SnakeMovement::Movement),
)
.with_system(
snake_growth
.label(SnakeMovement::Growth)
.after(SnakeMovement::Eating),
)
.into(),
)
It causes this error:
error[E0277]: the trait bound `ParallelSystemDescriptor: IntoSystem<(), (), _>` is not satisfied --> src\main.rs:442:30 | 442 | .with_system(snake_movement.label(SnakeMovement::Movement)) | ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoSystem<(), (), _>` is not implemented for `ParallelSystemDescriptor` | | | required by a bound introduced by this call | = help: the trait `AddConditionalToSet` is implemented for `ConditionalSystemDescriptor` = note: required for `ParallelSystemDescriptor` to implement `iyes_loopless::condition::IntoConditionalSystem<_>` = note: required for `ParallelSystemDescriptor` to implement `AddConditionalToSet` note: required by a bound in `iyes_loopless::condition::ConditionSet::with_system` --> C:\Users\osbornm\scoop\persist\rustup\.cargo\registry\src\github.com-1ecc6299db9ec823\iyes_loopless-0.7.1\src\condition.rs:652:12 | 652 | S: AddConditionalToSet, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `iyes_loopless::condition::ConditionSet::with_system`
For more information about this error, try
rustc --explain E0277
.
The solution I found is to add into_conditional() to each system:
app
.add_system_set(
ConditionSet::new()
.after("FixedTimestep")
.run_in_state(AppState::Playing)
.with_system(
snake_movement
.into_conditional()
.label(SnakeMovement::Movement)
)
.with_system(
snake_eating
.into_conditional()
.label(SnakeMovement::Eating)
.after(SnakeMovement::Movement),
)
.with_system(
snake_growth
.into_conditional()
.label(SnakeMovement::Growth)
.after(SnakeMovement::Eating),
)
.into(),
)
But that seems kind of clunky and like it may be able to be fixed easily.
Hello
Some background first; Im pretty new to Rust and Bevy.
I've added iyes_loopless to my dependencies (0.3.0 as I use bevy 0.6 still).
However, when trying to use a method like .add_enter_system
or add_loopless_state
on the App::new()
from Bevy I get this error from the compiler:
no method named add_enter_system
found for mutable reference &mut bevy::prelude::App
in the current scope
I've looked at your examples in this repository and I can't see anything specific I'm missing. My dependency is specified like this:
[dependencies.iyes_loopless] version = "0.3.0"
in my Cargo.toml
I did a cargo tree -f "{p} {f}"
just to see if there was maybe something with the features, but this was the output:
├── iyes_loopless v0.3.0 bevy-compat,bevy_core,bevy_utils,default,fixedtimestep,states │ ├── bevy_core v0.6.0 (*) │ ├── bevy_ecs v0.6.1 bevy_reflect,default (*) │ └── bevy_utils v0.6.0 (*)
Am a bit lost now, would really like to try this way of doing it before just using the Bevy built-in way of doing it.
Investigate what it would take to make a ConditionalExclusiveSystem
.
Hey there!
For my game I implemented a custom command queue that can be used to flush certain sets of commands before the end of the frame. This is something that was mentioned in the Bevy stageless design, and I wasn't sure if it was something you might want to add to this crate.
I feel like it's a feature other people might want to use, and it'd be good to have in a crate, but I wasn't sure if a new crate would be warranted, or if it'd fit in here, because it's kind of a preview to the stageless bevy design.
Here's a gist with the implementation and usage example. It's really quite simple:
https://gist.github.com/zicklag/3446143d563657d54e292cc7e2c15378
Using bevy main and the bevy_main branch together I get:
| ------------------- this is a function, perhaps you wish to call it
35 | .run_on_event::<WindowResized>()
| ^^^^^^^^^^^^ method cannot be called on `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6> fn(bevy::prelude::Commands<'r, 's>, bevy::prelude::EventReader<'t0, 't1, WindowResized>, bevy::prelude::ResMut<'t2, bevy::prelude::Assets<bevy::prelude::Image>>, std::option::Option<bevy::prelude::Res<'t3, OutputImage>>, bevy::prelude::Query<'t4, 't5, &'t6 mut bevy::prelude::Sprite, bevy::prelude::With<output_image::RenderTarget>>) {resize_output_image}` due to unsatisfied trait bounds
The code causing this is fairly simple:
app.add_plugin(ExtractResourcePlugin::<OutputImage>::default())
.add_system(
resize_output_image
.run_on_event::<WindowResized>()
.run_if_resource_exists::<OutputImage>(),
)
.add_system(
create_output_image
.run_on_event::<WindowResized>()
.run_unless_resource_exists::<OutputImage>(),
);
}
Where I'm playing around with having different things happen if a particular resource already exists or not.
I'm relatively new to rust, so am not sure if I'm doing something wrong here.
When trying to compile the crate without default features this error shows up.
--> iyes_loopless/src/lib.rs:13:20
13 | pub use crate::state::schedule::ScheduleLooplessStateExt;
| ^^^^^ could not find `state` in the crate root
The #cfg(feature = "app")
in lib.rs only applies to the first import. So the socond one gets included even if app
isn't enabled.
Also the app
feature should depend on the states
feature because the crate also does not compile when only app
is enabled.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.