bevy_ecs_tilemap icon indicating copy to clipboard operation
bevy_ecs_tilemap copied to clipboard

What happened to MapQuery in 0.7.0?

Open Caligari opened this issue 2 years ago • 4 comments

I've just updated Bevy to 0.8.0 and bevy_ecs_tilemap to 0.7.0, but there no longer seems to be a MapQuery (or indeed a lot of the structs which were in the docs last version). Is there a migration guide of some sort?

Caligari avatar Aug 11 '22 00:08 Caligari

Hey @Caligari, I just finished migrating a project of mine over. One of the ways I was able to ease the pain of migration was by implementing my own Layer component:

use bevy::prelude::*;

/// The base layer identifier is the primary base tile layer, used for background or root level
/// background tile rendering.
pub const BASE_LAYER: f32 = 0.0f32;

/// The world layer is the tile layer where belts are rendered and tile entities
/// are constructed for game logic.
pub const WORLD_LAYER: f32 = 1.0f32;

/// The debug layer is where the debug grid render occurs.
pub const DEBUG_LAYER: f32 = 2.0f32;

/// Trait used to identify map layers in the world and can be used to constrain generic parameters
/// for world layers.
pub trait Layer {
    /// Returns the z-index for the layer.
    fn z_index() -> f32;
}

#[derive(Component)]
pub struct MapLayer;

impl Layer for MapLayer {
    fn z_index() -> f32 {
        BASE_LAYER
    }
}

#[derive(Component)]
pub struct WorldLayer;

impl Layer for WorldLayer {
    fn z_index() -> f32 {
        WORLD_LAYER
    }
}

#[derive(Component)]
pub struct DebugLayer;

impl Layer for DebugLayer {
    fn z_index() -> f32 {
        DEBUG_LAYER
    }
}

And then I added a SystemParameter type similar to the old MapQuery that looks like this:

use bevy::prelude::*;
use bevy_ecs_tilemap::prelude::*;

use bevy::ecs::system::SystemParam;
use crate::world::Layer;

#[derive(SystemParam)]
pub struct TileQuery<'w, 's, T: Component + Layer> {
    map: Query<'w, 's, &'static TileStorage, With<T>>,
}

impl<'w, 's, T: Component + Layer> TileQuery<'w, 's, T> {
    /// This method returns the tile entity for the specific tile position in the layer.
    #[inline]
    pub fn tile_entity(&mut self, tile: UVec2) -> Option<Entity> {
        if let Ok(storage) = self.map.get_single() {
            let tile_pos = TilePos::new(tile.x, tile.y);

            storage.get(&tile_pos)
        } else {
            None
        }
    }
}

Then wherever I had a MapQuery in my system parameters, I replaced with TileQuery<T> where T is a Layer implementation.

The other change I had to make is by adding the specific Layer to the added entities. For example:

    // Add World Layer
    commands
        .entity(world_layer_entity)
        .insert_bundle(TilemapBundle {
            grid_size,
            size: map_size,
            storage: world_tile_storage,
            texture: TilemapTexture(belts_texture),
            tile_size,
            transform: helpers::get_centered_transform_2d(
                &map_size,
                &tile_size,
                WORLD_LAYER,
            ),
            ..Default::default()
        })
        .insert(WorldLayer); // <-- Insert the WorldLayer here. 

Hope this helps. It's not exactly equivalent to the MapQuery (I think MapQuery let you supply a layer id parameter on get_tile_entity), but it was sufficient for my use case.

mbolt35 avatar Aug 11 '22 02:08 mbolt35

Thanks, for that, @mbolt35! I'll see what I need.

I'm trying to work through the git history, but the examples were moved into an old_examples folder and deleted, so the history doesn't go back so I could see what changes were made. Just working out what my startup should now do, based on the changes I made to the previous example code, is a little confusing, but I'm getting there.

I'm making notes, which I will post here, if there isn't something more authoratative.

Caligari avatar Aug 11 '22 02:08 Caligari

I'll work on creating a migration guide, but I'm not sure how useful it'll be since almost everything has changed.

StarArawn avatar Aug 11 '22 03:08 StarArawn

So, several things have changed with the move to 0.7.0. I'm going to focus on the startup/set up, as that's where most of the confusion was, for me.

In the samples, MapQuery was used in startup to build layers, which is now handled differently. So, to update you need to:

  • remove MapQuery from startup parameters
  • asset_server.load now needs a type of Handle<Image> to get its return value into the form we need for a tilemap; for example:

let texture_handle: Handle<Image> = asset_server.load(FILENAME);

  • (old) MapSize and ChunkSize are now (new) combined into TilemapSize; for example:

MapSize(10,10), ChunkSize(64, 64) would now be let timemap_size = TilemapSize(x:640, y:640);

  • (new) let mut tile_storage = TileStorage::empty(tilemap_size); (using the TilemapSize, above)
  • (new) let tilemap_id = TilemapId(tilemap_entity); (where the tilemap_entity existed in the previous version)
  • (old) layer_builder.fill() calls become (new) bevy_ecs_tilemap::helpers::fill_tilemap_rect() calls using this format:
bevy_ecs_tilemap::helpers::fill_tilemap_rect(
        TileTexture(0),
        TilePos { x: 0, y: 0 },
        TilemapSize { x: 128, y: 128 },
        tilemap_id,
        &mut commands,
        &mut tile_storage,
    );
  • (new) let tile_size = TilemapTileSize { x: 17.0, y: 15.0 }; let grid_size = TilemapGridSize { x: 17.0, y: 15.0 }; (these seem to need to be the same, in most cases, and are directly tied to the individual tile size in pixels in the tilemap; previously this was the TileSize part of the LayerSettings)
  • (old) commands.insert(map) becomes (new) commands.insert_bundle(TilemapBundle{}) using the various items noted above. For example:
commands
    .entity(tilemap_entity)
    .insert_bundle(TilemapBundle {
        grid_size,
        size: tilemap_size,
        storage: tile_storage,
        texture: TilemapTexture(texture_handle),
        tile_size,
        mesh_type: TilemapMeshType::Hexagon(HexType::Column),
        ..Default::default()
    });

Together these changes got me going again, but I suspect there are other differences in usage that I had not run into. Hopefully this will help anyone else who is starting on that transition. though.

Caligari avatar Aug 17 '22 05:08 Caligari