#Ergonomics for Asset Creation with Metadata and Entity Spawning

3 messages · Page 1 of 1 (latest)

sick delta
#

I have asked quite a few things recently I hope that's fine :). I'm just trying to get a hang of bevy and experiment with it as much as I can. (I have tried my best to condense the code to its most important aspects without loosing the complexity that troubles me)

I have two more questions about ergonomics that are somewhat related.

  1. How do I handle metadata for assets? (I only want to specify it once)
  2. How do I use assets to spawn entities without having to fetch them all the time.

I have included my current ideas but I'm not 100% satisfied. I'd love any input on how you solve these problems.

Note that I have removed most generics (such as impl Into<IVec2>) etc. to make the code more concise.

  1. Metadata for assets:
    I use a new asset (Spritesheet) to store my metadata.
#[derive(Asset, Reflect, Clone)]
pub struct Spritesheet {
    pub texture: Handle<Image>,
    pub layout: Handle<TextureAtlasLayout>,
}

#[derive(Resource, Clone, Debug, Deref)]
struct CreaturesSpritesheet(Handle<Spritesheet>);

// Setting up the assets in the FromWorld implementation
impl FromWorld for CreaturesSpritesheet {
    fn from_world(world: &mut World) -> Self {
        let asset_server = world.resource::<AssetServer>();
        let texture = asset_server.load(
            "path",
        );
        let layout = TextureAtlasLayout::from_grid(
            UVec2::splat(10),
            14,
            18,
            Some(UVec2::new(2, 2)), // padding
            Some(UVec2::new(2, 2)), // offset
        );
        let mut texture_atlas_layouts = world.resource_mut::<Assets<TextureAtlasLayout>>();
        let layout_handle = texture_atlas_layouts.add(layout);

        let mut spritesheet_assets = world.resource_mut::<Assets<Spritesheet>>();
        let spritesheet = spritesheet_assets.add(Spritesheet {
            texture: texture.clone(),
            layout: layout_handle.clone(),
        });

        CreaturesSpritesheet(spritesheet)
    }
}
#

But if that metdadata includes Handles I need to get them in every system that wants to use the CreatureSpritesheet ... that is annoying ... Especially because this might be passed through quite a lot of functions. Which leads me to my second question.
How to spawn entities that require some setup without needing to fetch all the data in the system that's setting them up? Such as:

pub fn player_with_sprite(
    pos: IVec2,
    player_settings: &PlayerSpriteSettings,
    spritesheets: &Assets<Spritesheet>,
) -> impl Bundle {
    let spritesheet = spritesheets.get(&player_settings.spritesheet).unwrap();
    let mut sprite = Sprite::from_atlas_image(...);
    (Player, Pos(pos), sprite)
}

pub fn system_setup_game(
    mut commands: Commands,
    player_sprite_settings: Res<PlayerSpriteSettings>,
    spritesheets: Res<Assets<Spritesheet>>,
) {
    commands.spawn((
        player_with_sprite((0, 0), &player_sprite_settings, &spritesheets)
    ));
}
#

I have a couple of Ideas but I'm not really satisfied with them.

2.1: Use a custom system with input that spawns the player.

pub fn spawn_player(
    In(player_pos): In<IVec3>,
    player_settings: Res<PlayerSpriteSettings>,
    spritesheets: Res<Assets<Spritesheet>>,
    mut commands: Commands,
) {
    commands.spawn(player_with_sprite(
        player_pos,
        &player_settings,
        &spritesheets,
    ));
}

pub fn system_setup_game(
    mut commands: Commands,
    player_sprite_settings: Res<PlayerSpriteSettings>,
    spritesheets: Res<Assets<Spritesheet>>,
) {
    commands.run_system_cached_with(spawn_player, IVec3::new(0, 0, 0));
}

But here I can't return the entity id (If I pass it in I have to do more work yet again) ... unless we have exclusive world access ... but that condemns every system using it to also have exclusive world access:

2.2

pub fn spawn_player(
    In(player_pos): In<IVec3>,
    player_settings: Res<PlayerSpriteSettings>,
    spritesheets: Res<Assets<Spritesheet>>,
    mut commands: Commands,
) {
    commands.spawn(player_with_sprite(
        player_pos,
        &player_settings,
        &spritesheets,
    ));
}

pub fn exclusive_setup(world: &mut World) {
    let player_id = world
        .run_system_cached_with(spawn_player_exclusive, IVec3::new(0, 0, 0))
        .unwrap();
    ...
}