bevy_entitiles 0.11.0

A 2d tilemap library for bevy. With many useful algorithms/tools built in.
Documentation
use std::marker::PhantomData;

use bevy::{
    app::{App, Plugin, Update},
    asset::Handle,
    ecs::entity::Entity,
    render::render_resource::FilterMode,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};

use crate::{
    render::material::TilemapMaterial,
    serializing::map::save::TilemapSaver,
    tilemap::{
        bundles::{MaterialTilemapBundle, StandardPureColorTilemapBundle},
        chunking::storage::ChunkedStorage,
        map::{
            TilePivot, TileRenderSize, TilemapAnimations, TilemapLayerOpacities, TilemapName,
            TilemapSlotSize, TilemapStorage, TilemapTextureDescriptor, TilemapTextures,
            TilemapTransform, TilemapType,
        },
        tile::TileBuilder,
    },
};

pub const TILEMAP_META: &str = "tilemap.ron";
pub const TILES: &str = "tiles.ron";
pub const PATH_TILES: &str = "path_tiles.ron";
pub const PHYSICS_TILES: &str = "physics_tiles.ron";

pub mod load;
pub mod save;

#[derive(Default)]
pub struct EntiTilesTilemapSerializingPlugin<M: TilemapMaterial + Serialize + DeserializeOwned>(
    PhantomData<M>,
);

impl<M: TilemapMaterial + Serialize + DeserializeOwned> Plugin
    for EntiTilesTilemapSerializingPlugin<M>
{
    fn build(&self, app: &mut App) {
        app.add_systems(Update, (save::save::<M>, load::load::<M>));
    }
}

#[derive(Serialize, Deserialize)]
pub struct SerializedTilemapData<M: TilemapMaterial> {
    pub tilemap: SerializedTilemap<M>,
    pub tiles: Vec<TileBuilder>,
}

#[derive(Serialize, Deserialize)]
pub struct SerializedTilemap<M: TilemapMaterial> {
    pub name: TilemapName,
    pub tile_render_size: TileRenderSize,
    pub slot_size: TilemapSlotSize,
    pub ty: TilemapType,
    pub tile_pivot: TilePivot,
    pub layer_opacities: TilemapLayerOpacities,
    pub tilemap_transform: TilemapTransform,
    pub material: M,
    pub textures: Option<(Vec<SerializedTilemapTexture>, SerializedFilterMode)>,
    pub animations: Option<TilemapAnimations>,
    pub layers: TilemapLayer,
    pub chunk_size: u32,
}

impl<M: TilemapMaterial> SerializedTilemap<M> {
    pub fn from_tilemap(
        name: TilemapName,
        tile_render_size: TileRenderSize,
        slot_size: TilemapSlotSize,
        ty: TilemapType,
        tile_pivot: TilePivot,
        layer_opacities: TilemapLayerOpacities,
        storage: TilemapStorage,
        tilemap_transform: TilemapTransform,
        texture: Option<TilemapTextures>,
        material: M,
        animations: Option<TilemapAnimations>,
        saver: &TilemapSaver,
    ) -> Self {
        SerializedTilemap {
            name: name.clone(),
            ty,
            tile_render_size,
            slot_size,
            tile_pivot,
            material,
            textures: texture.map(|tex| {
                (
                    tex.textures
                        .into_iter()
                        .zip(saver.texture_path.as_ref().unwrap())
                        .map(|(tex, path)| SerializedTilemapTexture {
                            path: path.clone(),
                            desc: tex.desc.clone(),
                        })
                        .collect(),
                    tex.filter_mode.into(),
                )
            }),
            layer_opacities,
            tilemap_transform,
            layers: saver.layers,
            animations,
            chunk_size: storage.storage.chunk_size,
        }
    }

    pub fn into_tilemap(
        &self,
        tilemap: Entity,
        textures: Handle<TilemapTextures>,
        material: Handle<M>,
    ) -> MaterialTilemapBundle<M> {
        MaterialTilemapBundle {
            name: self.name.clone(),
            ty: self.ty,
            tile_render_size: self.tile_render_size,
            slot_size: self.slot_size,
            tile_pivot: self.tile_pivot,
            layer_opacities: self.layer_opacities,
            storage: TilemapStorage {
                tilemap,
                storage: ChunkedStorage::new(self.chunk_size),
                ..Default::default()
            },
            material,
            transform: self.tilemap_transform,
            textures,
            animations: self.animations.clone().unwrap(),
            ..Default::default()
        }
    }

    pub fn into_pure_color_tilemap(&self, tilemap: Entity) -> StandardPureColorTilemapBundle {
        StandardPureColorTilemapBundle {
            name: self.name.clone(),
            ty: self.ty,
            tile_render_size: self.tile_render_size,
            slot_size: self.slot_size,
            tile_pivot: self.tile_pivot,
            layer_opacities: self.layer_opacities,
            storage: TilemapStorage {
                tilemap,
                storage: ChunkedStorage::new(self.chunk_size),
                ..Default::default()
            },
            transform: self.tilemap_transform,
            ..Default::default()
        }
    }
}

#[derive(Serialize, Deserialize)]
pub struct SerializedTilemapTexture {
    pub path: String,
    pub desc: TilemapTextureDescriptor,
}

#[derive(Serialize, Deserialize, Clone, Copy)]
pub enum SerializedFilterMode {
    Nearest = 0,
    Linear = 1,
}

impl From<FilterMode> for SerializedFilterMode {
    fn from(value: FilterMode) -> Self {
        match value {
            FilterMode::Nearest => Self::Nearest,
            FilterMode::Linear => Self::Linear,
        }
    }
}

impl Into<FilterMode> for SerializedFilterMode {
    fn into(self) -> FilterMode {
        match self {
            Self::Nearest => FilterMode::Nearest,
            Self::Linear => FilterMode::Linear,
        }
    }
}

bitflags::bitflags! {
    #[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Clone, Copy, Debug)]
    pub struct TilemapLayer: u32 {
        const COLOR = 1;
        const PATH = 1 << 1;
        const PHYSICS = 1 << 2;
    }
}