rustspritegame-enginebevy

How to load part of image in bevy engine


I have a sprite sheet png file that contains some static sprites like walls or grass. How can I split them into individual sprites by their coordinate in the image?


Solution

  • You did not post any code or what you tried so far, so I am providing a general answer.

    There are multiple options:

    I personally like the uv coordinate manipulation more, a basic sample would look like this with bevy = 0.4:

    use bevy::prelude::*;
    
    fn main() {
        App::build()
            .add_resource(Msaa { samples: 4 })
            .add_plugins(DefaultPlugins)
            .add_startup_system(setup.system())
            .run();
    }
    
    /// set up a simple 3D scene
    fn setup(
        commands: &mut Commands,
        mut meshes: ResMut<Assets<Mesh>>,
        asset_server: Res<AssetServer>,
        mut materials: ResMut<Assets<StandardMaterial>>,
    ) {
    
        let texture_handle = asset_server.load("textures/sprites_array.png");
    
        let material_handle = materials.add(StandardMaterial {
            albedo_texture: Some(texture_handle.clone()),
            shaded: false,
            ..Default::default()
        });
    
        let mut uvs = Vec::new();
        uvs.push([0.0, 1.0]);
        uvs.push([0.0, 0.0]);
        uvs.push([1.0, 0.0]);
        uvs.push([1.0, 1.0]);
    
        let mut mesh = Mesh::from(shape::Quad::new(Vec2::new(1.0, 1.0)));
        mesh.set_attribute(Mesh::ATTRIBUTE_UV_0, uvs);
    
        // use only the upper left part of the texture atlas
        let mut uvs1 = Vec::new();
        uvs1.push([0.0, 0.5]);
        uvs1.push([0.0, 0.0]);
        uvs1.push([0.5, 0.0]);
        uvs1.push([0.5, 0.5]);
    
        let mut mesh1 = Mesh::from(shape::Quad::new(Vec2::new(1.0, 1.0)));
        mesh1.set_attribute(Mesh::ATTRIBUTE_UV_0, uvs1);
    
        // use only the lower right part of the texture atlas
        let mut uvs2 = Vec::new();
        uvs2.push([0.5, 1.0]);
        uvs2.push([0.5, 0.5]);
        uvs2.push([1.0, 0.5]);
        uvs2.push([1.0, 1.0]);
    
        let mut mesh2 = Mesh::from(shape::Quad::new(Vec2::new(1.0, 1.0)));
        mesh2.set_attribute(Mesh::ATTRIBUTE_UV_0, uvs2);
    
        // add entities to the world
        commands
            // the whole texture array
            .spawn(PbrBundle {
                mesh: meshes.add(mesh),
                material: material_handle.clone(),
                ..Default::default()
            })
            // only the "first" item of the texture array
            .spawn(PbrBundle {
                mesh: meshes.add(mesh1),
                material: material_handle.clone(),
                transform: Transform::from_translation(Vec3::new(2.0, 0.0, 0.0)),
                ..Default::default()
            })
            // only the "last" item of the texture array
            .spawn(PbrBundle {
                mesh: meshes.add(mesh2),
                material: material_handle.clone(),
                transform: Transform::from_translation(Vec3::new(-2.0, 0.0, 0.0)),
                ..Default::default()
            })
            // light
            .spawn(LightBundle {
                transform: Transform::from_translation(Vec3::new(4.0, 8.0, 4.0)),
                ..Default::default()
            })
            // camera
            .spawn(Camera3dBundle {
                transform: Transform::from_translation(Vec3::new(0.0, 0.0, 5.0))
                    .looking_at(Vec3::default(), Vec3::unit_y()),
                ..Default::default()
            });
    }
    

    I used this texture array (put it in assets/textures/sprites_array.png): Texture

    Which will then result in that scene: The bevy scene.