/bevy-scene-hook

Ad-hoc component insertion for bevy scenes

Primary LanguageRustApache License 2.0Apache-2.0

Bevy Scene hook

Bevy tracking Latest version Apache 2.0 Documentation

A proof of concept for adding components ad-hoc within code to entities spawned through scenes (such as gltf files) in the bevy game engine.

If you don't mind adding such a small dependency to your code rather than copy/pasting the code as a module, you can get it from crates.io.

Usage

[dependencies]
bevy-scene-hook = "3.0"

The following snippet of code is extracted from Warlock's Gambit source code.

It loads the scene.glb file when the game starts. When the scene is fully loaded, the closure passed to with_comp_hook is ran for each entity with a Name component present in the scene. We add a Graveyard component to the Entity containing the SceneHook, so that it can later be checked for whether the scene completed loading.

It is possible to name object in glb scenes in blender using the Outliner dock (the tree view at the top right) and double-clicking object names.

#[derive(Component)]
pub struct Graveyard;

fn hook(
    decks: &DeckAssets,
    name: &str,
    cmds: &mut EntityCommands,
) {
    match name {
        "PlayerPerspective_Orientation" => cmds.insert_bundle((
            RayCastSource::<HandRaycast>::new(),
            RayCastSource::<SleeveArea>::new(),
            RayCastSource::<HandDisengageArea>::new(),
        )),
        "PlayerDeck" => cmds.insert(decks.player.clone_weak()),
        "OppoDeck" => cmds.insert(decks.oppo.clone_weak()),
        "PlayerPile" => cmds.insert(Pile::new(Participant::Player)),
        "OppoPile" => cmds.insert(Pile::new(Participant::Oppo)),
        "PlayerCardSpawn" => cmds.insert(PlayerCardSpawner),
        "OppoCardSpawn" => cmds.insert(OppoCardSpawner),
        "PlayerHand" => cmds.insert_bundle((PlayerHand, Animated::bob(2.0, 0.05, 7.0))),
        "OppoHand" => cmds.insert_bundle((OppoHand, Animated::bob(1.0, 0.3, 6.0))),
        "Pile" => cmds.insert(Pile::new(PileType::War)),
        "ManBody" => cmds.insert(Animated::breath(0.0, 0.03, 6.0)),
        "ManHead" => cmds.insert(Animated::bob(6. / 4., 0.1, 6.0)),
        "Bird" => cmds.insert(Animated::breath(0.0, 0.075, 5.0)),
        "BirdPupillaSprite" => cmds.insert(BirdPupil),
        "BirdEyePupilla" => cmds.insert_bundle((BirdPupilRoot, Animated::bob(5. / 4., 0.02, 5.0))),
        _ => cmds,
    };
}
fn load_scene(
    mut scene_spawner: HookingSceneSpawner,
    mut cmds: Commands,
    decks: Res<DeckAssets>,
    asset_server: Res<AssetServer>,
) {
    let decks = decks.clone();
    let res = scene_spawner.with_comp_hook(
        asset_server.load("scene.glb#Scene0"),
        move |name: &Name, cmds| hook(&decks, name.as_str(), cmds),
    );
    cmds.entity(res.entity).insert(Graveyard);
}

pub struct Plugin;
impl BevyPlugin for Plugin {
    fn build(&self, app: &mut App) {
        app
            .add_plugin(HookPlugin)
            .add_startup_system(load_scene);
        // Use `.with_run_criteria(is_scene_hooked::<Graveyard>)`
        // to only run a system after at least one scene is loaded.
    }
}

Change log

  • 1.1.0: Add is_loaded method to SceneInstance
  • 1.2.0: Add the world module containing a SceneHook trait that has exclusive world access. Useful if you want access to assets for example.
  • 2.0.0: Breaking: bump bevy version to 0.7 (you should be able to upgrade from 1.2.0 without changing your code)
  • 3.0.0: Breaking: completely rework the crate.
    • Remove the world module, as the base hook method has become much more powerful.
    • Rename SceneHook to Hook, now Hook has a unique method to implement.
    • You don't have to add any system yourself, now you have to add the HookPlugin plugin to your app.
    • Move the API exclusively to a new SystemParam: HookingSceneSpawner. Please use that parameter to add and remove scenes that contain hooks. (please tell if you you accidentally spell it HonkingSceneSpawner more than once 🦆)
    • Moved the when_spawned run criteria to the is_scene_hooked function exposed at the root of the crate, the HookedSceneState system parameter or the SceneLoaded component. Please use any of those three instead of when_spawned.
    • Now supports passing closures as hooks, instead of having to define a trait each time.
    • Now supports adding multiple of the same scene! Doesn't handle hot-reloading, but that's alright since bevy's scene hot-reloading is currently broken anyway :D

Version matrix

bevy latest supporting version
0.7 3.0.0
0.6 1.2.0

License

This library is licensed under Apache 2.0.