执行条件

执行条件是一种机制,用于控制 Bevy 在运行时是否应该执行特定的系统。这就是你控制如何使功能只在特定条件下被执行。

执行条件是一个较底层的基本功能。Bevy 在上面提供了更高层次的抽象,比如 状态。如果你真的需要更直接的控制,你可以使用执行条件,而不使用这些抽象概念。

执行条件可以应用于单个系统系统集阶段

执行条件也是 Bevy 系统,它返回一个类型为 enum ShouldRun 的值。它们可以接受任何系统参数,就像普通系统一样。

这个例子显示了如何使用执行条件来实现不同的多人游戏模式:

    use bevy::ecs::schedule::ShouldRun;

    #[derive(Debug, PartialEq, Eq)]
    enum MultiplayerKind {
        Client,
        Host,
        Local,
    }

    fn run_if_connected(
        mode: Res<MultiplayerKind>,
        session: Res<MyNetworkSession>,
    ) -> ShouldRun
    {
        if *mode == MultiplayerKind::Client && session.is_connected() {
            ShouldRun::Yes
        } else {
            ShouldRun::No
        }
    }

    fn run_if_host(
        mode: Res<MultiplayerKind>,
    ) -> ShouldRun
    {
        if *mode == MultiplayerKind::Host || *mode == MultiplayerKind::Local {
            ShouldRun::Yes
        } else {
            ShouldRun::No
        }
    }

    fn main() {
        App::new()
            .add_plugins(DefaultPlugins)

            // if we are currently connected to a server,
            // activate our client systems
            .add_system_set(
                SystemSet::new()
                    .with_run_criteria(run_if_connected)
                    .before("input")
                    .with_system(server_session)
                    .with_system(fetch_server_updates)
            )

            // if we are hosting the game,
            // activate our game hosting systems
            .add_system_set(
                SystemSet::new()
                    .with_run_criteria(run_if_host)
                    .before("input")
                    .with_system(host_session)
                    .with_system(host_player_movement)
                    .with_system(host_enemy_ai)
            )

            // other systems in our game
            .add_system(smoke_particles)
            .add_system(water_animation)
            .add_system_set(
                SystemSet::new()
                    .label("input")
                    .with_system(keyboard_input)
                    .with_system(gamepad_input)
            )
            .run();
    }

执行条件标签

如果你有多个系统或系统集,你想共享同一个执行标准,你可以给这个执行条件一个标签

当你使用标签时,Bevy 将只执行一次执行条件系统,记住它的输出结果,并将结果应用于所有带有标签的任务。

        #[derive(Debug, Clone, PartialEq, Eq, Hash)]
        #[derive(RunCriteriaLabel)]
        enum MyRunCriteria {
            Client,
            Host,
        }

        fn main() {
            App::new()
                // ...
                .add_system_set(
                    SystemSet::new()
                        .with_run_criteria(
                            // assign it a label
                            run_if_host
                                .label(MyRunCriteria::Host)
                        )
                        .with_system(host_session)
                        .with_system(host_player_movement)
                        .with_system(host_enemy_ai)
                )

                // extra system for debugging the host
                // it can share our previously-registered run criteria
                .add_system(host_debug
                    .with_run_criteria(MyRunCriteria::Host)
                )
                .run();
        }

如果你有一个复杂的执行条件系统,该系统会进行写操作或其他非幂等性操作,那么一次性执行的属性就特别重要。

已知的陷阱

当在一个不是每帧都被执行的系统中接收事件时,在接收系统不执行的帧中,所有发送的事件都将会错过。

为了应对这种情况,你可以实现一个自定义的事件清理策略,以便手动管理相关事件类型的生命周期。


Bevy 的固定时间步长在底层也是通过执行条件实现的。