TilemapChunk cleanup (#19795)
# Objective - Make follow-up changes from #18866 ## Solution - Switch from the on add observer to an on insert hook - Make the component immutable - Remove required components ## Testing - `tilemap_chunk` example
This commit is contained in:
parent
a3d406dd49
commit
04c2b32be8
@ -5,11 +5,11 @@ use bevy_derive::{Deref, DerefMut};
|
|||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
component::Component,
|
component::Component,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
lifecycle::Add,
|
lifecycle::HookContext,
|
||||||
observer::On,
|
|
||||||
query::Changed,
|
query::Changed,
|
||||||
resource::Resource,
|
resource::Resource,
|
||||||
system::{Commands, Query, ResMut},
|
system::{Query, ResMut},
|
||||||
|
world::DeferredWorld,
|
||||||
};
|
};
|
||||||
use bevy_image::{Image, ImageSampler};
|
use bevy_image::{Image, ImageSampler};
|
||||||
use bevy_math::{FloatOrd, UVec2, Vec2, Vec3};
|
use bevy_math::{FloatOrd, UVec2, Vec2, Vec3};
|
||||||
@ -33,7 +33,6 @@ pub struct TilemapChunkPlugin;
|
|||||||
impl Plugin for TilemapChunkPlugin {
|
impl Plugin for TilemapChunkPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.init_resource::<TilemapChunkMeshCache>()
|
app.init_resource::<TilemapChunkMeshCache>()
|
||||||
.add_observer(on_add_tilemap_chunk)
|
|
||||||
.add_systems(Update, update_tilemap_chunk_indices);
|
.add_systems(Update, update_tilemap_chunk_indices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,7 +46,8 @@ pub struct TilemapChunkMeshCache(HashMap<TilemapChunkMeshCacheKey, Handle<Mesh>>
|
|||||||
/// A component representing a chunk of a tilemap.
|
/// A component representing a chunk of a tilemap.
|
||||||
/// Each chunk is a rectangular section of tiles that is rendered as a single mesh.
|
/// Each chunk is a rectangular section of tiles that is rendered as a single mesh.
|
||||||
#[derive(Component, Clone, Debug, Default)]
|
#[derive(Component, Clone, Debug, Default)]
|
||||||
#[require(Mesh2d, MeshMaterial2d<TilemapChunkMaterial>, TilemapChunkIndices, Anchor)]
|
#[require(Anchor)]
|
||||||
|
#[component(immutable, on_insert = on_insert_tilemap_chunk)]
|
||||||
pub struct TilemapChunk {
|
pub struct TilemapChunk {
|
||||||
/// The size of the chunk in tiles
|
/// The size of the chunk in tiles
|
||||||
pub chunk_size: UVec2,
|
pub chunk_size: UVec2,
|
||||||
@ -62,31 +62,26 @@ pub struct TilemapChunk {
|
|||||||
|
|
||||||
/// Component storing the indices of tiles within a chunk.
|
/// Component storing the indices of tiles within a chunk.
|
||||||
/// Each index corresponds to a specific tile in the tileset.
|
/// Each index corresponds to a specific tile in the tileset.
|
||||||
#[derive(Component, Clone, Debug, Default, Deref, DerefMut)]
|
#[derive(Component, Clone, Debug, Deref, DerefMut)]
|
||||||
pub struct TilemapChunkIndices(pub Vec<Option<u16>>);
|
pub struct TilemapChunkIndices(pub Vec<Option<u16>>);
|
||||||
|
|
||||||
fn on_add_tilemap_chunk(
|
fn on_insert_tilemap_chunk(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
|
||||||
trigger: On<Add, TilemapChunk>,
|
let Some(tilemap_chunk) = world.get::<TilemapChunk>(entity) else {
|
||||||
tilemap_chunk_query: Query<(&TilemapChunk, &TilemapChunkIndices, &Anchor)>,
|
warn!("TilemapChunk not found for tilemap chunk {}", entity);
|
||||||
mut commands: Commands,
|
return;
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
};
|
||||||
mut materials: ResMut<Assets<TilemapChunkMaterial>>,
|
|
||||||
mut images: ResMut<Assets<Image>>,
|
let chunk_size = tilemap_chunk.chunk_size;
|
||||||
mut tilemap_chunk_mesh_cache: ResMut<TilemapChunkMeshCache>,
|
let alpha_mode = tilemap_chunk.alpha_mode;
|
||||||
) {
|
let tileset = tilemap_chunk.tileset.clone();
|
||||||
let chunk_entity = trigger.target();
|
|
||||||
let Ok((
|
let Some(indices) = world.get::<TilemapChunkIndices>(entity) else {
|
||||||
TilemapChunk {
|
warn!("TilemapChunkIndices not found for tilemap chunk {}", entity);
|
||||||
chunk_size,
|
return;
|
||||||
tile_display_size,
|
};
|
||||||
tileset,
|
|
||||||
alpha_mode,
|
let Some(&anchor) = world.get::<Anchor>(entity) else {
|
||||||
},
|
warn!("Anchor not found for tilemap chunk {}", entity);
|
||||||
indices,
|
|
||||||
anchor,
|
|
||||||
)) = tilemap_chunk_query.get(chunk_entity)
|
|
||||||
else {
|
|
||||||
warn!("Tilemap chunk {} not found", chunk_entity);
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -94,7 +89,7 @@ fn on_add_tilemap_chunk(
|
|||||||
if indices.len() != expected_indices_length {
|
if indices.len() != expected_indices_length {
|
||||||
warn!(
|
warn!(
|
||||||
"Invalid indices length for tilemap chunk {} of size {}. Expected {}, got {}",
|
"Invalid indices length for tilemap chunk {} of size {}. Expected {}, got {}",
|
||||||
chunk_entity,
|
entity,
|
||||||
chunk_size,
|
chunk_size,
|
||||||
indices.len(),
|
indices.len(),
|
||||||
expected_indices_length
|
expected_indices_length
|
||||||
@ -102,30 +97,40 @@ fn on_add_tilemap_chunk(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let indices_image = make_chunk_image(chunk_size, &indices.0);
|
let indices_image = make_chunk_image(&chunk_size, &indices.0);
|
||||||
|
|
||||||
let display_size = (chunk_size * tile_display_size).as_vec2();
|
let display_size = (chunk_size * tilemap_chunk.tile_display_size).as_vec2();
|
||||||
|
|
||||||
let mesh_key: TilemapChunkMeshCacheKey = (
|
let mesh_key: TilemapChunkMeshCacheKey = (
|
||||||
*chunk_size,
|
chunk_size,
|
||||||
FloatOrd(display_size.x),
|
FloatOrd(display_size.x),
|
||||||
FloatOrd(display_size.y),
|
FloatOrd(display_size.y),
|
||||||
FloatOrd(anchor.as_vec().x),
|
FloatOrd(anchor.as_vec().x),
|
||||||
FloatOrd(anchor.as_vec().y),
|
FloatOrd(anchor.as_vec().y),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mesh = tilemap_chunk_mesh_cache
|
let tilemap_chunk_mesh_cache = world.resource::<TilemapChunkMeshCache>();
|
||||||
.entry(mesh_key)
|
let mesh = if let Some(mesh) = tilemap_chunk_mesh_cache.get(&mesh_key) {
|
||||||
.or_insert_with(|| meshes.add(make_chunk_mesh(chunk_size, &display_size, anchor)));
|
mesh.clone()
|
||||||
|
} else {
|
||||||
|
let mut meshes = world.resource_mut::<Assets<Mesh>>();
|
||||||
|
meshes.add(make_chunk_mesh(&chunk_size, &display_size, &anchor))
|
||||||
|
};
|
||||||
|
|
||||||
commands.entity(chunk_entity).insert((
|
let mut images = world.resource_mut::<Assets<Image>>();
|
||||||
Mesh2d(mesh.clone()),
|
let indices = images.add(indices_image);
|
||||||
MeshMaterial2d(materials.add(TilemapChunkMaterial {
|
|
||||||
tileset: tileset.clone(),
|
let mut materials = world.resource_mut::<Assets<TilemapChunkMaterial>>();
|
||||||
indices: images.add(indices_image),
|
let material = materials.add(TilemapChunkMaterial {
|
||||||
alpha_mode: *alpha_mode,
|
tileset,
|
||||||
})),
|
indices,
|
||||||
));
|
alpha_mode,
|
||||||
|
});
|
||||||
|
|
||||||
|
world
|
||||||
|
.commands()
|
||||||
|
.entity(entity)
|
||||||
|
.insert((Mesh2d(mesh), MeshMaterial2d(material)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_tilemap_chunk_indices(
|
fn update_tilemap_chunk_indices(
|
||||||
@ -154,6 +159,7 @@ fn update_tilemap_chunk_indices(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Getting the material mutably to trigger change detection
|
||||||
let Some(material) = materials.get_mut(material.id()) else {
|
let Some(material) = materials.get_mut(material.id()) else {
|
||||||
warn!(
|
warn!(
|
||||||
"TilemapChunkMaterial not found for tilemap chunk {}",
|
"TilemapChunkMaterial not found for tilemap chunk {}",
|
||||||
|
@ -9,7 +9,6 @@ use bevy_render::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Plugin that adds support for tilemap chunk materials.
|
/// Plugin that adds support for tilemap chunk materials.
|
||||||
#[derive(Default)]
|
|
||||||
pub struct TilemapChunkMaterialPlugin;
|
pub struct TilemapChunkMaterialPlugin;
|
||||||
|
|
||||||
impl Plugin for TilemapChunkMaterialPlugin {
|
impl Plugin for TilemapChunkMaterialPlugin {
|
||||||
|
Loading…
Reference in New Issue
Block a user