bevy_entitiles 0.11.0

A 2d tilemap library for bevy. With many useful algorithms/tools built in.
Documentation
use bevy::{
    ecs::{entity::Entity, event::EventWriter, system::Query},
    math::UVec2,
    prelude::Commands,
};

use crate::{
    math::GridRect,
    tilemap::{
        chunking::storage::ChunkedStorage,
        coordinates,
        map::{TilePivot, TilemapSlotSize, TilemapTransform, TilemapType},
        physics::{
            DataPhysicsTilemap, PackedPhysicsTile, PhysicsCollider, PhysicsTileSpawn,
            PhysicsTilemap,
        },
    },
};

pub fn spawn_colliders(
    mut commands: Commands,
    mut tilemaps_query: Query<(
        Entity,
        &mut PhysicsTilemap,
        &TilemapType,
        &TilemapTransform,
        &TilePivot,
        &TilemapSlotSize,
    )>,
    mut spawn_event: EventWriter<PhysicsTileSpawn>,
) {
    for (entity, mut physics_tilemap, ty, transform, tile_pivot, slot_size) in &mut tilemaps_query {
        let PhysicsTilemap {
            storage,
            spawn_queue,
            data,
        } = &mut *physics_tilemap;

        for (aabb, physics_tile, maybe_int_repr) in spawn_queue.drain(..) {
            let vertices = coordinates::get_tile_collider_world(
                aabb.origin,
                *ty,
                aabb.extent,
                transform,
                tile_pivot.0,
                slot_size.0,
            );

            let packed_tile = PackedPhysicsTile {
                parent: aabb.origin,
                collider: match ty {
                    TilemapType::Square | TilemapType::Isometric => {
                        PhysicsCollider::Convex(vertices)
                    }
                    TilemapType::Hexagonal(_) => PhysicsCollider::Polyline(vertices),
                },
                physics_tile,
            };
            let tile_entity = packed_tile.spawn(&mut commands);

            spawn_event.send(PhysicsTileSpawn {
                tilemap: entity,
                tile: tile_entity,
                int_repr: maybe_int_repr,
            });

            storage.set_elem(aabb.origin, tile_entity);
            data.set_elem(aabb.origin, packed_tile);
        }
    }
}

pub fn data_physics_tilemap_analyzer(
    mut commands: Commands,
    mut tilemaps_query: Query<(Entity, &mut DataPhysicsTilemap, Option<&mut PhysicsTilemap>)>,
) {
    for (entity, mut data_tilemap, mut physics_tilemap) in &mut tilemaps_query {
        let mut aabbs = Vec::new();
        let size = data_tilemap.size;
        let air = data_tilemap.air;

        for y in 0..size.y {
            for x in 0..size.x {
                let cur = UVec2 { x, y };

                let cur_i = {
                    let i = data_tilemap.get_or_air(cur);
                    if i == air {
                        continue;
                    }
                    i
                };

                let mut d = UVec2 {
                    x: if x == size.x - 1 { 0 } else { 1 },
                    y: if y == size.y - 1 { 0 } else { 1 },
                };
                let mut dst = cur;
                while d.x != 0 || d.y != 0 {
                    for t_x in cur.x..=dst.x {
                        if data_tilemap.get_or_air(UVec2::new(t_x, dst.y + d.y)) != cur_i {
                            d.y = 0;
                            break;
                        }
                    }

                    for t_y in cur.y..=dst.y {
                        if data_tilemap.get_or_air(UVec2::new(dst.x + d.x, t_y)) != cur_i {
                            d.x = 0;
                            break;
                        }
                    }

                    if d == UVec2::ONE
                        && data_tilemap.get_or_air(UVec2::new(dst.x + 1, dst.y + 1)) != cur_i
                    {
                        d.y = 0;
                    }

                    dst += d;
                }

                for y in cur.y..=dst.y {
                    for x in cur.x..=dst.x {
                        data_tilemap.set(UVec2 { x, y }, air);
                    }
                }

                aabbs.push((
                    GridRect::from_min_max(
                        cur.as_ivec2() + data_tilemap.origin,
                        dst.as_ivec2() + data_tilemap.origin,
                    ),
                    data_tilemap.get_tile(cur_i).unwrap_or_default(),
                    Some(cur_i),
                ));
            }
        }

        if let Some(physics_tilemap) = &mut physics_tilemap {
            physics_tilemap.spawn_queue.extend(aabbs);
        } else {
            commands.entity(entity).insert(PhysicsTilemap {
                storage: Default::default(),
                spawn_queue: aabbs,
                data: ChunkedStorage::default(),
            });
        }

        commands.entity(entity).remove::<DataPhysicsTilemap>();
    }
}