-
-
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
Need the OnEnter() and OnExit() to be run even if when transitioning to and from the same state. #9130
Comments
Re-entering states is definitely a useful thing to be able to do, having this functionality back in some form would be really great to see. |
Add |
I think some people might not expect their state to be reentered andit would create some bugs if simply re-added to |
If a user doesn't want that to happen, she needs a way to check the previous state (not sure if previous state is kept track of now). |
There are use cases for both re-triggering and not re-triggering. See #8191. I don't know what the overhead of a schedule is in Bevy, but if it's not significant then both use cases should be easily supported. The docs should be clear on the distinction. I think it's not really cognitive overhead; the state transition logic maps quite nicely to the schedules. |
I think also some more care should be given to changing things as fundamental as this without soliciting at least some feedback on how it's being used. I know everything is still in pre-1.0 unstable land but it really upends a lot to have to completely rework something like state transitions because one person got surprised by it. |
I would also highly appreciate if the state transition is triggered, also if the next state is the same as the current state. State transitions are a very powerful and robust mechanism to execute a bunch of actions/systems in a specific order (or in parallel). |
An associated constant A hacky workaround until a solution for Bevy has been deployed can be to manually implement EDIT: The current docs for the apply_state_transition system should mention inequality matters here. |
Thank you @urben1680 for this advice.
|
@nightactive-git Oh too bad, I did not test it as it seemed obvious to me that it would work. Sorry. #[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
pub struct UnequalState<Inner>{
state: Inner,
flip: bool
}
// States derive only works with fieldless enums
type ArrayIter<T> = std::array::IntoIter<UnequalState<T>, 2>;
impl<T> States for UnequalState<T> where T: States{
type Iter = FlatMap<<T as States>::Iter, ArrayIter<T>, fn(T) -> ArrayIter<T>>;
fn variants() -> Self::Iter {
T::variants().flat_map(|state| [
Self { state: state.clone(), flip: false },
Self { state, flip: true },
].into_iter())
}
}
impl<T> UnequalState<T> {
/// use this to construct a state using the current state
/// &self should be taken from `Res<State<>>`, not `NextState<>`!
fn unequal_new(&self, state: T) -> Self {
Self {
state,
flip: !self.flip
}
}
} |
I'm in favor of supporting this as an opt-in behavior: it's clearly useful, but still quite surprising. Reverting is my preference over keeping the current behavior though. |
Made a PR re-adding the behavior as opt-in via |
I don't think there is a need to complicate Another argument for this would be this. |
That would imply that using Also, if you e.g. call |
The wrapper can check for values inside of |
Okay I see what you're saying. You could give |
Few more thoughts: The enum FooBar {
#[default]
Foo,
Bar,
}
app.add_systems(Update, (sys_a, sys_b).chain());
fn sys_a(next: ResMut<NextState<FooBar>>) {
// Should set Foo to Bar
nest.set_force(FooBar::Bar);
}
fn sys_b(next: ResMut<NextState<FooBar>>) {
// Replaces Bar, no state change occurs
nest.set_force(FooBar::Foo);
} which could be the intended way for this, but definitely not the one I'd expect. |
Another problem with the entire idea of forced updates is it straight up doesn't make sense when you nest states. I think we shouldn't support forced updates, at least not like this. |
It is the intended behavior. If it's unexpected, that's probably because of the name of the method. It's supposed to convey that the state transition will happen (if it's still queued when |
If the current state is |
The Idea of removing the verification and let the user verifying themselves if they are trying to change something to the same state would probably be the simplest and a good way to do this? |
I don't think setting the state to |
Yeah that effectively lines up with @MiniaczQ's proposal which I agree with. You'd choose between |
What if this happened due to system order ambiguity, then it's an additional thing to worry about |
If you have a race condition / ambiguity between systems that set the next state, that's just a logic error. I don't think there's a consistently sane way for bevy to handle that. |
Just resolving whether an state update should occur during Edit: |
Made a PR for the system param approach, which I prefer. I'm leaving the Names are all bikesheddable, I didn't think too hard about them. |
Until this is fixed, the easiest workaround is to add a |
This is fixed in my 3rd-party crate pyri_state. I was unable to get any fix upstreamed unfortunately after a lot of discussion, because there's more than one way to implement this and it's not unanimous. In |
…13579) # Objective This PR addresses one of the issues from [discord state discussion](https://discord.com/channels/691052431525675048/1237949214017716356). Same-state transitions can be desirable, so there should exist a hook for them. Fixes #9130. ## Solution - Allow `StateTransitionEvent<S>` to contain identity transitions. - Ignore identity transitions at schedule running level (`OnExit`, `OnTransition`, `OnEnter`). - Propagate identity transitions through `SubStates` and `ComputedStates`. - Add example about registering custom transition schedules. ## Changelog - `StateTransitionEvent<S>` can be emitted with same `exited` and `entered` state. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
What problem does this solve or what need does it fill?
When using bevy 0.10.1, I can trigger a button click event and enter StateA, and query some resources and spawn some bundles when I enter this StateA with
add_system(setup.in_schedule(OnEnter(StateA)))
, every time I click the button (without leave the StateA), I can despawn bundles by usingadd_system(exit.in_schedule(OnExit(StateA)));
and spawn new bundles according to the resources again. But after I update to bevy 0.11, this cannot be done because of #8359.What solution would you like?
I hope
OnEnter
andOnExit
can be run again when the system enters the same state, or at least, can make it optional.What alternative(s) have you considered?
No effective methods were found.
The text was updated successfully, but these errors were encountered: