Skip Navigation

Bevy: How to Load Multiple Texture Atlases

So I'm currently working with Bevy to make a game with a style similar to that of Octopath Traveler. I'm using the bevy_sprite3d crate to render sprites in the 3D space. I'm currently working on writing the code for the battle scene of my JRPG. However, whenever I try to load multiple sprites into the scene, it gives me the following error:

error[B0002]: ResMut<bevy_asset::assets::Assets<bevy_sprite::texture_atlas::TextureAtlas>> in system load_sprites conflicts with a previous ResMut<bevy_asset::assets::Assets<bevy_sprite::texture_atlas::TextureAtlas>> access. Consider removing the duplicate access.

relevant system code
fn load_sprites(mut commands: Commands, asset_server: Res<AssetServer>, sprites_in_scene: Res<SpritesInScene>, mut texture_atlases: ResMut<Assets<TextureAtlas>>, mut sprite_params: Sprite3dParams) {
    // Load first player sprite
    commands.spawn(AtlasSprite3d {
        atlas: texture_atlases.add(get_texture_atlas(&asset_server, sprites_in_scene.player_sprite1 /* u32 */, (37, 38), 19)),

        pixels_per_metre: 32.,
        partial_alpha: true,
        unlit: true,

        ..default()
    }.bundle(&mut sprite_params))
    .insert(AnimationTimer(Timer::from_seconds(3. / 60., TimerMode::Repeating)))
    .insert(Transform::from_xyz(-5., 0., 0.));

    // Load second player sprite if it exists
    if let Some(id) = sprites_in_scene.player_sprite2 {
        commands.spawn(AtlasSprite3d {
            atlas: texture_atlases.add(get_texture_atlas(&asset_server, id, (1, 1), 1)),

            pixels_per_metre: 32.,
            partial_alpha: true,
            unlit: true,

            ..default()
        }.bundle(&mut sprite_params))
        .insert(AnimationTimer(Timer::from_seconds(3. / 60., TimerMode::Repeating)))
        .insert(Transform::from_xyz(-2.5, 0., 0.));
    }

    // Load first enemy sprite
    commands.spawn(AtlasSprite3d {
        atlas: texture_atlases.add(get_texture_atlas(&asset_server, sprites_in_scene.enemy_sprite1 /* u32 */, (42, 42), 21)),

        pixels_per_metre: 32.,
        partial_alpha: true,
        unlit: true,

        ..default()
    }.bundle(&mut sprite_params))
    .insert(AnimationTimer(Timer::from_seconds(3. / 60., TimerMode::Repeating)))
    .insert(Transform::from_xyz(5., 0., 0.));

    // Load second enemy sprite if it exists
    if let Some(id) = sprites_in_scene.enemy_sprite2 {
        commands.spawn(AtlasSprite3d {
            atlas: texture_atlases.add(get_texture_atlas(&asset_server, id, (1, 1), 1)),

            pixels_per_metre: 32.,
            partial_alpha: true,
            unlit: true,

            ..default()
        }.bundle(&mut sprite_params))
        .insert(AnimationTimer(Timer::from_seconds(3. / 60., TimerMode::Repeating)))
        .insert(Transform::from_xyz(2.5, 0., 0.));
    }
}

// The signature for get_texture_atlas:
fn get_texture_atlas(asset_server: &Res<AssetServer>, id: u32, tile_size: (u32, u32), row_num: usize) -> TextureAtlas

Am I doing this wrong? Is there a better way to load multiple texture atlases for the different entities in my battle scene? Thanks in advance!

4

You're viewing a single thread.

4 comments
  • Logic Projects on YouTube has a RPG they're working on that could be relevant to you.

    I've tried something myself and ended up writing my own data structures to hold handles to the sprites and change them as necessary. But that's a lot of work still and not sure if it's the best long-term.

    • Hello! So I ended up fixing this issue with sprite loading and figured out how to load multiple sprites in the scene. It turns out that I can't load the images and then spawn in the sprite objs in the same function because of Rust rules 🤷

      Anyhow, I am having a different issue now, and I've made a new post about it here.