bevy_entitiles 0.1.1

A tilemap library for bevy. With many algorithms built in.
use bevy::prelude::{UVec2, Vec2};

use crate::{
    render::extract::{ExtractedTilemap, ExtractedView},
    tilemap::{TileType, TilemapBuilder},
};

#[derive(Clone, Copy, Default, Debug)]
pub struct AabbBox2d {
    pub min: Vec2,
    pub max: Vec2,
}

impl AabbBox2d {
    pub fn new(min_x: f32, min_y: f32, max_x: f32, max_y: f32) -> Self {
        AabbBox2d {
            min: Vec2::new(min_x, min_y),
            max: Vec2::new(max_x, max_y),
        }
    }

    pub fn from_chunk(chunk_index: UVec2, tilemap: &ExtractedTilemap) -> Self {
        match tilemap.tile_type {
            TileType::Square => {
                let chunk_render_size = tilemap.tile_render_size * tilemap.render_chunk_size as f32;
                AabbBox2d {
                    min: chunk_index.as_vec2() * chunk_render_size + tilemap.translation,
                    max: (chunk_index + 1).as_vec2() * chunk_render_size + tilemap.translation,
                }
            }
            TileType::IsometricDiamond => {
                let chunk_index = chunk_index.as_vec2();
                let chunk_render_size = tilemap.render_chunk_size as f32 * tilemap.tile_render_size;
                let center_x = (chunk_index.x - chunk_index.y) / 2. * chunk_render_size.x;
                let center_y = (chunk_index.x + chunk_index.y + 1.) / 2. * chunk_render_size.y;

                AabbBox2d {
                    min: Vec2::new(
                        center_x - chunk_render_size.x / 2. + tilemap.translation.x,
                        center_y - chunk_render_size.y / 2. + tilemap.translation.y,
                    ),
                    max: Vec2::new(
                        center_x + chunk_render_size.x / 2. + tilemap.translation.x,
                        center_y + chunk_render_size.y / 2. + tilemap.translation.y,
                    ),
                }
            }
        }
    }

    pub fn from_tilemap_builder(builder: &TilemapBuilder) -> AabbBox2d {
        match builder.tile_type {
            TileType::Square => {
                let tilemap_render_size = builder.size.as_vec2() * builder.tile_render_size;
                AabbBox2d {
                    min: (tilemap_render_size - tilemap_render_size) / 2. + builder.translation,
                    max: (tilemap_render_size + tilemap_render_size) / 2. + builder.translation,
                }
            }
            TileType::IsometricDiamond => {
                let size = builder.size.as_vec2();
                let tilemap_render_size = (size.x + size.y) / 2. * builder.tile_render_size;
                let center_x = (size.x - size.y) * builder.tile_render_size.x / 4.;
                let center_y = tilemap_render_size.y / 2.;
                AabbBox2d {
                    min: Vec2::new(
                        center_x - tilemap_render_size.x / 2. + builder.translation.x,
                        center_y - tilemap_render_size.y / 2. + builder.translation.y,
                    ),
                    max: Vec2::new(
                        center_x + tilemap_render_size.x / 2. + builder.translation.x,
                        center_y + tilemap_render_size.y / 2. + builder.translation.y,
                    ),
                }
            }
        }
    }

    pub fn from_camera(camera: &ExtractedView) -> Self {
        let half_width = camera.width * camera.scale;
        let half_height = camera.height * camera.scale;
        AabbBox2d {
            min: Vec2::new(
                camera.transform.x - half_width,
                camera.transform.y - half_height,
            ),
            max: Vec2::new(
                camera.transform.x + half_width,
                camera.transform.y + half_height,
            ),
        }
    }

    #[inline]
    pub fn width(&self) -> f32 {
        self.max.x - self.min.x
    }

    #[inline]
    pub fn height(&self) -> f32 {
        self.max.y - self.min.y
    }

    #[inline]
    pub fn center(&self) -> Vec2 {
        (self.min + self.max) / 2.
    }

    #[inline]
    pub fn top_left(&self) -> Vec2 {
        Vec2::new(self.min.x, self.max.y)
    }

    #[inline]
    pub fn bottom_right(&self) -> Vec2 {
        Vec2::new(self.max.x, self.min.y)
    }

    #[inline]
    pub fn area(&self) -> f32 {
        self.width() * self.height()
    }

    #[inline]
    pub fn expand(&mut self, other: &AabbBox2d) {
        self.min = self.min.min(other.min);
        self.max = self.max.max(other.max);
    }

    #[inline]
    pub fn is_intersected_with(&self, other: &AabbBox2d) -> bool {
        self.min.x < other.max.x
            && self.max.x > other.min.x
            && self.min.y < other.max.y
            && self.max.y > other.min.y
    }

    #[inline]
    pub fn with_additional_translation(&self, translation: Vec2) -> Self {
        AabbBox2d {
            min: self.min + translation,
            max: self.max + translation,
        }
    }

    #[inline]
    pub fn with_uniform_scale(&self, scale: f32) -> Self {
        let width = self.width() * scale;
        let height = self.height() * scale;
        AabbBox2d {
            min: self.center() - Vec2::new(width, height) / 2.,
            max: self.center() + Vec2::new(width, height) / 2.,
        }
    }
}