Skip to content

Event-component-system #2309

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

Closed
simensgreen opened this issue Jun 6, 2021 · 7 comments
Closed

Event-component-system #2309

simensgreen opened this issue Jun 6, 2021 · 7 comments
Labels
A-ECS Entities, components, systems, and events C-Feature A new feature, making something new possible C-Usability A targeted quality-of-life change that makes Bevy easier to use

Comments

@simensgreen
Copy link
Contributor

What problem does this solve or what need does it fill?

  • The problem of system responses to ongoing events (the system will not respond if it was triggered at stages before the event was generated).
  • Systems are now dealing with the events themselves.

What solution would you like?

Each event has a set of components, systems waiting for events are transferred to the class of event handlers and are called only when there is an event with a suitable set of components.
For example, the event when the user pressed a key on the keyboard can have the components KeyPress(usize), UserInput, the cursor movement event UserInput, Cursor, Position(usize, usize), and an event generated by some system, for example, the player "jumped" - PlayerEvent , Jump{vector: Vec2}
Naturally, this can be connected to an existing ecs and the system will be called with a set of components from the world and a set of components from an event.

Here is an example of pseudocode (as I see it), I think those who read this perfectly understand the capabilities of ecs without this example, but still

/// This system will only be called when there are events with KeyPress, or periodically called with an empty iterator
fn jump_handler(event_server: &mut EventServer, events: EventQuery<KeyPress>, player_pos: Query<&mut Position, Player>)
{
    for event in events.iter()
    {
        // ASCII `Space` code is 32
        if event.0 == 32 
        { 
            event_server.spawn().insert(PlayerEvent::default()).insert(Jump{ vector: Vec2::new(0.0, 1.0, 0.0)});
            player_pos.iter().next().unwrap().add(Vec2::new(0.0, 1.0, 0.0));
        }
    }
}

/// This system will only be called when there are jump events or periodically called with an empty iterator
fn jumper_achievment(jump_counter: ResMut<JumpCounter>, events: EventQuery<Jump>, event_server: &mut EventServer)
{
    jump_counter.add(events.iter().len())
    if jump_counter >= 100 { event_server.spawn().insert(Achievment::Jumper) }
}

What alternative(s) have you considered?

The current alternatives with signal and receiver systems look good, but ecs will give flexibility in my opinion
I also considered two options for calling systems:

  • immediate call of associated systems when an event occurs
  • accumulation of events and their postponed call (current system with stages)

While I'm thinking about it, and it seems to me the option with the accumulation of events is safer and easier to implement.

Additional context

I wrote a small python example (as a prototype). You can see the link

@simensgreen simensgreen added C-Feature A new feature, making something new possible S-Needs-Triage This issue needs to be labelled labels Jun 6, 2021
@NathanSWard
Copy link
Contributor

Would you mind clarifying how/why the current event system via EventReader and EventWriter won't satisfy this?
For example with the first system that you had in your explanation, you could just use EventReader<KeyboardInput> or event just Res<Input<Keycode>>

@simensgreen
Copy link
Contributor Author

I probably need to write a more complex example. Yes, you can now create your own event types, but you won't be able to make smart queries like With <> or Without <>. Now, if there are many types of events, it will be easy to get confused and difficult to control, or systems can be falsely triggered, wasting computer resources.

@Ixentus
Copy link
Contributor

Ixentus commented Jun 6, 2021

You can put EventReaders in RunCriteria to keep the logic separate from the system.

@NathanSWard
Copy link
Contributor

NathanSWard commented Jun 7, 2021

@simensgreen
Would adding

fn run_if_has_event<T>(events: EventReader<T>) -> ShouldRun {
    if events.iter().next().is_some() {
        ShouldRun::Yes
    } else {
        ShouldRun::No
    }
}

as the run criteria solve your use case?

@NathanSWard NathanSWard added A-ECS Entities, components, systems, and events C-Usability A targeted quality-of-life change that makes Bevy easier to use and removed S-Needs-Triage This issue needs to be labelled labels Jun 7, 2021
@alice-i-cecile
Copy link
Member

Have you seen my EventHandler pattern discussed in bevyengine/rfcs#25?

If I understand what you're after, it aims to solve a very similar set of patterns in a more direct fashion.

@NathanSWard
Copy link
Contributor

NathanSWard commented Jun 11, 2021

@simensgreen
As a quick follow up, did any of the provided answers address what this issues is requesting?

@simensgreen
Copy link
Contributor Author

Yes, it seems bevyengine/rfcs#25 really looks like what I was thinking. Now I do not have much time to fully study the issue, but when the time comes, I will return to this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Feature A new feature, making something new possible C-Usability A targeted quality-of-life change that makes Bevy easier to use
Projects
None yet
Development

No branches or pull requests

4 participants