bevy_entitiles 0.11.0

A 2d tilemap library for bevy. With many useful algorithms/tools built in.
Documentation
use bevy::{
    ecs::entity::EntityHashMap,
    math::{Mat2, Vec4},
    prelude::{Res, ResMut, Resource, Vec2},
    render::{
        render_resource::{DynamicUniformBuffer, GpuArrayBuffer, ShaderType},
        renderer::{RenderDevice, RenderQueue},
    },
    time::Time,
};

use crate::{render::extract::TilemapInstances, tilemap::map::TilemapType};

#[derive(ShaderType, Clone, Copy)]
pub struct TilemapUniform {
    pub translation: Vec2,
    pub rotation: Mat2,
    pub tile_render_size: Vec2,
    pub slot_size: Vec2,
    pub pivot: Vec2,
    pub layer_opacities: Vec4,
    pub axis_dir: Vec2,
    pub hex_legs: f32,
    pub time: f32,
}

#[cfg(feature = "atlas")]
#[derive(ShaderType, Clone)]
pub struct GpuTilemapTextureDescriptor {
    pub tile_count: bevy::math::UVec2,
    pub tile_uv_size: Vec2,
    pub uv_scale: Vec2,
}

#[derive(Default)]
pub struct SharedTilemapBuffers {
    pub uniform: DynamicUniformBuffer<TilemapUniform>,
    pub indices: EntityHashMap<u32>,
}

pub struct UnsharedTilemapBuffers {
    pub animation: GpuArrayBuffer<i32>,
    #[cfg(feature = "atlas")]
    pub texture_desc: GpuArrayBuffer<GpuTilemapTextureDescriptor>,
}

impl UnsharedTilemapBuffers {
    pub fn new(render_device: &RenderDevice) -> Self {
        Self {
            animation: GpuArrayBuffer::new(render_device),
            #[cfg(feature = "atlas")]
            texture_desc: GpuArrayBuffer::new(render_device),
        }
    }
}

#[derive(Resource, Default)]
pub struct TilemapBuffers {
    pub shared: SharedTilemapBuffers,
    pub unshared: EntityHashMap<UnsharedTilemapBuffers>,
}

pub fn prepare_tilemap_buffers(
    tilemap_instances: Res<TilemapInstances>,
    mut tilemap_buffers: ResMut<TilemapBuffers>,
    render_device: Res<RenderDevice>,
    render_queue: Res<RenderQueue>,
    time: Res<Time>,
    #[cfg(feature = "atlas")] textures_assets: Res<
        bevy::render::render_asset::RenderAssets<crate::tilemap::map::TilemapTextures>,
    >,
) {
    tilemap_buffers.shared.uniform.clear();

    for (entity, tilemap) in tilemap_instances.iter() {
        let index = tilemap_buffers.shared.uniform.push(&TilemapUniform {
            translation: tilemap.transform.translation,
            rotation: tilemap.transform.get_rotation_matrix(),
            tile_render_size: tilemap.tile_render_size,
            slot_size: tilemap.slot_size,
            pivot: tilemap.tile_pivot,
            layer_opacities: tilemap.layer_opacities,
            axis_dir: tilemap.axis_flip.as_vec2(),
            hex_legs: match tilemap.ty {
                TilemapType::Hexagonal(legs) => legs as f32,
                _ => 0.,
            },
            time: time.elapsed_seconds(),
        });
        tilemap_buffers.shared.indices.insert(*entity, index);

        let unshared = tilemap_buffers
            .unshared
            .entry(*entity)
            .or_insert_with(|| UnsharedTilemapBuffers::new(&render_device));
        if let Some(anim) = &tilemap.changed_animations {
            for data in &anim.0 {
                unshared.animation.push(*data);
            }
            unshared
                .animation
                .write_buffer(&render_device, &render_queue);
        }

        #[cfg(feature = "atlas")]
        if let Some(handle) = &tilemap.texture {
            if let Some(textures) = textures_assets.get(handle) {
                unshared.texture_desc.clear();

                for (i, t) in textures.textures.iter().enumerate() {
                    unshared.texture_desc.push(GpuTilemapTextureDescriptor {
                        tile_count: t.desc.size / t.desc.tile_size,
                        tile_uv_size: t.desc.tile_size.as_vec2() / t.desc.size.as_vec2(),
                        uv_scale: textures.uv_scales[i],
                    });
                }

                unshared
                    .texture_desc
                    .write_buffer(&render_device, &render_queue);
            }
        }
    }

    tilemap_buffers
        .shared
        .uniform
        .write_buffer(&render_device, &render_queue);
}