use bevy::{
asset::Assets,
camera::visibility::{VisibilityClass, add_visibility_class},
ecs::{
entity::{EntityMapper, MapEntities},
reflect::ReflectMapEntities,
},
math::{UVec2, Vec2},
prelude::{
Component, Deref, DerefMut, Entity, Handle, Image, Reflect, ReflectComponent, Res, ResMut,
},
render::render_resource::TextureUsages,
};
use std::ops::Add;
pub const CHUNK_SIZE_2D: UVec2 = UVec2::from_array([64, 64]);
#[derive(Component, Debug, Copy, Clone)]
#[require(VisibilityClass)]
#[component(on_add = add_visibility_class::<TilemapRenderSettings>)]
pub struct TilemapRenderSettings {
pub render_chunk_size: UVec2,
pub y_sort: bool,
}
impl Default for TilemapRenderSettings {
fn default() -> Self {
Self {
render_chunk_size: CHUNK_SIZE_2D,
y_sort: false,
}
}
}
#[derive(Component, Reflect, Clone, Copy, Debug, Hash, Deref, DerefMut, PartialEq, Eq)]
#[reflect(Component, MapEntities)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TilemapId(pub Entity);
impl MapEntities for TilemapId {
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
self.0 = entity_mapper.get_mapped(self.0);
}
}
impl Default for TilemapId {
fn default() -> Self {
Self(Entity::from_raw_u32(0).unwrap())
}
}
#[derive(Component, Reflect, Default, Clone, Copy, Debug, Hash, PartialEq)]
#[reflect(Component)]
pub struct TilemapSize {
pub x: u32,
pub y: u32,
}
impl TilemapSize {
pub const fn new(x: u32, y: u32) -> Self {
Self { x, y }
}
pub const fn count(&self) -> usize {
(self.x * self.y) as usize
}
}
impl Add<TilemapSize> for TilemapSize {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
TilemapSize {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl From<TilemapSize> for Vec2 {
fn from(tilemap_size: TilemapSize) -> Self {
Vec2::new(tilemap_size.x as f32, tilemap_size.y as f32)
}
}
impl From<&TilemapSize> for Vec2 {
fn from(tilemap_size: &TilemapSize) -> Self {
Vec2::new(tilemap_size.x as f32, tilemap_size.y as f32)
}
}
impl From<TilemapSize> for UVec2 {
fn from(size: TilemapSize) -> Self {
UVec2::new(size.x, size.y)
}
}
impl From<UVec2> for TilemapSize {
fn from(vec: UVec2) -> Self {
TilemapSize { x: vec.x, y: vec.y }
}
}
#[derive(Component, Reflect, Clone, Debug, Hash, PartialEq, Eq)]
#[reflect(Component)]
pub enum TilemapTexture {
Single(Handle<Image>),
#[cfg(not(feature = "atlas"))]
Vector(Vec<Handle<Image>>),
#[cfg(not(feature = "atlas"))]
TextureContainer(Handle<Image>),
}
impl Default for TilemapTexture {
fn default() -> Self {
TilemapTexture::Single(Default::default())
}
}
impl TilemapTexture {
#[cfg(feature = "atlas")]
pub fn image_handle(&self) -> &Handle<Image> {
match &self {
TilemapTexture::Single(handle) => handle,
}
}
pub fn image_handles(&self) -> Vec<&Handle<Image>> {
match &self {
TilemapTexture::Single(handle) => vec![handle],
#[cfg(not(feature = "atlas"))]
TilemapTexture::Vector(handles) => handles.iter().collect(),
#[cfg(not(feature = "atlas"))]
TilemapTexture::TextureContainer(handle) => vec![handle],
}
}
pub fn verify_ready(&self, images: &Res<Assets<Image>>) -> bool {
#[cfg(feature = "atlas")]
{
images.get(self.image_handle()).is_some()
}
#[cfg(not(feature = "atlas"))]
self.image_handles().into_iter().all(|h| {
if let Some(image) = images.get(h) {
image
.texture_descriptor
.usage
.contains(TextureUsages::COPY_SRC)
} else {
false
}
})
}
pub fn set_images_to_copy_src(&self, images: &mut ResMut<Assets<Image>>) {
for handle in self.image_handles() {
if let Some(image) = images.get(handle)
&& !image
.texture_descriptor
.usage
.contains(TextureUsages::COPY_SRC)
&& let Some(image) = images.get_mut(handle)
{
image.texture_descriptor.usage = TextureUsages::TEXTURE_BINDING
| TextureUsages::COPY_SRC
| TextureUsages::COPY_DST;
};
}
}
}
#[derive(Component, Reflect, Default, Clone, Copy, Debug, PartialOrd, PartialEq)]
#[reflect(Component)]
pub struct TilemapTileSize {
pub x: f32,
pub y: f32,
}
impl TilemapTileSize {
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
}
impl Add<TilemapTileSize> for TilemapTileSize {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl Add<Vec2> for TilemapTileSize {
type Output = Self;
fn add(self, rhs: Vec2) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl From<TilemapTileSize> for TilemapGridSize {
fn from(tile_size: TilemapTileSize) -> Self {
TilemapGridSize {
x: tile_size.x,
y: tile_size.y,
}
}
}
impl From<TilemapTileSize> for Vec2 {
fn from(tile_size: TilemapTileSize) -> Self {
Vec2::new(tile_size.x, tile_size.y)
}
}
impl From<&TilemapTileSize> for Vec2 {
fn from(tile_size: &TilemapTileSize) -> Self {
Vec2::new(tile_size.x, tile_size.y)
}
}
impl From<Vec2> for TilemapTileSize {
fn from(v: Vec2) -> Self {
let Vec2 { x, y } = v;
TilemapTileSize { x, y }
}
}
#[derive(Component, Reflect, Default, Clone, Copy, Debug, PartialOrd, PartialEq)]
#[reflect(Component)]
pub struct TilemapGridSize {
pub x: f32,
pub y: f32,
}
impl TilemapGridSize {
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
}
impl Add<TilemapGridSize> for TilemapGridSize {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
TilemapGridSize {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl Add<Vec2> for TilemapGridSize {
type Output = Self;
fn add(self, rhs: Vec2) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl From<TilemapGridSize> for Vec2 {
fn from(grid_size: TilemapGridSize) -> Self {
Vec2::new(grid_size.x, grid_size.y)
}
}
impl From<&TilemapGridSize> for Vec2 {
fn from(grid_size: &TilemapGridSize) -> Self {
Vec2::new(grid_size.x, grid_size.y)
}
}
impl From<Vec2> for TilemapGridSize {
fn from(v: Vec2) -> Self {
TilemapGridSize { x: v.x, y: v.y }
}
}
impl From<&Vec2> for TilemapGridSize {
fn from(v: &Vec2) -> Self {
TilemapGridSize { x: v.x, y: v.y }
}
}
#[derive(Component, Reflect, Default, Clone, Copy, Debug, PartialEq)]
#[reflect(Component)]
pub struct TilemapSpacing {
pub x: f32,
pub y: f32,
}
impl Add<TilemapSpacing> for TilemapSpacing {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
TilemapSpacing {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl Add<Vec2> for TilemapSpacing {
type Output = Self;
fn add(self, rhs: Vec2) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl From<TilemapSpacing> for Vec2 {
fn from(spacing: TilemapSpacing) -> Self {
Vec2::new(spacing.x, spacing.y)
}
}
impl TilemapSpacing {
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
pub const fn zero() -> Self {
Self { x: 0.0, y: 0.0 }
}
}
#[derive(Component, Reflect, Default, Clone, Copy, Debug, PartialEq)]
#[reflect(Component)]
pub struct TilemapTextureSize {
pub x: f32,
pub y: f32,
}
impl TilemapTextureSize {
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
}
impl Add<TilemapTextureSize> for TilemapTextureSize {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
TilemapTextureSize {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl Add<Vec2> for TilemapTextureSize {
type Output = Self;
fn add(self, rhs: Vec2) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl From<TilemapTextureSize> for Vec2 {
fn from(texture_size: TilemapTextureSize) -> Self {
Vec2::new(texture_size.x, texture_size.y)
}
}
impl From<Vec2> for TilemapTextureSize {
fn from(size: Vec2) -> Self {
TilemapTextureSize {
x: size.x,
y: size.y,
}
}
}
impl From<TilemapTileSize> for TilemapTextureSize {
fn from(tile_size: TilemapTileSize) -> Self {
let TilemapTileSize { x, y } = tile_size;
TilemapTextureSize { x, y }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)]
pub enum HexCoordSystem {
RowEven,
RowOdd,
ColumnEven,
ColumnOdd,
Row,
Column,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)]
pub enum IsoCoordSystem {
Diamond,
Staggered,
}
#[derive(Component, Reflect, Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[reflect(Component)]
pub enum TilemapType {
#[default]
Square,
Hexagon(HexCoordSystem),
Isometric(IsoCoordSystem),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn add_tilemap_size() {
let a = TilemapSize { x: 2, y: 2 };
let b = TilemapSize { x: 3, y: 3 };
assert_eq!(a + b, TilemapSize { x: 5, y: 5 });
}
#[test]
fn add_tilemap_tile_size() {
let a = TilemapTileSize { x: 2., y: 2. };
let b = TilemapTileSize { x: 3., y: 3. };
assert_eq!(a + b, TilemapTileSize { x: 5., y: 5. });
}
#[test]
fn add_tilemap_tile_size_vec2() {
let a = TilemapTileSize { x: 2., y: 2. };
let b = Vec2 { x: 3., y: 3. };
assert_eq!(a + b, TilemapTileSize { x: 5., y: 5. });
}
#[test]
fn add_tilemap_grid_size() {
let a = TilemapGridSize { x: 2., y: 2. };
let b = TilemapGridSize { x: 3., y: 3. };
assert_eq!(a + b, TilemapGridSize { x: 5., y: 5. });
}
fn add_tilemap_grid_size_vec2() {
let a = TilemapGridSize { x: 2., y: 2. };
let b = Vec2 { x: 3., y: 3. };
assert_eq!(a + b, TilemapGridSize { x: 5., y: 5. });
}
#[test]
fn add_tilemap_spacing() {
let a = TilemapSpacing { x: 2., y: 2. };
let b = TilemapSpacing { x: 3., y: 3. };
assert_eq!(a + b, TilemapSpacing { x: 5., y: 5. });
}
#[test]
fn add_tilemap_spacing_vec2() {
let a = TilemapSpacing { x: 2., y: 2. };
let b = Vec2 { x: 3., y: 3. };
assert_eq!(a + b, TilemapSpacing { x: 5., y: 5. });
}
#[test]
fn add_tilemap_texture_size() {
let a = TilemapTextureSize { x: 2., y: 2. };
let b = TilemapTextureSize { x: 3., y: 3. };
assert_eq!(a + b, TilemapTextureSize { x: 5., y: 5. });
}
#[test]
fn add_tilemap_texture_size_vec2() {
let a = TilemapTextureSize { x: 2., y: 2. };
let b = Vec2 { x: 3., y: 3. };
assert_eq!(a + b, TilemapTextureSize { x: 5., y: 5. });
}
}