@@ -5,11 +5,11 @@ use bevy_derive::{Deref, DerefMut};
5
5
use bevy_ecs:: {
6
6
component:: Component ,
7
7
entity:: Entity ,
8
- lifecycle:: Add ,
9
- observer:: On ,
8
+ lifecycle:: HookContext ,
10
9
query:: Changed ,
11
10
resource:: Resource ,
12
- system:: { Commands , Query , ResMut } ,
11
+ system:: { Query , ResMut } ,
12
+ world:: DeferredWorld ,
13
13
} ;
14
14
use bevy_image:: { Image , ImageSampler } ;
15
15
use bevy_math:: { FloatOrd , UVec2 , Vec2 , Vec3 } ;
@@ -33,7 +33,6 @@ pub struct TilemapChunkPlugin;
33
33
impl Plugin for TilemapChunkPlugin {
34
34
fn build ( & self , app : & mut App ) {
35
35
app. init_resource :: < TilemapChunkMeshCache > ( )
36
- . add_observer ( on_add_tilemap_chunk)
37
36
. add_systems ( Update , update_tilemap_chunk_indices) ;
38
37
}
39
38
}
@@ -47,7 +46,8 @@ pub struct TilemapChunkMeshCache(HashMap<TilemapChunkMeshCacheKey, Handle<Mesh>>
47
46
/// A component representing a chunk of a tilemap.
48
47
/// Each chunk is a rectangular section of tiles that is rendered as a single mesh.
49
48
#[ derive( Component , Clone , Debug , Default ) ]
50
- #[ require( Mesh2d , MeshMaterial2d <TilemapChunkMaterial >, TilemapChunkIndices , Anchor ) ]
49
+ #[ require( Anchor ) ]
50
+ #[ component( immutable, on_insert = on_insert_tilemap_chunk) ]
51
51
pub struct TilemapChunk {
52
52
/// The size of the chunk in tiles
53
53
pub chunk_size : UVec2 ,
@@ -62,70 +62,75 @@ pub struct TilemapChunk {
62
62
63
63
/// Component storing the indices of tiles within a chunk.
64
64
/// Each index corresponds to a specific tile in the tileset.
65
- #[ derive( Component , Clone , Debug , Default , Deref , DerefMut ) ]
65
+ #[ derive( Component , Clone , Debug , Deref , DerefMut ) ]
66
66
pub struct TilemapChunkIndices ( pub Vec < Option < u16 > > ) ;
67
67
68
- fn on_add_tilemap_chunk (
69
- trigger : On < Add , TilemapChunk > ,
70
- tilemap_chunk_query : Query < ( & TilemapChunk , & TilemapChunkIndices , & Anchor ) > ,
71
- mut commands : Commands ,
72
- mut meshes : ResMut < Assets < Mesh > > ,
73
- mut materials : ResMut < Assets < TilemapChunkMaterial > > ,
74
- mut images : ResMut < Assets < Image > > ,
75
- mut tilemap_chunk_mesh_cache : ResMut < TilemapChunkMeshCache > ,
76
- ) {
77
- let chunk_entity = trigger. target ( ) ;
78
- let Ok ( (
79
- TilemapChunk {
80
- chunk_size,
81
- tile_display_size,
82
- tileset,
83
- alpha_mode,
84
- } ,
85
- indices,
86
- anchor,
87
- ) ) = tilemap_chunk_query. get ( chunk_entity)
88
- else {
89
- warn ! ( "Tilemap chunk {} not found" , chunk_entity) ;
68
+ fn on_insert_tilemap_chunk ( mut world : DeferredWorld , HookContext { entity, .. } : HookContext ) {
69
+ let Some ( tilemap_chunk) = world. get :: < TilemapChunk > ( entity) else {
70
+ warn ! ( "TilemapChunk not found for tilemap chunk {}" , entity) ;
71
+ return ;
72
+ } ;
73
+
74
+ let chunk_size = tilemap_chunk. chunk_size ;
75
+ let alpha_mode = tilemap_chunk. alpha_mode ;
76
+ let tileset = tilemap_chunk. tileset . clone ( ) ;
77
+
78
+ let Some ( indices) = world. get :: < TilemapChunkIndices > ( entity) else {
79
+ warn ! ( "TilemapChunkIndices not found for tilemap chunk {}" , entity) ;
80
+ return ;
81
+ } ;
82
+
83
+ let Some ( & anchor) = world. get :: < Anchor > ( entity) else {
84
+ warn ! ( "Anchor not found for tilemap chunk {}" , entity) ;
90
85
return ;
91
86
} ;
92
87
93
88
let expected_indices_length = chunk_size. element_product ( ) as usize ;
94
89
if indices. len ( ) != expected_indices_length {
95
90
warn ! (
96
91
"Invalid indices length for tilemap chunk {} of size {}. Expected {}, got {}" ,
97
- chunk_entity ,
92
+ entity ,
98
93
chunk_size,
99
94
indices. len( ) ,
100
95
expected_indices_length
101
96
) ;
102
97
return ;
103
98
}
104
99
105
- let indices_image = make_chunk_image ( chunk_size, & indices. 0 ) ;
100
+ let indices_image = make_chunk_image ( & chunk_size, & indices. 0 ) ;
106
101
107
- let display_size = ( chunk_size * tile_display_size) . as_vec2 ( ) ;
102
+ let display_size = ( chunk_size * tilemap_chunk . tile_display_size ) . as_vec2 ( ) ;
108
103
109
104
let mesh_key: TilemapChunkMeshCacheKey = (
110
- * chunk_size,
105
+ chunk_size,
111
106
FloatOrd ( display_size. x ) ,
112
107
FloatOrd ( display_size. y ) ,
113
108
FloatOrd ( anchor. as_vec ( ) . x ) ,
114
109
FloatOrd ( anchor. as_vec ( ) . y ) ,
115
110
) ;
116
111
117
- let mesh = tilemap_chunk_mesh_cache
118
- . entry ( mesh_key)
119
- . or_insert_with ( || meshes. add ( make_chunk_mesh ( chunk_size, & display_size, anchor) ) ) ;
120
-
121
- commands. entity ( chunk_entity) . insert ( (
122
- Mesh2d ( mesh. clone ( ) ) ,
123
- MeshMaterial2d ( materials. add ( TilemapChunkMaterial {
124
- tileset : tileset. clone ( ) ,
125
- indices : images. add ( indices_image) ,
126
- alpha_mode : * alpha_mode,
127
- } ) ) ,
128
- ) ) ;
112
+ let tilemap_chunk_mesh_cache = world. resource :: < TilemapChunkMeshCache > ( ) ;
113
+ let mesh = if let Some ( mesh) = tilemap_chunk_mesh_cache. get ( & mesh_key) {
114
+ mesh. clone ( )
115
+ } else {
116
+ let mut meshes = world. resource_mut :: < Assets < Mesh > > ( ) ;
117
+ meshes. add ( make_chunk_mesh ( & chunk_size, & display_size, & anchor) )
118
+ } ;
119
+
120
+ let mut images = world. resource_mut :: < Assets < Image > > ( ) ;
121
+ let indices = images. add ( indices_image) ;
122
+
123
+ let mut materials = world. resource_mut :: < Assets < TilemapChunkMaterial > > ( ) ;
124
+ let material = materials. add ( TilemapChunkMaterial {
125
+ tileset,
126
+ indices,
127
+ alpha_mode,
128
+ } ) ;
129
+
130
+ world
131
+ . commands ( )
132
+ . entity ( entity)
133
+ . insert ( ( Mesh2d ( mesh) , MeshMaterial2d ( material) ) ) ;
129
134
}
130
135
131
136
fn update_tilemap_chunk_indices (
@@ -154,6 +159,7 @@ fn update_tilemap_chunk_indices(
154
159
continue ;
155
160
}
156
161
162
+ // Getting the material mutably to trigger change detection
157
163
let Some ( material) = materials. get_mut ( material. id ( ) ) else {
158
164
warn ! (
159
165
"TilemapChunkMaterial not found for tilemap chunk {}" ,
0 commit comments