17个版本 (11个破坏性版本)

0.11.0 2024年1月11日
0.10.3 2023年12月23日
0.9.2 2023年12月5日
0.8.0 2023年11月18日

#1542游戏开发

每月26次下载
3 crates 使用

MIT/Apache

130KB
2K SLoC

ECS

ReactCommands 使注册和注销ECS钩子变得容易。当需要将信息(例如实体ID)传递到反应系统时,反应器最有用。

一旦检测到反应触发器,反应器将在第一次 apply_deferred 后运行。如果反应器触发其他反应器,它们将在初始反应器之后立即运行(直到整个反应树终止)。目前不支持递归反应。

注册反应器

使用 ReactCommands 注册反应器。您必须指定一个 '反应触发器'

fn setup(mut rcommands: ReactCommands)
{
    rcommands.on(resource_mutation::<A>(),
        |a: ReactRes<A>|
        {
            //...
        }
    );
}

可用的反应触发器有

  • [resource_mutation<R: ReactResource>()]
  • [insertion<C: ReactComponent>()]
  • [mutation<C: ReactComponent>()]
  • [removal<C: ReactComponent>()]
  • [entity_insertion<C: ReactComponent>(entity)]
  • [entity_mutation<C: ReactComponent>(entity)]
  • [entity_removal<C: ReactComponent>(entity)]
  • [event<E>()]

反应堆可以与多个反应触发器相关联

fn setup(mut rcommands: ReactCommands)
{
    rcommands.on((resource_mutation::<A>(), entity_insertion<B>(entity)),
        move |a: ReactRes<A>, q: Query<&B>|
        {
            q.get(entity);
            //...etc.
        }
    );
}

撤销反应堆

可以使用在注册时获得的 RevokeToken 来撤销反应堆。

let token = rcommands.on(resource_mutation::<A>(), || { todo!(); });
rcommands.revoke(token);

触发类型:资源突变

向您的应用添加反应性资源

#[derive(ReactResource)]
struct Counter(u32);

app.add_plugins(ReactPlugin)
    .add_react_resource(Counter);

修改资源

fn increment(mut rcommands: ReactCommands, mut counter: ReactResMut<Counter>)
{
    counter.get_mut(&mut rcommands).0 += 1;
}

对资源突变做出反应

fn setup(mut rcommands: ReactCommands)
{
    rcommands.on(resource_mutation::<Counter>(),
        |counter: ReactRes<Counter>|
        {
            println!("count: {}", counter.0);
        }
    );
}

触发类型:组件插入/修改/删除

#[derive(ReactComponent)]
struct Health(u16);

fn setup(mut rcommands: ReactCommands)
{
    let entity = rcommands.commands().spawn_empty().id();
    rcommands.insert(entity, Health(0u16));

    rcommands.on(entity_mutation::<Health>(entity)
        move |q: Query<&React<Health>>|
        {
            let health = q.get(entity).unwrap();
            println!("health: {}", health.0);
        }
    );
}

fn add_health(mut rcommands: ReactCommands, mut q: Query<&mut React<Health>>)
{
    for health in q.iter_mut()
    {
        health.get_mut(&mut rcommands).0 += 10;
    }
}

实体无关的触发器(insertion<C>()mutation<C>()removal<C>())只能相互组合,因为它们的反应堆需要一个 In<Entity> 系统参数

#[derive(ReactComponent)]
struct A;
#[derive(ReactComponent)]
struct B;

rcommands.on((insertion::<A>(), removal::<B>()),
    |In(entity): In<Entity>, a: Query<(Option<&React<A>>, Option<&React<B>>)>|
    {
        //...
    }
);

触发类型:事件

注册一个反应事件

app.add_react_event::<u32>();

发送事件

rcommands.send(0u32);

使用 ReactEventReader 来访问事件数据并对事件做出反应

rcommands.on(event::<u32>(),
    |mut events: ReactEventReader<u32>|
    {
        for event in events.iter()
        {
            println!("react u32: {}", event);
        }
    }
);

触发类型:销毁

使用 [ReactCommands::on_despawn()] 方法对销毁做出反应

rcommands.on_despawn(entity, move || println!("entity despawned: {}", entity));

一次性反应堆

如果您只想让反应堆运行一次,请使用 [ReactCommands::once()]。

let entity = rcommands.commands().spawn(Player);
rcommands.once(event::<ResetEverything>(),
    move |world: &mut World|
    {
        world.despawn(entity);
    }
);

依赖关系

~23MB
~417K SLoC