1/**************************************************************************/
2/* tile_map.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "tile_map.h"
32#include "tile_map.compat.inc"
33
34#include "core/core_string_names.h"
35#include "core/io/marshalls.h"
36#include "scene/resources/world_2d.h"
37#include "servers/navigation_server_2d.h"
38
39#ifdef DEBUG_ENABLED
40#include "servers/navigation_server_3d.h"
41#endif // DEBUG_ENABLED
42
43#ifdef DEBUG_ENABLED
44/////////////////////////////// Debug //////////////////////////////////////////
45constexpr int TILE_MAP_DEBUG_QUADRANT_SIZE = 16;
46
47Vector2i TileMapLayer::_coords_to_debug_quadrant_coords(const Vector2i &p_coords) const {
48 return Vector2i(
49 p_coords.x > 0 ? p_coords.x / TILE_MAP_DEBUG_QUADRANT_SIZE : (p_coords.x - (TILE_MAP_DEBUG_QUADRANT_SIZE - 1)) / TILE_MAP_DEBUG_QUADRANT_SIZE,
50 p_coords.y > 0 ? p_coords.y / TILE_MAP_DEBUG_QUADRANT_SIZE : (p_coords.y - (TILE_MAP_DEBUG_QUADRANT_SIZE - 1)) / TILE_MAP_DEBUG_QUADRANT_SIZE);
51}
52
53void TileMapLayer::_debug_update() {
54 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
55 RenderingServer *rs = RenderingServer::get_singleton();
56
57 // Check if we should cleanup everything.
58 bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree();
59
60 if (forced_cleanup) {
61 for (KeyValue<Vector2i, Ref<DebugQuadrant>> &kv : debug_quadrant_map) {
62 // Free the quadrant.
63 Ref<DebugQuadrant> &debug_quadrant = kv.value;
64 if (debug_quadrant->canvas_item.is_valid()) {
65 rs->free(debug_quadrant->canvas_item);
66 }
67 }
68 debug_quadrant_map.clear();
69 _debug_was_cleaned_up = true;
70 return;
71 }
72
73 // Check if anything is dirty, in such a case, redraw debug.
74 bool anything_changed = false;
75 for (int i = 0; i < DIRTY_FLAGS_MAX; i++) {
76 if (dirty.flags[i]) {
77 anything_changed = true;
78 break;
79 }
80 }
81
82 // List all debug quadrants to update, creating new ones if needed.
83 SelfList<DebugQuadrant>::List dirty_debug_quadrant_list;
84
85 if (_debug_was_cleaned_up || anything_changed) {
86 // Update all cells.
87 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
88 CellData &cell_data = kv.value;
89 _debug_quadrants_update_cell(cell_data, dirty_debug_quadrant_list);
90 }
91 } else {
92 // Update dirty cells.
93 for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) {
94 CellData &cell_data = *cell_data_list_element->self();
95 _debug_quadrants_update_cell(cell_data, dirty_debug_quadrant_list);
96 }
97 }
98
99 // Update those quadrants.
100 for (SelfList<DebugQuadrant> *quadrant_list_element = dirty_debug_quadrant_list.first(); quadrant_list_element;) {
101 SelfList<DebugQuadrant> *next_quadrant_list_element = quadrant_list_element->next(); // "Hack" to clear the list while iterating.
102
103 DebugQuadrant &debug_quadrant = *quadrant_list_element->self();
104
105 // Check if the quadrant has a tile.
106 bool has_a_tile = false;
107 RID &ci = debug_quadrant.canvas_item;
108 for (SelfList<CellData> *cell_data_list_element = debug_quadrant.cells.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) {
109 CellData &cell_data = *cell_data_list_element->self();
110 if (cell_data.cell.source_id != TileSet::INVALID_SOURCE) {
111 has_a_tile = true;
112 break;
113 }
114 }
115
116 if (has_a_tile) {
117 // Update the quadrant.
118 if (ci.is_valid()) {
119 rs->canvas_item_clear(ci);
120 } else {
121 ci = rs->canvas_item_create();
122 rs->canvas_item_set_z_index(ci, RS::CANVAS_ITEM_Z_MAX - 1);
123 rs->canvas_item_set_parent(ci, tile_map_node->get_canvas_item());
124 }
125
126 const Vector2 quadrant_pos = tile_map_node->map_to_local(debug_quadrant.quadrant_coords * TILE_MAP_DEBUG_QUADRANT_SIZE);
127 Transform2D xform(0, quadrant_pos);
128 rs->canvas_item_set_transform(ci, xform);
129
130 for (SelfList<CellData> *cell_data_list_element = debug_quadrant.cells.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) {
131 CellData &cell_data = *cell_data_list_element->self();
132 if (cell_data.cell.source_id != TileSet::INVALID_SOURCE) {
133 _rendering_draw_cell_debug(ci, quadrant_pos, cell_data);
134 _physics_draw_cell_debug(ci, quadrant_pos, cell_data);
135 _navigation_draw_cell_debug(ci, quadrant_pos, cell_data);
136 _scenes_draw_cell_debug(ci, quadrant_pos, cell_data);
137 }
138 }
139 } else {
140 // Free the quadrant.
141 if (ci.is_valid()) {
142 rs->free(ci);
143 }
144 quadrant_list_element->remove_from_list();
145 debug_quadrant_map.erase(debug_quadrant.quadrant_coords);
146 }
147
148 quadrant_list_element = next_quadrant_list_element;
149 }
150
151 dirty_debug_quadrant_list.clear();
152
153 _debug_was_cleaned_up = false;
154}
155
156void TileMapLayer::_debug_quadrants_update_cell(CellData &r_cell_data, SelfList<DebugQuadrant>::List &r_dirty_debug_quadrant_list) {
157 Vector2i quadrant_coords = _coords_to_debug_quadrant_coords(r_cell_data.coords);
158
159 if (!debug_quadrant_map.has(quadrant_coords)) {
160 // Create a new quadrant and add it to the quadrant map.
161 Ref<DebugQuadrant> new_quadrant;
162 new_quadrant.instantiate();
163 new_quadrant->quadrant_coords = quadrant_coords;
164 debug_quadrant_map[quadrant_coords] = new_quadrant;
165 }
166
167 // Add the cell to its quadrant, if it is not already in there.
168 Ref<DebugQuadrant> &debug_quadrant = debug_quadrant_map[quadrant_coords];
169 if (!r_cell_data.debug_quadrant_list_element.in_list()) {
170 debug_quadrant->cells.add(&r_cell_data.debug_quadrant_list_element);
171 }
172
173 // Mark the quadrant as dirty.
174 if (!debug_quadrant->dirty_quadrant_list_element.in_list()) {
175 r_dirty_debug_quadrant_list.add(&debug_quadrant->dirty_quadrant_list_element);
176 }
177}
178#endif // DEBUG_ENABLED
179
180/////////////////////////////// Rendering //////////////////////////////////////
181Vector2i TileMapLayer::_coords_to_rendering_quadrant_coords(const Vector2i &p_coords) const {
182 int quad_size = get_effective_quadrant_size();
183
184 // Rounding down, instead of simply rounding towards zero (truncating).
185 return Vector2i(
186 p_coords.x > 0 ? p_coords.x / quad_size : (p_coords.x - (quad_size - 1)) / quad_size,
187 p_coords.y > 0 ? p_coords.y / quad_size : (p_coords.y - (quad_size - 1)) / quad_size);
188}
189
190void TileMapLayer::_rendering_update() {
191 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
192 RenderingServer *rs = RenderingServer::get_singleton();
193
194 // Check if we should cleanup everything.
195 bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree();
196
197 // ----------- Layer level processing -----------
198 if (forced_cleanup) {
199 // Cleanup.
200 if (canvas_item.is_valid()) {
201 rs->free(canvas_item);
202 canvas_item = RID();
203 }
204 } else {
205 // Create/Update the layer's CanvasItem.
206 if (!canvas_item.is_valid()) {
207 RID ci = rs->canvas_item_create();
208 rs->canvas_item_set_parent(ci, tile_map_node->get_canvas_item());
209 rs->canvas_item_set_draw_index(ci, layer_index_in_tile_map_node - (int64_t)0x80000000);
210 canvas_item = ci;
211 }
212 RID &ci = canvas_item;
213 rs->canvas_item_set_sort_children_by_y(ci, y_sort_enabled);
214 rs->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid());
215 rs->canvas_item_set_z_index(ci, z_index);
216 rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree()));
217 rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree()));
218 rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask());
219
220 // Modulate the layer.
221 Color layer_modulate = modulate;
222 int selected_layer = tile_map_node->get_selected_layer();
223 if (selected_layer >= 0 && layer_index_in_tile_map_node != selected_layer) {
224 int z_selected = tile_map_node->get_layer_z_index(selected_layer);
225 if (z_index < z_selected || (z_index == z_selected && layer_index_in_tile_map_node < selected_layer)) {
226 layer_modulate = layer_modulate.darkened(0.5);
227 } else if (z_index > z_selected || (z_index == z_selected && layer_index_in_tile_map_node > selected_layer)) {
228 layer_modulate = layer_modulate.darkened(0.5);
229 layer_modulate.a *= 0.3;
230 }
231 }
232 rs->canvas_item_set_modulate(ci, layer_modulate);
233 }
234
235 // ----------- Quadrants processing -----------
236
237 // List all rendering quadrants to update, creating new ones if needed.
238 SelfList<RenderingQuadrant>::List dirty_rendering_quadrant_list;
239
240 // Check if anything changed that might change the quadrant shape.
241 // If so, recreate everything.
242 if (forced_cleanup || dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE]) {
243 // Free all quadrants.
244 for (const KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) {
245 for (int i = 0; i < kv.value->canvas_items.size(); i++) {
246 const RID &ci = kv.value->canvas_items[i];
247 if (ci.is_valid()) {
248 rs->free(ci);
249 }
250 }
251 kv.value->cells.clear();
252 }
253 rendering_quadrant_map.clear();
254 _rendering_was_cleaned_up = true;
255 }
256
257 if (!forced_cleanup) {
258 // List all quadrants to update, recreating them if needed.
259 if (dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || _rendering_was_cleaned_up) {
260 // Update all cells.
261 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
262 CellData &cell_data = kv.value;
263 _rendering_quadrants_update_cell(cell_data, dirty_rendering_quadrant_list);
264 }
265 } else {
266 // Update dirty cells.
267 for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) {
268 CellData &cell_data = *cell_data_list_element->self();
269 _rendering_quadrants_update_cell(cell_data, dirty_rendering_quadrant_list);
270 }
271 }
272
273 // Update all dirty quadrants.
274 for (SelfList<RenderingQuadrant> *quadrant_list_element = dirty_rendering_quadrant_list.first(); quadrant_list_element;) {
275 SelfList<RenderingQuadrant> *next_quadrant_list_element = quadrant_list_element->next(); // "Hack" to clear the list while iterating.
276
277 const Ref<RenderingQuadrant> &rendering_quadrant = quadrant_list_element->self();
278
279 // Check if the quadrant has a tile.
280 bool has_a_tile = false;
281 for (SelfList<CellData> *cell_data_list_element = rendering_quadrant->cells.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) {
282 CellData &cell_data = *cell_data_list_element->self();
283 if (cell_data.cell.source_id != TileSet::INVALID_SOURCE) {
284 has_a_tile = true;
285 break;
286 }
287 }
288
289 if (has_a_tile) {
290 // Process the quadrant.
291
292 // First, clear the quadrant's canvas items.
293 for (RID &ci : rendering_quadrant->canvas_items) {
294 rs->free(ci);
295 }
296 rendering_quadrant->canvas_items.clear();
297
298 // Those allow to group cell per material or z-index.
299 Ref<Material> prev_material;
300 int prev_z_index = 0;
301 RID prev_ci;
302
303 for (SelfList<CellData> *cell_data_quadrant_list_element = rendering_quadrant->cells.first(); cell_data_quadrant_list_element; cell_data_quadrant_list_element = cell_data_quadrant_list_element->next()) {
304 CellData &cell_data = *cell_data_quadrant_list_element->self();
305
306 TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(*tile_set->get_source(cell_data.cell.source_id));
307
308 // Get the tile data.
309 const TileData *tile_data;
310 if (cell_data.runtime_tile_data_cache) {
311 tile_data = cell_data.runtime_tile_data_cache;
312 } else {
313 tile_data = atlas_source->get_tile_data(cell_data.cell.get_atlas_coords(), cell_data.cell.alternative_tile);
314 }
315
316 Ref<Material> mat = tile_data->get_material();
317 int tile_z_index = tile_data->get_z_index();
318
319 // Quandrant pos.
320 Vector2i quadrant_coords = _coords_to_rendering_quadrant_coords(cell_data.coords);
321 Vector2 ci_position = tile_map_node->map_to_local(quadrant_coords * get_effective_quadrant_size());
322 if (tile_map_node->is_y_sort_enabled() && y_sort_enabled) {
323 // When Y-sorting, the quandrant size is sure to be 1, we can thus offset the CanvasItem.
324 ci_position.y += y_sort_origin + tile_data->get_y_sort_origin();
325 }
326
327 // --- CanvasItems ---
328 RID ci;
329
330 // Check if the material or the z_index changed.
331 if (prev_ci == RID() || prev_material != mat || prev_z_index != tile_z_index) {
332 // If so, create a new CanvasItem.
333 ci = rs->canvas_item_create();
334 if (mat.is_valid()) {
335 rs->canvas_item_set_material(ci, mat->get_rid());
336 }
337 rs->canvas_item_set_parent(ci, canvas_item);
338 rs->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid());
339
340 Transform2D xform(0, ci_position);
341 rs->canvas_item_set_transform(ci, xform);
342
343 rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask());
344 rs->canvas_item_set_z_as_relative_to_parent(ci, true);
345 rs->canvas_item_set_z_index(ci, tile_z_index);
346
347 rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree()));
348 rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree()));
349
350 rendering_quadrant->canvas_items.push_back(ci);
351
352 prev_ci = ci;
353 prev_material = mat;
354 prev_z_index = tile_z_index;
355
356 } else {
357 // Keep the same canvas_item to draw on.
358 ci = prev_ci;
359 }
360
361 const Vector2 local_tile_pos = tile_map_node->map_to_local(cell_data.coords);
362
363 // Random animation offset.
364 real_t random_animation_offset = 0.0;
365 if (atlas_source->get_tile_animation_mode(cell_data.cell.get_atlas_coords()) != TileSetAtlasSource::TILE_ANIMATION_MODE_DEFAULT) {
366 Array to_hash;
367 to_hash.push_back(local_tile_pos);
368 to_hash.push_back(get_instance_id()); // Use instance id as a random hash
369 random_animation_offset = RandomPCG(to_hash.hash()).randf();
370 }
371
372 // Drawing the tile in the canvas item.
373 tile_map_node->draw_tile(ci, local_tile_pos - ci_position, tile_set, cell_data.cell.source_id, cell_data.cell.get_atlas_coords(), cell_data.cell.alternative_tile, -1, tile_map_node->get_self_modulate(), tile_data, random_animation_offset);
374 }
375 } else {
376 // Free the quadrant.
377 for (int i = 0; i < rendering_quadrant->canvas_items.size(); i++) {
378 const RID &ci = rendering_quadrant->canvas_items[i];
379 if (ci.is_valid()) {
380 rs->free(ci);
381 }
382 }
383 rendering_quadrant->cells.clear();
384 rendering_quadrant_map.erase(rendering_quadrant->quadrant_coords);
385 }
386
387 quadrant_list_element = next_quadrant_list_element;
388 }
389
390 dirty_rendering_quadrant_list.clear();
391
392 // Reset the drawing indices.
393 {
394 int index = -(int64_t)0x80000000; // Always must be drawn below children.
395
396 // Sort the quadrants coords per local coordinates.
397 RBMap<Vector2, Ref<RenderingQuadrant>, RenderingQuadrant::CoordsWorldComparator> local_to_map;
398 for (KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) {
399 Ref<RenderingQuadrant> &rendering_quadrant = kv.value;
400 local_to_map[tile_map_node->map_to_local(rendering_quadrant->quadrant_coords)] = rendering_quadrant;
401 }
402
403 // Sort the quadrants.
404 for (const KeyValue<Vector2, Ref<RenderingQuadrant>> &E : local_to_map) {
405 for (const RID &ci : E.value->canvas_items) {
406 RS::get_singleton()->canvas_item_set_draw_index(ci, index++);
407 }
408 }
409 }
410
411 // Updates on TileMap changes.
412 if (dirty.flags[DIRTY_FLAGS_TILE_MAP_LIGHT_MASK] ||
413 dirty.flags[DIRTY_FLAGS_TILE_MAP_USE_PARENT_MATERIAL] ||
414 dirty.flags[DIRTY_FLAGS_TILE_MAP_TEXTURE_FILTER] ||
415 dirty.flags[DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT]) {
416 for (KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) {
417 Ref<RenderingQuadrant> &rendering_quadrant = kv.value;
418 for (const RID &ci : rendering_quadrant->canvas_items) {
419 rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask());
420 rs->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid());
421 rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree()));
422 rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree()));
423 }
424 }
425 }
426 }
427
428 // ----------- Occluders processing -----------
429 if (forced_cleanup) {
430 // Clean everything.
431 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
432 _rendering_occluders_clear_cell(kv.value);
433 }
434 } else {
435 if (_rendering_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) {
436 // Update all cells.
437 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
438 _rendering_occluders_update_cell(kv.value);
439 }
440 } else {
441 // Update dirty cells.
442 for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) {
443 CellData &cell_data = *cell_data_list_element->self();
444 _rendering_occluders_update_cell(cell_data);
445 }
446 }
447
448 // Updates on TileMap changes.
449 if (dirty.flags[DIRTY_FLAGS_TILE_MAP_IN_CANVAS] || dirty.flags[DIRTY_FLAGS_TILE_MAP_VISIBILITY]) {
450 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
451 CellData &cell_data = kv.value;
452 for (const RID &occluder : cell_data.occluders) {
453 Transform2D xform(0, tile_map_node->map_to_local(kv.key));
454 rs->canvas_light_occluder_attach_to_canvas(occluder, tile_map_node->get_canvas());
455 rs->canvas_light_occluder_set_transform(occluder, tile_map_node->get_global_transform() * xform);
456 }
457 }
458 }
459 }
460
461 // -----------
462 // Mark the rendering state as up to date.
463 _rendering_was_cleaned_up = forced_cleanup;
464}
465
466void TileMapLayer::_rendering_quadrants_update_cell(CellData &r_cell_data, SelfList<RenderingQuadrant>::List &r_dirty_rendering_quadrant_list) {
467 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
468 Vector2i quadrant_coords = _coords_to_rendering_quadrant_coords(r_cell_data.coords);
469
470 if (rendering_quadrant_map.has(quadrant_coords)) {
471 // Mark the quadrant as dirty.
472 Ref<RenderingQuadrant> &rendering_quadrant = rendering_quadrant_map[quadrant_coords];
473 if (!rendering_quadrant->dirty_quadrant_list_element.in_list()) {
474 r_dirty_rendering_quadrant_list.add(&rendering_quadrant->dirty_quadrant_list_element);
475 }
476 } else {
477 // Create a new quadrant and add it to the quadrant lists.
478 Ref<RenderingQuadrant> new_quadrant;
479 new_quadrant.instantiate();
480 new_quadrant->quadrant_coords = quadrant_coords;
481 rendering_quadrant_map[quadrant_coords] = new_quadrant;
482 }
483
484 // Check if the cell is valid.
485 bool is_valid = false;
486 TileSetSource *source;
487 if (tile_set->has_source(r_cell_data.cell.source_id)) {
488 source = *tile_set->get_source(r_cell_data.cell.source_id);
489 TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
490 if (atlas_source && atlas_source->has_tile(r_cell_data.cell.get_atlas_coords()) && atlas_source->has_alternative_tile(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile)) {
491 is_valid = true;
492 }
493 }
494
495 // Add/Remove the cell to/from its quadrant.
496 Ref<RenderingQuadrant> &rendering_quadrant = rendering_quadrant_map[quadrant_coords];
497 if (r_cell_data.rendering_quadrant_list_element.in_list()) {
498 if (!is_valid) {
499 r_cell_data.rendering_quadrant_list_element.remove_from_list();
500 }
501 } else {
502 if (is_valid) {
503 rendering_quadrant->cells.add(&r_cell_data.rendering_quadrant_list_element);
504 }
505 }
506
507 // Add the quadrant to the dirty quadrant list.
508 if (!rendering_quadrant->dirty_quadrant_list_element.in_list()) {
509 r_dirty_rendering_quadrant_list.add(&rendering_quadrant->dirty_quadrant_list_element);
510 }
511}
512
513void TileMapLayer::_rendering_occluders_clear_cell(CellData &r_cell_data) {
514 RenderingServer *rs = RenderingServer::get_singleton();
515
516 // Free the occluders.
517 for (const RID &rid : r_cell_data.occluders) {
518 rs->free(rid);
519 }
520 r_cell_data.occluders.clear();
521}
522
523void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) {
524 bool node_visible = tile_map_node->is_visible_in_tree();
525 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
526 RenderingServer *rs = RenderingServer::get_singleton();
527
528 TileSetSource *source;
529 if (tile_set->has_source(r_cell_data.cell.source_id)) {
530 source = *tile_set->get_source(r_cell_data.cell.source_id);
531
532 if (source->has_tile(r_cell_data.cell.get_atlas_coords()) && source->has_alternative_tile(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile)) {
533 TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
534 if (atlas_source) {
535 // Get the tile data.
536 const TileData *tile_data;
537 if (r_cell_data.runtime_tile_data_cache) {
538 tile_data = r_cell_data.runtime_tile_data_cache;
539 } else {
540 tile_data = atlas_source->get_tile_data(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile);
541 }
542
543 // Update/create occluders.
544 for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) {
545 Transform2D xform;
546 xform.set_origin(tile_map_node->map_to_local(r_cell_data.coords));
547 if (tile_data->get_occluder(i).is_valid()) {
548 RID occluder_id = rs->canvas_light_occluder_create();
549 rs->canvas_light_occluder_set_enabled(occluder_id, node_visible);
550 rs->canvas_light_occluder_set_transform(occluder_id, tile_map_node->get_global_transform() * xform);
551 rs->canvas_light_occluder_set_polygon(occluder_id, tile_map_node->get_transformed_polygon(Ref<Resource>(tile_data->get_occluder(i)), r_cell_data.cell.alternative_tile)->get_rid());
552 rs->canvas_light_occluder_attach_to_canvas(occluder_id, tile_map_node->get_canvas());
553 rs->canvas_light_occluder_set_light_mask(occluder_id, tile_set->get_occlusion_layer_light_mask(i));
554 r_cell_data.occluders.push_back(occluder_id);
555 }
556 }
557
558 return;
559 }
560 }
561 }
562
563 // If we did not return earlier, clear the cell.
564 _rendering_occluders_clear_cell(r_cell_data);
565}
566
567#ifdef DEBUG_ENABLED
568void TileMapLayer::_rendering_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data) {
569 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
570 ERR_FAIL_COND(!tile_set.is_valid());
571
572 if (!Engine::get_singleton()->is_editor_hint()) {
573 return;
574 }
575
576 // Draw a placeholder for tiles needing one.
577 RenderingServer *rs = RenderingServer::get_singleton();
578 const TileMapCell &c = r_cell_data.cell;
579
580 TileSetSource *source;
581 if (tile_set->has_source(c.source_id)) {
582 source = *tile_set->get_source(c.source_id);
583
584 if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
585 TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
586 if (atlas_source) {
587 Vector2i grid_size = atlas_source->get_atlas_grid_size();
588 if (!atlas_source->get_runtime_texture().is_valid() || c.get_atlas_coords().x >= grid_size.x || c.get_atlas_coords().y >= grid_size.y) {
589 // Generate a random color from the hashed values of the tiles.
590 Array to_hash;
591 to_hash.push_back(c.source_id);
592 to_hash.push_back(c.get_atlas_coords());
593 to_hash.push_back(c.alternative_tile);
594 uint32_t hash = RandomPCG(to_hash.hash()).rand();
595
596 Color color;
597 color = color.from_hsv(
598 (float)((hash >> 24) & 0xFF) / 256.0,
599 Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0),
600 Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0),
601 0.8);
602
603 // Draw a placeholder tile.
604 Transform2D cell_to_quadrant;
605 cell_to_quadrant.set_origin(tile_map_node->map_to_local(r_cell_data.coords) - p_quadrant_pos);
606 rs->canvas_item_add_set_transform(p_canvas_item, cell_to_quadrant);
607 rs->canvas_item_add_circle(p_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
608 }
609 }
610 }
611 }
612}
613#endif // DEBUG_ENABLED
614
615/////////////////////////////// Physics //////////////////////////////////////
616
617void TileMapLayer::_physics_update() {
618 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
619
620 // Check if we should cleanup everything.
621 bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree();
622 if (forced_cleanup) {
623 // Clean everything.
624 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
625 _physics_clear_cell(kv.value);
626 }
627 } else {
628 if (_physics_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || dirty.flags[DIRTY_FLAGS_TILE_MAP_COLLISION_ANIMATABLE]) {
629 // Update all cells.
630 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
631 _physics_update_cell(kv.value);
632 }
633 } else {
634 // Update dirty cells.
635 for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) {
636 CellData &cell_data = *cell_data_list_element->self();
637 _physics_update_cell(cell_data);
638 }
639 }
640 }
641
642 // -----------
643 // Mark the physics state as up to date.
644 _physics_was_cleaned_up = forced_cleanup;
645}
646
647void TileMapLayer::_physics_notify_tilemap_change(TileMapLayer::DirtyFlags p_what) {
648 Transform2D gl_transform = tile_map_node->get_global_transform();
649 bool in_editor = false;
650#ifdef TOOLS_ENABLED
651 in_editor = Engine::get_singleton()->is_editor_hint();
652#endif
653
654 if (p_what == DIRTY_FLAGS_TILE_MAP_XFORM) {
655 if (tile_map_node->is_inside_tree() && (!tile_map_node->is_collision_animatable() || in_editor)) {
656 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
657 const CellData &cell_data = kv.value;
658
659 for (RID body : cell_data.bodies) {
660 if (body.is_valid()) {
661 Transform2D xform(0, tile_map_node->map_to_local(bodies_coords[body]));
662 xform = gl_transform * xform;
663 PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
664 }
665 }
666 }
667 }
668 } else if (p_what == DIRTY_FLAGS_TILE_MAP_LOCAL_XFORM) {
669 if (tile_map_node->is_inside_tree() && tile_map_node->is_collision_animatable() && !in_editor) {
670 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
671 const CellData &cell_data = kv.value;
672
673 for (RID body : cell_data.bodies) {
674 if (body.is_valid()) {
675 Transform2D xform(0, tile_map_node->map_to_local(bodies_coords[body]));
676 xform = gl_transform * xform;
677 PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
678 }
679 }
680 }
681 }
682 }
683}
684
685void TileMapLayer::_physics_clear_cell(CellData &r_cell_data) {
686 PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
687
688 // Clear bodies.
689 for (RID body : r_cell_data.bodies) {
690 if (body.is_valid()) {
691 bodies_coords.erase(body);
692 ps->free(body);
693 }
694 }
695 r_cell_data.bodies.clear();
696}
697
698void TileMapLayer::_physics_update_cell(CellData &r_cell_data) {
699 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
700 Transform2D gl_transform = tile_map_node->get_global_transform();
701 RID space = tile_map_node->get_world_2d()->get_space();
702 PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
703
704 // Recreate bodies and shapes.
705 TileMapCell &c = r_cell_data.cell;
706
707 TileSetSource *source;
708 if (tile_set->has_source(c.source_id)) {
709 source = *tile_set->get_source(c.source_id);
710
711 if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
712 TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
713 if (atlas_source) {
714 const TileData *tile_data;
715 if (r_cell_data.runtime_tile_data_cache) {
716 tile_data = r_cell_data.runtime_tile_data_cache;
717 } else {
718 tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
719 }
720
721 // Free unused bodies then resize the bodies array.
722 for (unsigned int i = tile_set->get_physics_layers_count(); i < r_cell_data.bodies.size(); i++) {
723 RID body = r_cell_data.bodies[i];
724 if (body.is_valid()) {
725 bodies_coords.erase(body);
726 ps->free(body);
727 }
728 }
729 r_cell_data.bodies.resize(tile_set->get_physics_layers_count());
730
731 for (int tile_set_physics_layer = 0; tile_set_physics_layer < tile_set->get_physics_layers_count(); tile_set_physics_layer++) {
732 Ref<PhysicsMaterial> physics_material = tile_set->get_physics_layer_physics_material(tile_set_physics_layer);
733 uint32_t physics_layer = tile_set->get_physics_layer_collision_layer(tile_set_physics_layer);
734 uint32_t physics_mask = tile_set->get_physics_layer_collision_mask(tile_set_physics_layer);
735
736 RID body = r_cell_data.bodies[tile_set_physics_layer];
737 if (tile_data->get_collision_polygons_count(tile_set_physics_layer) == 0) {
738 // No body needed, free it if it exists.
739 if (body.is_valid()) {
740 bodies_coords.erase(body);
741 ps->free(body);
742 }
743 body = RID();
744 } else {
745 // Create or update the body.
746 if (!body.is_valid()) {
747 body = ps->body_create();
748 }
749 bodies_coords[body] = r_cell_data.coords;
750 ps->body_set_mode(body, tile_map_node->is_collision_animatable() ? PhysicsServer2D::BODY_MODE_KINEMATIC : PhysicsServer2D::BODY_MODE_STATIC);
751 ps->body_set_space(body, space);
752
753 Transform2D xform;
754 xform.set_origin(tile_map_node->map_to_local(r_cell_data.coords));
755 xform = gl_transform * xform;
756 ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
757
758 ps->body_attach_object_instance_id(body, tile_map_node->get_instance_id());
759 ps->body_set_collision_layer(body, physics_layer);
760 ps->body_set_collision_mask(body, physics_mask);
761 ps->body_set_pickable(body, false);
762 ps->body_set_state(body, PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, tile_data->get_constant_linear_velocity(tile_set_physics_layer));
763 ps->body_set_state(body, PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, tile_data->get_constant_angular_velocity(tile_set_physics_layer));
764
765 if (!physics_material.is_valid()) {
766 ps->body_set_param(body, PhysicsServer2D::BODY_PARAM_BOUNCE, 0);
767 ps->body_set_param(body, PhysicsServer2D::BODY_PARAM_FRICTION, 1);
768 } else {
769 ps->body_set_param(body, PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material->computed_bounce());
770 ps->body_set_param(body, PhysicsServer2D::BODY_PARAM_FRICTION, physics_material->computed_friction());
771 }
772
773 // Clear body's shape if needed.
774 ps->body_clear_shapes(body);
775
776 // Add the shapes to the body.
777 int body_shape_index = 0;
778 for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(tile_set_physics_layer); polygon_index++) {
779 // Iterate over the polygons.
780 bool one_way_collision = tile_data->is_collision_polygon_one_way(tile_set_physics_layer, polygon_index);
781 float one_way_collision_margin = tile_data->get_collision_polygon_one_way_margin(tile_set_physics_layer, polygon_index);
782 int shapes_count = tile_data->get_collision_polygon_shapes_count(tile_set_physics_layer, polygon_index);
783 for (int shape_index = 0; shape_index < shapes_count; shape_index++) {
784 // Add decomposed convex shapes.
785 Ref<ConvexPolygonShape2D> shape = tile_data->get_collision_polygon_shape(tile_set_physics_layer, polygon_index, shape_index);
786 shape = tile_map_node->get_transformed_polygon(Ref<Resource>(shape), c.alternative_tile);
787 ps->body_add_shape(body, shape->get_rid());
788 ps->body_set_shape_as_one_way_collision(body, body_shape_index, one_way_collision, one_way_collision_margin);
789
790 body_shape_index++;
791 }
792 }
793 }
794
795 // Set the body again.
796 r_cell_data.bodies[tile_set_physics_layer] = body;
797 }
798
799 return;
800 }
801 }
802 }
803
804 // If we did not return earlier, clear the cell.
805 _physics_clear_cell(r_cell_data);
806}
807
808#ifdef DEBUG_ENABLED
809void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data) {
810 // Draw the debug collision shapes.
811 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
812 ERR_FAIL_COND(!tile_set.is_valid());
813
814 if (!tile_map_node->get_tree()) {
815 return;
816 }
817
818 bool show_collision = false;
819 switch (tile_map_node->get_collision_visibility_mode()) {
820 case TileMap::VISIBILITY_MODE_DEFAULT:
821 show_collision = !Engine::get_singleton()->is_editor_hint() && tile_map_node->get_tree()->is_debugging_collisions_hint();
822 break;
823 case TileMap::VISIBILITY_MODE_FORCE_HIDE:
824 show_collision = false;
825 break;
826 case TileMap::VISIBILITY_MODE_FORCE_SHOW:
827 show_collision = true;
828 break;
829 }
830 if (!show_collision) {
831 return;
832 }
833
834 RenderingServer *rs = RenderingServer::get_singleton();
835 PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
836
837 Color debug_collision_color = tile_map_node->get_tree()->get_debug_collisions_color();
838 Vector<Color> color;
839 color.push_back(debug_collision_color);
840
841 Transform2D quadrant_to_local(0, p_quadrant_pos);
842 Transform2D global_to_quadrant = (tile_map_node->get_global_transform() * quadrant_to_local).affine_inverse();
843
844 for (RID body : r_cell_data.bodies) {
845 if (body.is_valid()) {
846 Transform2D body_to_quadrant = global_to_quadrant * Transform2D(ps->body_get_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM));
847 rs->canvas_item_add_set_transform(p_canvas_item, body_to_quadrant);
848 for (int shape_index = 0; shape_index < ps->body_get_shape_count(body); shape_index++) {
849 const RID &shape = ps->body_get_shape(body, shape_index);
850 const PhysicsServer2D::ShapeType &type = ps->shape_get_type(shape);
851 if (type == PhysicsServer2D::SHAPE_CONVEX_POLYGON) {
852 rs->canvas_item_add_polygon(p_canvas_item, ps->shape_get_data(shape), color);
853 } else {
854 WARN_PRINT("Wrong shape type for a tile, should be SHAPE_CONVEX_POLYGON.");
855 }
856 }
857 rs->canvas_item_add_set_transform(p_canvas_item, Transform2D());
858 }
859 }
860};
861#endif // DEBUG_ENABLED
862
863/////////////////////////////// Navigation //////////////////////////////////////
864
865void TileMapLayer::_navigation_update() {
866 ERR_FAIL_NULL(NavigationServer2D::get_singleton());
867 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
868 NavigationServer2D *ns = NavigationServer2D::get_singleton();
869
870 // Check if we should cleanup everything.
871 bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree();
872
873 // ----------- Layer level processing -----------
874 if (forced_cleanup) {
875 if (navigation_map.is_valid() && !uses_world_navigation_map) {
876 ns->free(navigation_map);
877 navigation_map = RID();
878 }
879 } else {
880 // Update navigation maps.
881 if (!navigation_map.is_valid()) {
882 if (layer_index_in_tile_map_node == 0) {
883 // Use the default World2D navigation map for the first layer when empty.
884 navigation_map = tile_map_node->get_world_2d()->get_navigation_map();
885 uses_world_navigation_map = true;
886 } else {
887 RID new_layer_map = ns->map_create();
888 // Set the default NavigationPolygon cell_size on the new map as a mismatch causes an error.
889 ns->map_set_cell_size(new_layer_map, 1.0);
890 ns->map_set_active(new_layer_map, true);
891 navigation_map = new_layer_map;
892 uses_world_navigation_map = false;
893 }
894 }
895 }
896
897 // ----------- Navigation regions processing -----------
898 if (forced_cleanup) {
899 // Clean everything.
900 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
901 _navigation_clear_cell(kv.value);
902 }
903 } else {
904 if (_navigation_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) {
905 // Update all cells.
906 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
907 _navigation_update_cell(kv.value);
908 }
909 } else {
910 // Update dirty cells.
911 for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) {
912 CellData &cell_data = *cell_data_list_element->self();
913 _navigation_update_cell(cell_data);
914 }
915 }
916
917 if (dirty.flags[DIRTY_FLAGS_TILE_MAP_XFORM]) {
918 Transform2D tilemap_xform = tile_map_node->get_global_transform();
919 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
920 const CellData &cell_data = kv.value;
921 // Update navigation regions transform.
922 for (const RID &region : cell_data.navigation_regions) {
923 if (!region.is_valid()) {
924 continue;
925 }
926 Transform2D tile_transform;
927 tile_transform.set_origin(tile_map_node->map_to_local(kv.key));
928 NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform);
929 }
930 }
931 }
932 }
933
934 // -----------
935 // Mark the navigation state as up to date.
936 _navigation_was_cleaned_up = forced_cleanup;
937}
938
939void TileMapLayer::_navigation_clear_cell(CellData &r_cell_data) {
940 NavigationServer2D *ns = NavigationServer2D::get_singleton();
941 // Clear navigation shapes.
942 for (unsigned int i = 0; i < r_cell_data.navigation_regions.size(); i++) {
943 const RID &region = r_cell_data.navigation_regions[i];
944 if (region.is_valid()) {
945 ns->region_set_map(region, RID());
946 ns->free(region);
947 }
948 }
949 r_cell_data.navigation_regions.clear();
950}
951
952void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) {
953 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
954 NavigationServer2D *ns = NavigationServer2D::get_singleton();
955 Transform2D tilemap_xform = tile_map_node->get_global_transform();
956
957 // Get the navigation polygons and create regions.
958 TileMapCell &c = r_cell_data.cell;
959
960 TileSetSource *source;
961 if (tile_set->has_source(c.source_id)) {
962 source = *tile_set->get_source(c.source_id);
963
964 if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
965 TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
966 if (atlas_source) {
967 const TileData *tile_data;
968 if (r_cell_data.runtime_tile_data_cache) {
969 tile_data = r_cell_data.runtime_tile_data_cache;
970 } else {
971 tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
972 }
973
974 // Free unused regions then resize the regions array.
975 for (unsigned int i = tile_set->get_navigation_layers_count(); i < r_cell_data.navigation_regions.size(); i++) {
976 RID &region = r_cell_data.navigation_regions[i];
977 if (region.is_valid()) {
978 ns->region_set_map(region, RID());
979 ns->free(region);
980 region = RID();
981 }
982 }
983 r_cell_data.navigation_regions.resize(tile_set->get_navigation_layers_count());
984
985 // Create, update or clear regions.
986 for (unsigned int navigation_layer_index = 0; navigation_layer_index < r_cell_data.navigation_regions.size(); navigation_layer_index++) {
987 Ref<NavigationPolygon> navigation_polygon;
988 navigation_polygon = tile_data->get_navigation_polygon(navigation_layer_index);
989 navigation_polygon = tile_map_node->get_transformed_polygon(Ref<Resource>(navigation_polygon), c.alternative_tile);
990
991 RID &region = r_cell_data.navigation_regions[navigation_layer_index];
992
993 if (navigation_polygon.is_valid() && (navigation_polygon->get_polygon_count() > 0 || navigation_polygon->get_outline_count() > 0)) {
994 // Create or update regions.
995 Transform2D tile_transform;
996 tile_transform.set_origin(tile_map_node->map_to_local(r_cell_data.coords));
997 if (!region.is_valid()) {
998 region = ns->region_create();
999 }
1000 ns->region_set_owner_id(region, tile_map_node->get_instance_id());
1001 ns->region_set_map(region, navigation_map);
1002 ns->region_set_transform(region, tilemap_xform * tile_transform);
1003 ns->region_set_navigation_layers(region, tile_set->get_navigation_layer_layers(navigation_layer_index));
1004 ns->region_set_navigation_polygon(region, navigation_polygon);
1005 } else {
1006 // Clear region.
1007 if (region.is_valid()) {
1008 ns->region_set_map(region, RID());
1009 ns->free(region);
1010 region = RID();
1011 }
1012 }
1013 }
1014
1015 return;
1016 }
1017 }
1018 }
1019
1020 // If we did not return earlier, clear the cell.
1021 _navigation_clear_cell(r_cell_data);
1022}
1023
1024#ifdef DEBUG_ENABLED
1025void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data) {
1026 // Draw the debug collision shapes.
1027 bool show_navigation = false;
1028 switch (tile_map_node->get_navigation_visibility_mode()) {
1029 case TileMap::VISIBILITY_MODE_DEFAULT:
1030 show_navigation = !Engine::get_singleton()->is_editor_hint() && tile_map_node->get_tree()->is_debugging_navigation_hint();
1031 break;
1032 case TileMap::VISIBILITY_MODE_FORCE_HIDE:
1033 show_navigation = false;
1034 break;
1035 case TileMap::VISIBILITY_MODE_FORCE_SHOW:
1036 show_navigation = true;
1037 break;
1038 }
1039 if (!show_navigation) {
1040 return;
1041 }
1042
1043 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1044
1045 RenderingServer *rs = RenderingServer::get_singleton();
1046 const NavigationServer2D *ns2d = NavigationServer2D::get_singleton();
1047
1048 bool enabled_geometry_face_random_color = ns2d->get_debug_navigation_enable_geometry_face_random_color();
1049 bool enabled_edge_lines = ns2d->get_debug_navigation_enable_edge_lines();
1050
1051 Color debug_face_color = ns2d->get_debug_navigation_geometry_face_color();
1052 Color debug_edge_color = ns2d->get_debug_navigation_geometry_edge_color();
1053
1054 RandomPCG rand;
1055
1056 const TileMapCell &c = r_cell_data.cell;
1057
1058 TileSetSource *source;
1059 if (tile_set->has_source(c.source_id)) {
1060 source = *tile_set->get_source(c.source_id);
1061
1062 if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
1063 TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
1064 if (atlas_source) {
1065 const TileData *tile_data;
1066 if (r_cell_data.runtime_tile_data_cache) {
1067 tile_data = r_cell_data.runtime_tile_data_cache;
1068 } else {
1069 tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
1070 }
1071
1072 Transform2D cell_to_quadrant;
1073 cell_to_quadrant.set_origin(tile_map_node->map_to_local(r_cell_data.coords) - p_quadrant_pos);
1074 rs->canvas_item_add_set_transform(p_canvas_item, cell_to_quadrant);
1075
1076 for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
1077 Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(layer_index);
1078 if (navigation_polygon.is_valid()) {
1079 navigation_polygon = tile_map_node->get_transformed_polygon(Ref<Resource>(navigation_polygon), c.alternative_tile);
1080 Vector<Vector2> navigation_polygon_vertices = navigation_polygon->get_vertices();
1081 if (navigation_polygon_vertices.size() < 3) {
1082 continue;
1083 }
1084
1085 for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) {
1086 // An array of vertices for this polygon.
1087 Vector<int> polygon = navigation_polygon->get_polygon(i);
1088 Vector<Vector2> debug_polygon_vertices;
1089 debug_polygon_vertices.resize(polygon.size());
1090 for (int j = 0; j < polygon.size(); j++) {
1091 ERR_FAIL_INDEX(polygon[j], navigation_polygon_vertices.size());
1092 debug_polygon_vertices.write[j] = navigation_polygon_vertices[polygon[j]];
1093 }
1094
1095 // Generate the polygon color, slightly randomly modified from the settings one.
1096 Color random_variation_color = debug_face_color;
1097 if (enabled_geometry_face_random_color) {
1098 random_variation_color.set_hsv(
1099 debug_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1,
1100 debug_face_color.get_s(),
1101 debug_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2);
1102 }
1103 random_variation_color.a = debug_face_color.a;
1104
1105 Vector<Color> debug_face_colors;
1106 debug_face_colors.push_back(random_variation_color);
1107 rs->canvas_item_add_polygon(p_canvas_item, debug_polygon_vertices, debug_face_colors);
1108
1109 if (enabled_edge_lines) {
1110 Vector<Color> debug_edge_colors;
1111 debug_edge_colors.push_back(debug_edge_color);
1112 debug_polygon_vertices.push_back(debug_polygon_vertices[0]); // Add first again for closing polyline.
1113 rs->canvas_item_add_polyline(p_canvas_item, debug_polygon_vertices, debug_edge_colors);
1114 }
1115 }
1116 }
1117 }
1118 }
1119 }
1120 }
1121}
1122#endif // DEBUG_ENABLED
1123
1124/////////////////////////////// Scenes //////////////////////////////////////
1125
1126void TileMapLayer::_scenes_update() {
1127 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1128
1129 // Check if we should cleanup everything.
1130 bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree();
1131
1132 if (forced_cleanup) {
1133 // Clean everything.
1134 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
1135 _scenes_clear_cell(kv.value);
1136 }
1137 } else {
1138 if (_scenes_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) {
1139 // Update all cells.
1140 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
1141 _scenes_update_cell(kv.value);
1142 }
1143 } else {
1144 // Update dirty cells.
1145 for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) {
1146 CellData &cell_data = *cell_data_list_element->self();
1147 _scenes_update_cell(cell_data);
1148 }
1149 }
1150 }
1151
1152 // -----------
1153 // Mark the scenes state as up to date.
1154 _scenes_was_cleaned_up = forced_cleanup;
1155}
1156
1157void TileMapLayer::_scenes_clear_cell(CellData &r_cell_data) {
1158 // Cleanup existing scene.
1159 Node *node = tile_map_node->get_node_or_null(r_cell_data.scene);
1160 if (node) {
1161 node->queue_free();
1162 }
1163 r_cell_data.scene = "";
1164}
1165
1166void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) {
1167 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1168
1169 // Clear the scene in any case.
1170 _scenes_clear_cell(r_cell_data);
1171
1172 // Create the scene.
1173 const TileMapCell &c = r_cell_data.cell;
1174
1175 TileSetSource *source;
1176 if (tile_set->has_source(c.source_id)) {
1177 source = *tile_set->get_source(c.source_id);
1178
1179 if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
1180 TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
1181 if (scenes_collection_source) {
1182 Ref<PackedScene> packed_scene = scenes_collection_source->get_scene_tile_scene(c.alternative_tile);
1183 if (packed_scene.is_valid()) {
1184 Node *scene = packed_scene->instantiate();
1185 Control *scene_as_control = Object::cast_to<Control>(scene);
1186 Node2D *scene_as_node2d = Object::cast_to<Node2D>(scene);
1187 if (scene_as_control) {
1188 scene_as_control->set_position(tile_map_node->map_to_local(r_cell_data.coords) + scene_as_control->get_position());
1189 } else if (scene_as_node2d) {
1190 Transform2D xform;
1191 xform.set_origin(tile_map_node->map_to_local(r_cell_data.coords));
1192 scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform());
1193 }
1194 tile_map_node->add_child(scene);
1195 r_cell_data.scene = scene->get_name();
1196 }
1197 }
1198 }
1199 }
1200}
1201
1202#ifdef DEBUG_ENABLED
1203void TileMapLayer::_scenes_draw_cell_debug(const RID &p_canvas_item, const Vector2i &p_quadrant_pos, const CellData &r_cell_data) {
1204 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1205 ERR_FAIL_COND(!tile_set.is_valid());
1206
1207 if (!Engine::get_singleton()->is_editor_hint()) {
1208 return;
1209 }
1210
1211 // Draw a placeholder for scenes needing one.
1212 RenderingServer *rs = RenderingServer::get_singleton();
1213
1214 const TileMapCell &c = r_cell_data.cell;
1215
1216 TileSetSource *source;
1217 if (tile_set->has_source(c.source_id)) {
1218 source = *tile_set->get_source(c.source_id);
1219
1220 if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
1221 return;
1222 }
1223
1224 TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
1225 if (scenes_collection_source) {
1226 if (!scenes_collection_source->get_scene_tile_scene(c.alternative_tile).is_valid() || scenes_collection_source->get_scene_tile_display_placeholder(c.alternative_tile)) {
1227 // Generate a random color from the hashed values of the tiles.
1228 Array to_hash;
1229 to_hash.push_back(c.source_id);
1230 to_hash.push_back(c.alternative_tile);
1231 uint32_t hash = RandomPCG(to_hash.hash()).rand();
1232
1233 Color color;
1234 color = color.from_hsv(
1235 (float)((hash >> 24) & 0xFF) / 256.0,
1236 Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0),
1237 Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0),
1238 0.8);
1239
1240 // Draw a placeholder tile.
1241 Transform2D cell_to_quadrant;
1242 cell_to_quadrant.set_origin(tile_map_node->map_to_local(r_cell_data.coords) - p_quadrant_pos);
1243 rs->canvas_item_add_set_transform(p_canvas_item, cell_to_quadrant);
1244 rs->canvas_item_add_circle(p_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
1245 }
1246 }
1247 }
1248}
1249#endif // DEBUG_ENABLED
1250
1251/////////////////////////////////////////////////////////////////////
1252
1253void TileMapLayer::_build_runtime_update_tile_data() {
1254 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1255
1256 // Check if we should cleanup everything.
1257 bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree();
1258 if (!forced_cleanup) {
1259 if (tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update)) {
1260 if (_runtime_update_tile_data_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) {
1261 for (KeyValue<Vector2i, CellData> &E : tile_map) {
1262 _build_runtime_update_tile_data_for_cell(E.value);
1263 }
1264 } else if (dirty.flags[DIRTY_FLAGS_TILE_MAP_RUNTIME_UPDATE]) {
1265 for (KeyValue<Vector2i, CellData> &E : tile_map) {
1266 _build_runtime_update_tile_data_for_cell(E.value, true);
1267 }
1268 } else {
1269 for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) {
1270 CellData &cell_data = *cell_data_list_element->self();
1271 _build_runtime_update_tile_data_for_cell(cell_data);
1272 }
1273 }
1274 }
1275 }
1276
1277 // -----------
1278 // Mark the navigation state as up to date.
1279 _runtime_update_tile_data_was_cleaned_up = forced_cleanup;
1280}
1281
1282void TileMapLayer::_build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_auto_add_to_dirty_list) {
1283 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1284
1285 TileMapCell &c = r_cell_data.cell;
1286 TileSetSource *source;
1287 if (tile_set->has_source(c.source_id)) {
1288 source = *tile_set->get_source(c.source_id);
1289
1290 if (source->has_tile(c.get_atlas_coords()) && source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
1291 TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
1292 if (atlas_source) {
1293 bool ret = false;
1294 if (tile_map_node->GDVIRTUAL_CALL(_use_tile_data_runtime_update, layer_index_in_tile_map_node, r_cell_data.coords, ret) && ret) {
1295 TileData *tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
1296
1297 // Create the runtime TileData.
1298 TileData *tile_data_runtime_use = tile_data->duplicate();
1299 tile_data_runtime_use->set_allow_transform(true);
1300 r_cell_data.runtime_tile_data_cache = tile_data_runtime_use;
1301
1302 tile_map_node->GDVIRTUAL_CALL(_tile_data_runtime_update, layer_index_in_tile_map_node, r_cell_data.coords, tile_data_runtime_use);
1303
1304 if (p_auto_add_to_dirty_list) {
1305 dirty.cell_list.add(&r_cell_data.dirty_list_element);
1306 }
1307 }
1308 }
1309 }
1310 }
1311}
1312
1313void TileMapLayer::_clear_runtime_update_tile_data() {
1314 for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) {
1315 CellData &cell_data = *cell_data_list_element->self();
1316
1317 // Clear the runtime tile data.
1318 if (cell_data.runtime_tile_data_cache) {
1319 memdelete(cell_data.runtime_tile_data_cache);
1320 cell_data.runtime_tile_data_cache = nullptr;
1321 }
1322 }
1323}
1324
1325TileSet::TerrainsPattern TileMapLayer::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet<TerrainConstraint> &p_constraints, TileSet::TerrainsPattern p_current_pattern) {
1326 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1327 if (!tile_set.is_valid()) {
1328 return TileSet::TerrainsPattern();
1329 }
1330 // Returns all tiles compatible with the given constraints.
1331 RBMap<TileSet::TerrainsPattern, int> terrain_pattern_score;
1332 RBSet<TileSet::TerrainsPattern> pattern_set = tile_set->get_terrains_pattern_set(p_terrain_set);
1333 ERR_FAIL_COND_V(pattern_set.is_empty(), TileSet::TerrainsPattern());
1334 for (TileSet::TerrainsPattern &terrain_pattern : pattern_set) {
1335 int score = 0;
1336
1337 // Check the center bit constraint.
1338 TerrainConstraint terrain_constraint = TerrainConstraint(tile_map_node, p_position, terrain_pattern.get_terrain());
1339 const RBSet<TerrainConstraint>::Element *in_set_constraint_element = p_constraints.find(terrain_constraint);
1340 if (in_set_constraint_element) {
1341 if (in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) {
1342 score += in_set_constraint_element->get().get_priority();
1343 }
1344 } else if (p_current_pattern.get_terrain() != terrain_pattern.get_terrain()) {
1345 continue; // Ignore a pattern that cannot keep bits without constraints unmodified.
1346 }
1347
1348 // Check the surrounding bits
1349 bool invalid_pattern = false;
1350 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
1351 TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
1352 if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
1353 // Check if the bit is compatible with the constraints.
1354 TerrainConstraint terrain_bit_constraint = TerrainConstraint(tile_map_node, p_position, bit, terrain_pattern.get_terrain_peering_bit(bit));
1355 in_set_constraint_element = p_constraints.find(terrain_bit_constraint);
1356 if (in_set_constraint_element) {
1357 if (in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) {
1358 score += in_set_constraint_element->get().get_priority();
1359 }
1360 } else if (p_current_pattern.get_terrain_peering_bit(bit) != terrain_pattern.get_terrain_peering_bit(bit)) {
1361 invalid_pattern = true; // Ignore a pattern that cannot keep bits without constraints unmodified.
1362 break;
1363 }
1364 }
1365 }
1366 if (invalid_pattern) {
1367 continue;
1368 }
1369
1370 terrain_pattern_score[terrain_pattern] = score;
1371 }
1372
1373 // Compute the minimum score.
1374 TileSet::TerrainsPattern min_score_pattern = p_current_pattern;
1375 int min_score = INT32_MAX;
1376 for (KeyValue<TileSet::TerrainsPattern, int> E : terrain_pattern_score) {
1377 if (E.value < min_score) {
1378 min_score_pattern = E.key;
1379 min_score = E.value;
1380 }
1381 }
1382
1383 return min_score_pattern;
1384}
1385
1386RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const {
1387 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1388 if (!tile_set.is_valid()) {
1389 return RBSet<TerrainConstraint>();
1390 }
1391
1392 // Compute the constraints needed from the surrounding tiles.
1393 RBSet<TerrainConstraint> output;
1394 output.insert(TerrainConstraint(tile_map_node, p_position, p_terrains_pattern.get_terrain()));
1395
1396 for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
1397 TileSet::CellNeighbor side = TileSet::CellNeighbor(i);
1398 if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, side)) {
1399 TerrainConstraint c = TerrainConstraint(tile_map_node, p_position, side, p_terrains_pattern.get_terrain_peering_bit(side));
1400 output.insert(c);
1401 }
1402 }
1403
1404 return output;
1405}
1406
1407RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_painted_cells_list(const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const {
1408 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1409 if (!tile_set.is_valid()) {
1410 return RBSet<TerrainConstraint>();
1411 }
1412
1413 ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), RBSet<TerrainConstraint>());
1414
1415 // Build a set of dummy constraints to get the constrained points.
1416 RBSet<TerrainConstraint> dummy_constraints;
1417 for (const Vector2i &E : p_painted) {
1418 for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over neighbor bits.
1419 TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
1420 if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
1421 dummy_constraints.insert(TerrainConstraint(tile_map_node, E, bit, -1));
1422 }
1423 }
1424 }
1425
1426 // For each constrained point, we get all overlapping tiles, and select the most adequate terrain for it.
1427 RBSet<TerrainConstraint> constraints;
1428 for (const TerrainConstraint &E_constraint : dummy_constraints) {
1429 HashMap<int, int> terrain_count;
1430
1431 // Count the number of occurrences per terrain.
1432 HashMap<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = E_constraint.get_overlapping_coords_and_peering_bits();
1433 for (const KeyValue<Vector2i, TileSet::CellNeighbor> &E_overlapping : overlapping_terrain_bits) {
1434 TileData *neighbor_tile_data = nullptr;
1435 TileMapCell neighbor_cell = get_cell(E_overlapping.key);
1436 if (neighbor_cell.source_id != TileSet::INVALID_SOURCE) {
1437 Ref<TileSetSource> source = tile_set->get_source(neighbor_cell.source_id);
1438 Ref<TileSetAtlasSource> atlas_source = source;
1439 if (atlas_source.is_valid()) {
1440 TileData *tile_data = atlas_source->get_tile_data(neighbor_cell.get_atlas_coords(), neighbor_cell.alternative_tile);
1441 if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
1442 neighbor_tile_data = tile_data;
1443 }
1444 }
1445 }
1446
1447 int terrain = neighbor_tile_data ? neighbor_tile_data->get_terrain_peering_bit(TileSet::CellNeighbor(E_overlapping.value)) : -1;
1448 if (!p_ignore_empty_terrains || terrain >= 0) {
1449 if (!terrain_count.has(terrain)) {
1450 terrain_count[terrain] = 0;
1451 }
1452 terrain_count[terrain] += 1;
1453 }
1454 }
1455
1456 // Get the terrain with the max number of occurrences.
1457 int max = 0;
1458 int max_terrain = -1;
1459 for (const KeyValue<int, int> &E_terrain_count : terrain_count) {
1460 if (E_terrain_count.value > max) {
1461 max = E_terrain_count.value;
1462 max_terrain = E_terrain_count.key;
1463 }
1464 }
1465
1466 // Set the adequate terrain.
1467 if (max > 0) {
1468 TerrainConstraint c = E_constraint;
1469 c.set_terrain(max_terrain);
1470 constraints.insert(c);
1471 }
1472 }
1473
1474 // Add the centers as constraints.
1475 for (Vector2i E_coords : p_painted) {
1476 TileData *tile_data = nullptr;
1477 TileMapCell cell = get_cell(E_coords);
1478 if (cell.source_id != TileSet::INVALID_SOURCE) {
1479 Ref<TileSetSource> source = tile_set->get_source(cell.source_id);
1480 Ref<TileSetAtlasSource> atlas_source = source;
1481 if (atlas_source.is_valid()) {
1482 tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
1483 }
1484 }
1485
1486 int terrain = (tile_data && tile_data->get_terrain_set() == p_terrain_set) ? tile_data->get_terrain() : -1;
1487 if (!p_ignore_empty_terrains || terrain >= 0) {
1488 constraints.insert(TerrainConstraint(tile_map_node, E_coords, terrain));
1489 }
1490 }
1491
1492 return constraints;
1493}
1494
1495void TileMapLayer::set_tile_map(TileMap *p_tile_map) {
1496 tile_map_node = p_tile_map;
1497}
1498
1499void TileMapLayer::set_layer_index_in_tile_map_node(int p_index) {
1500 if (p_index == layer_index_in_tile_map_node) {
1501 return;
1502 }
1503 layer_index_in_tile_map_node = p_index;
1504 dirty.flags[DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE] = true;
1505 tile_map_node->queue_internal_update();
1506}
1507
1508Rect2 TileMapLayer::get_rect(bool &r_changed) const {
1509 // Compute the displayed area of the tilemap.
1510 r_changed = false;
1511#ifdef DEBUG_ENABLED
1512
1513 if (rect_cache_dirty) {
1514 Rect2 r_total;
1515 bool first = true;
1516 for (const KeyValue<Vector2i, CellData> &E : tile_map) {
1517 Rect2 r;
1518 r.position = tile_map_node->map_to_local(E.key);
1519 r.size = Size2();
1520 if (first) {
1521 r_total = r;
1522 first = false;
1523 } else {
1524 r_total = r_total.merge(r);
1525 }
1526 }
1527
1528 r_changed = rect_cache != r_total;
1529
1530 rect_cache = r_total;
1531 rect_cache_dirty = false;
1532 }
1533#endif
1534 return rect_cache;
1535}
1536
1537HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints) {
1538 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1539 if (!tile_set.is_valid()) {
1540 return HashMap<Vector2i, TileSet::TerrainsPattern>();
1541 }
1542
1543 // Copy the constraints set.
1544 RBSet<TerrainConstraint> constraints = p_constraints;
1545
1546 // Output map.
1547 HashMap<Vector2i, TileSet::TerrainsPattern> output;
1548
1549 // Add all positions to a set.
1550 for (int i = 0; i < p_to_replace.size(); i++) {
1551 const Vector2i &coords = p_to_replace[i];
1552
1553 // Select the best pattern for the given constraints.
1554 TileSet::TerrainsPattern current_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
1555 TileMapCell cell = get_cell(coords);
1556 if (cell.source_id != TileSet::INVALID_SOURCE) {
1557 TileSetSource *source = *tile_set->get_source(cell.source_id);
1558 TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
1559 if (atlas_source) {
1560 // Get tile data.
1561 TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
1562 if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
1563 current_pattern = tile_data->get_terrains_pattern();
1564 }
1565 }
1566 }
1567 TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints, current_pattern);
1568
1569 // Update the constraint set with the new ones.
1570 RBSet<TerrainConstraint> new_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, pattern);
1571 for (const TerrainConstraint &E_constraint : new_constraints) {
1572 if (constraints.has(E_constraint)) {
1573 constraints.erase(E_constraint);
1574 }
1575 TerrainConstraint c = E_constraint;
1576 c.set_priority(5);
1577 constraints.insert(c);
1578 }
1579
1580 output[coords] = pattern;
1581 }
1582 return output;
1583}
1584
1585HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_connect(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
1586 HashMap<Vector2i, TileSet::TerrainsPattern> output;
1587 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1588 ERR_FAIL_COND_V(!tile_set.is_valid(), output);
1589 ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output);
1590
1591 // Build list and set of tiles that can be modified (painted and their surroundings).
1592 Vector<Vector2i> can_modify_list;
1593 RBSet<Vector2i> can_modify_set;
1594 RBSet<Vector2i> painted_set;
1595 for (int i = p_coords_array.size() - 1; i >= 0; i--) {
1596 const Vector2i &coords = p_coords_array[i];
1597 can_modify_list.push_back(coords);
1598 can_modify_set.insert(coords);
1599 painted_set.insert(coords);
1600 }
1601 for (Vector2i coords : p_coords_array) {
1602 // Find the adequate neighbor.
1603 for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
1604 TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
1605 if (tile_map_node->is_existing_neighbor(bit)) {
1606 Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit);
1607 if (!can_modify_set.has(neighbor)) {
1608 can_modify_list.push_back(neighbor);
1609 can_modify_set.insert(neighbor);
1610 }
1611 }
1612 }
1613 }
1614
1615 // Build a set, out of the possibly modified tiles, of the one with a center bit that is set (or will be) to the painted terrain.
1616 RBSet<Vector2i> cells_with_terrain_center_bit;
1617 for (Vector2i coords : can_modify_set) {
1618 bool connect = false;
1619 if (painted_set.has(coords)) {
1620 connect = true;
1621 } else {
1622 // Get the center bit of the cell.
1623 TileData *tile_data = nullptr;
1624 TileMapCell cell = get_cell(coords);
1625 if (cell.source_id != TileSet::INVALID_SOURCE) {
1626 Ref<TileSetSource> source = tile_set->get_source(cell.source_id);
1627 Ref<TileSetAtlasSource> atlas_source = source;
1628 if (atlas_source.is_valid()) {
1629 tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
1630 }
1631 }
1632
1633 if (tile_data && tile_data->get_terrain_set() == p_terrain_set && tile_data->get_terrain() == p_terrain) {
1634 connect = true;
1635 }
1636 }
1637 if (connect) {
1638 cells_with_terrain_center_bit.insert(coords);
1639 }
1640 }
1641
1642 RBSet<TerrainConstraint> constraints;
1643
1644 // Add new constraints from the path drawn.
1645 for (Vector2i coords : p_coords_array) {
1646 // Constraints on the center bit.
1647 TerrainConstraint c = TerrainConstraint(tile_map_node, coords, p_terrain);
1648 c.set_priority(10);
1649 constraints.insert(c);
1650
1651 // Constraints on the connecting bits.
1652 for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
1653 TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
1654 if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
1655 c = TerrainConstraint(tile_map_node, coords, bit, p_terrain);
1656 c.set_priority(10);
1657 if ((int(bit) % 2) == 0) {
1658 // Side peering bits: add the constraint if the center is of the same terrain.
1659 Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit);
1660 if (cells_with_terrain_center_bit.has(neighbor)) {
1661 constraints.insert(c);
1662 }
1663 } else {
1664 // Corner peering bits: add the constraint if all tiles on the constraint has the same center bit.
1665 HashMap<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = c.get_overlapping_coords_and_peering_bits();
1666 bool valid = true;
1667 for (KeyValue<Vector2i, TileSet::CellNeighbor> kv : overlapping_terrain_bits) {
1668 if (!cells_with_terrain_center_bit.has(kv.key)) {
1669 valid = false;
1670 break;
1671 }
1672 }
1673 if (valid) {
1674 constraints.insert(c);
1675 }
1676 }
1677 }
1678 }
1679 }
1680
1681 // Fills in the constraint list from existing tiles.
1682 for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(painted_set, p_terrain_set, p_ignore_empty_terrains)) {
1683 constraints.insert(c);
1684 }
1685
1686 // Fill the terrains.
1687 output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
1688 return output;
1689}
1690
1691HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_path(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
1692 HashMap<Vector2i, TileSet::TerrainsPattern> output;
1693 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1694 ERR_FAIL_COND_V(!tile_set.is_valid(), output);
1695 ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output);
1696
1697 // Make sure the path is correct and build the peering bit list while doing it.
1698 Vector<TileSet::CellNeighbor> neighbor_list;
1699 for (int i = 0; i < p_coords_array.size() - 1; i++) {
1700 // Find the adequate neighbor.
1701 TileSet::CellNeighbor found_bit = TileSet::CELL_NEIGHBOR_MAX;
1702 for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
1703 TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
1704 if (tile_map_node->is_existing_neighbor(bit)) {
1705 if (tile_map_node->get_neighbor_cell(p_coords_array[i], bit) == p_coords_array[i + 1]) {
1706 found_bit = bit;
1707 break;
1708 }
1709 }
1710 }
1711 ERR_FAIL_COND_V_MSG(found_bit == TileSet::CELL_NEIGHBOR_MAX, output, vformat("Invalid terrain path, %s is not a neighboring tile of %s", p_coords_array[i + 1], p_coords_array[i]));
1712 neighbor_list.push_back(found_bit);
1713 }
1714
1715 // Build list and set of tiles that can be modified (painted and their surroundings).
1716 Vector<Vector2i> can_modify_list;
1717 RBSet<Vector2i> can_modify_set;
1718 RBSet<Vector2i> painted_set;
1719 for (int i = p_coords_array.size() - 1; i >= 0; i--) {
1720 const Vector2i &coords = p_coords_array[i];
1721 can_modify_list.push_back(coords);
1722 can_modify_set.insert(coords);
1723 painted_set.insert(coords);
1724 }
1725 for (Vector2i coords : p_coords_array) {
1726 // Find the adequate neighbor.
1727 for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
1728 TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
1729 if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
1730 Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit);
1731 if (!can_modify_set.has(neighbor)) {
1732 can_modify_list.push_back(neighbor);
1733 can_modify_set.insert(neighbor);
1734 }
1735 }
1736 }
1737 }
1738
1739 RBSet<TerrainConstraint> constraints;
1740
1741 // Add new constraints from the path drawn.
1742 for (Vector2i coords : p_coords_array) {
1743 // Constraints on the center bit.
1744 TerrainConstraint c = TerrainConstraint(tile_map_node, coords, p_terrain);
1745 c.set_priority(10);
1746 constraints.insert(c);
1747 }
1748 for (int i = 0; i < p_coords_array.size() - 1; i++) {
1749 // Constraints on the peering bits.
1750 TerrainConstraint c = TerrainConstraint(tile_map_node, p_coords_array[i], neighbor_list[i], p_terrain);
1751 c.set_priority(10);
1752 constraints.insert(c);
1753 }
1754
1755 // Fills in the constraint list from existing tiles.
1756 for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(painted_set, p_terrain_set, p_ignore_empty_terrains)) {
1757 constraints.insert(c);
1758 }
1759
1760 // Fill the terrains.
1761 output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
1762 return output;
1763}
1764
1765HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_pattern(const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains) {
1766 HashMap<Vector2i, TileSet::TerrainsPattern> output;
1767 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1768 ERR_FAIL_COND_V(!tile_set.is_valid(), output);
1769 ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output);
1770
1771 // Build list and set of tiles that can be modified (painted and their surroundings).
1772 Vector<Vector2i> can_modify_list;
1773 RBSet<Vector2i> can_modify_set;
1774 RBSet<Vector2i> painted_set;
1775 for (int i = p_coords_array.size() - 1; i >= 0; i--) {
1776 const Vector2i &coords = p_coords_array[i];
1777 can_modify_list.push_back(coords);
1778 can_modify_set.insert(coords);
1779 painted_set.insert(coords);
1780 }
1781 for (Vector2i coords : p_coords_array) {
1782 // Find the adequate neighbor.
1783 for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
1784 TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
1785 if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
1786 Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit);
1787 if (!can_modify_set.has(neighbor)) {
1788 can_modify_list.push_back(neighbor);
1789 can_modify_set.insert(neighbor);
1790 }
1791 }
1792 }
1793 }
1794
1795 // Add constraint by the new ones.
1796 RBSet<TerrainConstraint> constraints;
1797
1798 // Add new constraints from the path drawn.
1799 for (Vector2i coords : p_coords_array) {
1800 // Constraints on the center bit.
1801 RBSet<TerrainConstraint> added_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, p_terrains_pattern);
1802 for (TerrainConstraint c : added_constraints) {
1803 c.set_priority(10);
1804 constraints.insert(c);
1805 }
1806 }
1807
1808 // Fills in the constraint list from modified tiles border.
1809 for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(painted_set, p_terrain_set, p_ignore_empty_terrains)) {
1810 constraints.insert(c);
1811 }
1812
1813 // Fill the terrains.
1814 output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
1815 return output;
1816}
1817
1818TileMapCell TileMapLayer::get_cell(const Vector2i &p_coords, bool p_use_proxies) const {
1819 if (!tile_map.has(p_coords)) {
1820 return TileMapCell();
1821 } else {
1822 TileMapCell c = tile_map.find(p_coords)->value.cell;
1823 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1824 if (p_use_proxies && tile_set.is_valid()) {
1825 Array proxyed = tile_set->map_tile_proxy(c.source_id, c.get_atlas_coords(), c.alternative_tile);
1826 c.source_id = proxyed[0];
1827 c.set_atlas_coords(proxyed[1]);
1828 c.alternative_tile = proxyed[2];
1829 }
1830 return c;
1831 }
1832}
1833
1834int TileMapLayer::get_effective_quadrant_size() const {
1835 // When using YSort, the quadrant size is reduced to 1 to have one CanvasItem per quadrant.
1836 if (tile_map_node->is_y_sort_enabled() && is_y_sort_enabled()) {
1837 return 1;
1838 } else {
1839 return tile_map_node->get_rendering_quadrant_size();
1840 }
1841}
1842
1843void TileMapLayer::set_tile_data(TileMapLayer::DataFormat p_format, const Vector<int> &p_data) {
1844 ERR_FAIL_COND(p_format > TileMapLayer::FORMAT_3);
1845
1846 // Set data for a given tile from raw data.
1847
1848 int c = p_data.size();
1849 const int *r = p_data.ptr();
1850
1851 int offset = (p_format >= TileMapLayer::FORMAT_2) ? 3 : 2;
1852 ERR_FAIL_COND_MSG(c % offset != 0, vformat("Corrupted tile data. Got size: %s. Expected modulo: %s", offset));
1853
1854 clear();
1855
1856#ifdef DISABLE_DEPRECATED
1857 ERR_FAIL_COND_MSG(p_format != TileMapLayer::FORMAT_3, vformat("Cannot handle deprecated TileMap data format version %d. This Godot version was compiled with no support for deprecated data.", p_format));
1858#endif
1859
1860 for (int i = 0; i < c; i += offset) {
1861 const uint8_t *ptr = (const uint8_t *)&r[i];
1862 uint8_t local[12];
1863 for (int j = 0; j < ((p_format >= TileMapLayer::FORMAT_2) ? 12 : 8); j++) {
1864 local[j] = ptr[j];
1865 }
1866
1867#ifdef BIG_ENDIAN_ENABLED
1868
1869 SWAP(local[0], local[3]);
1870 SWAP(local[1], local[2]);
1871 SWAP(local[4], local[7]);
1872 SWAP(local[5], local[6]);
1873 //TODO: ask someone to check this...
1874 if (FORMAT >= FORMAT_2) {
1875 SWAP(local[8], local[11]);
1876 SWAP(local[9], local[10]);
1877 }
1878#endif
1879 // Extracts position in TileMap.
1880 int16_t x = decode_uint16(&local[0]);
1881 int16_t y = decode_uint16(&local[2]);
1882
1883 if (p_format == TileMapLayer::FORMAT_3) {
1884 uint16_t source_id = decode_uint16(&local[4]);
1885 uint16_t atlas_coords_x = decode_uint16(&local[6]);
1886 uint16_t atlas_coords_y = decode_uint16(&local[8]);
1887 uint16_t alternative_tile = decode_uint16(&local[10]);
1888 set_cell(Vector2i(x, y), source_id, Vector2i(atlas_coords_x, atlas_coords_y), alternative_tile);
1889 } else {
1890#ifndef DISABLE_DEPRECATED
1891 // Previous decated format.
1892
1893 uint32_t v = decode_uint32(&local[4]);
1894 // Extract the transform flags that used to be in the tilemap.
1895 bool flip_h = v & (1UL << 29);
1896 bool flip_v = v & (1UL << 30);
1897 bool transpose = v & (1UL << 31);
1898 v &= (1UL << 29) - 1;
1899
1900 // Extract autotile/atlas coords.
1901 int16_t coord_x = 0;
1902 int16_t coord_y = 0;
1903 if (p_format == TileMapLayer::FORMAT_2) {
1904 coord_x = decode_uint16(&local[8]);
1905 coord_y = decode_uint16(&local[10]);
1906 }
1907
1908 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
1909 if (tile_set.is_valid()) {
1910 Array a = tile_set->compatibility_tilemap_map(v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose);
1911 if (a.size() == 3) {
1912 set_cell(Vector2i(x, y), a[0], a[1], a[2]);
1913 } else {
1914 ERR_PRINT(vformat("No valid tile in Tileset for: tile:%s coords:%s flip_h:%s flip_v:%s transpose:%s", v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose));
1915 }
1916 } else {
1917 int compatibility_alternative_tile = ((int)flip_h) + ((int)flip_v << 1) + ((int)transpose << 2);
1918 set_cell(Vector2i(x, y), v, Vector2i(coord_x, coord_y), compatibility_alternative_tile);
1919 }
1920#endif
1921 }
1922 }
1923}
1924
1925Vector<int> TileMapLayer::get_tile_data() const {
1926 // Export tile data to raw format.
1927 Vector<int> tile_data;
1928 tile_data.resize(tile_map.size() * 3);
1929 int *w = tile_data.ptrw();
1930
1931 // Save in highest format.
1932
1933 int idx = 0;
1934 for (const KeyValue<Vector2i, CellData> &E : tile_map) {
1935 uint8_t *ptr = (uint8_t *)&w[idx];
1936 encode_uint16((int16_t)(E.key.x), &ptr[0]);
1937 encode_uint16((int16_t)(E.key.y), &ptr[2]);
1938 encode_uint16(E.value.cell.source_id, &ptr[4]);
1939 encode_uint16(E.value.cell.coord_x, &ptr[6]);
1940 encode_uint16(E.value.cell.coord_y, &ptr[8]);
1941 encode_uint16(E.value.cell.alternative_tile, &ptr[10]);
1942 idx += 3;
1943 }
1944
1945 return tile_data;
1946}
1947
1948void TileMapLayer::notify_tile_map_change(DirtyFlags p_what) {
1949 dirty.flags[p_what] = true;
1950 tile_map_node->queue_internal_update();
1951 _physics_notify_tilemap_change(p_what);
1952}
1953
1954void TileMapLayer::internal_update() {
1955 // Find TileData that need a runtime modification.
1956 // This may add cells to the dirty list is a runtime modification has been notified.
1957 _build_runtime_update_tile_data();
1958
1959 // Update all subsystems.
1960 _rendering_update();
1961 _physics_update();
1962 _navigation_update();
1963 _scenes_update();
1964#ifdef DEBUG_ENABLED
1965 _debug_update();
1966#endif // DEBUG_ENABLED
1967
1968 _clear_runtime_update_tile_data();
1969
1970 // Clear the "what is dirty" flags.
1971 for (int i = 0; i < DIRTY_FLAGS_MAX; i++) {
1972 dirty.flags[i] = false;
1973 }
1974
1975 // List the cells to delete definitely.
1976 Vector<Vector2i> to_delete;
1977 for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) {
1978 CellData &cell_data = *cell_data_list_element->self();
1979 // Select the the cell from tile_map if it is invalid.
1980 if (cell_data.cell.source_id == TileSet::INVALID_SOURCE) {
1981 to_delete.push_back(cell_data.coords);
1982 }
1983 }
1984
1985 // Remove cells that are empty after the cleanup.
1986 for (const Vector2i &coords : to_delete) {
1987 tile_map.erase(coords);
1988 }
1989
1990 // Clear the dirty cells list.
1991 dirty.cell_list.clear();
1992}
1993
1994void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
1995 // Set the current cell tile (using integer position).
1996 Vector2i pk(p_coords);
1997 HashMap<Vector2i, CellData>::Iterator E = tile_map.find(pk);
1998
1999 int source_id = p_source_id;
2000 Vector2i atlas_coords = p_atlas_coords;
2001 int alternative_tile = p_alternative_tile;
2002
2003 if ((source_id == TileSet::INVALID_SOURCE || atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE) &&
2004 (source_id != TileSet::INVALID_SOURCE || atlas_coords != TileSetSource::INVALID_ATLAS_COORDS || alternative_tile != TileSetSource::INVALID_TILE_ALTERNATIVE)) {
2005 source_id = TileSet::INVALID_SOURCE;
2006 atlas_coords = TileSetSource::INVALID_ATLAS_COORDS;
2007 alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
2008 }
2009
2010 if (!E) {
2011 if (source_id == TileSet::INVALID_SOURCE) {
2012 return; // Nothing to do, the tile is already empty.
2013 }
2014
2015 // Insert a new cell in the tile map.
2016 CellData new_cell_data;
2017 new_cell_data.coords = pk;
2018 E = tile_map.insert(pk, new_cell_data);
2019 } else {
2020 if (E->value.cell.source_id == source_id && E->value.cell.get_atlas_coords() == atlas_coords && E->value.cell.alternative_tile == alternative_tile) {
2021 return; // Nothing changed.
2022 }
2023 }
2024
2025 TileMapCell &c = E->value.cell;
2026 c.source_id = source_id;
2027 c.set_atlas_coords(atlas_coords);
2028 c.alternative_tile = alternative_tile;
2029
2030 // Make the given cell dirty.
2031 if (!E->value.dirty_list_element.in_list()) {
2032 dirty.cell_list.add(&(E->value.dirty_list_element));
2033 }
2034 tile_map_node->queue_internal_update();
2035
2036 used_rect_cache_dirty = true;
2037}
2038
2039void TileMapLayer::erase_cell(const Vector2i &p_coords) {
2040 set_cell(p_coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
2041}
2042
2043int TileMapLayer::get_cell_source_id(const Vector2i &p_coords, bool p_use_proxies) const {
2044 // Get a cell source id from position.
2045 HashMap<Vector2i, CellData>::ConstIterator E = tile_map.find(p_coords);
2046
2047 if (!E) {
2048 return TileSet::INVALID_SOURCE;
2049 }
2050
2051 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
2052 if (p_use_proxies && tile_set.is_valid()) {
2053 Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile);
2054 return proxyed[0];
2055 }
2056
2057 return E->value.cell.source_id;
2058}
2059
2060Vector2i TileMapLayer::get_cell_atlas_coords(const Vector2i &p_coords, bool p_use_proxies) const {
2061 // Get a cell source id from position.
2062 HashMap<Vector2i, CellData>::ConstIterator E = tile_map.find(p_coords);
2063
2064 if (!E) {
2065 return TileSetSource::INVALID_ATLAS_COORDS;
2066 }
2067
2068 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
2069 if (p_use_proxies && tile_set.is_valid()) {
2070 Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile);
2071 return proxyed[1];
2072 }
2073
2074 return E->value.cell.get_atlas_coords();
2075}
2076
2077int TileMapLayer::get_cell_alternative_tile(const Vector2i &p_coords, bool p_use_proxies) const {
2078 // Get a cell source id from position.
2079 HashMap<Vector2i, CellData>::ConstIterator E = tile_map.find(p_coords);
2080
2081 if (!E) {
2082 return TileSetSource::INVALID_TILE_ALTERNATIVE;
2083 }
2084
2085 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
2086 if (p_use_proxies && tile_set.is_valid()) {
2087 Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile);
2088 return proxyed[2];
2089 }
2090
2091 return E->value.cell.alternative_tile;
2092}
2093
2094TileData *TileMapLayer::get_cell_tile_data(const Vector2i &p_coords, bool p_use_proxies) const {
2095 int source_id = get_cell_source_id(p_coords, p_use_proxies);
2096 if (source_id == TileSet::INVALID_SOURCE) {
2097 return nullptr;
2098 }
2099
2100 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
2101 Ref<TileSetAtlasSource> source = tile_set->get_source(source_id);
2102 if (source.is_valid()) {
2103 return source->get_tile_data(get_cell_atlas_coords(p_coords, p_use_proxies), get_cell_alternative_tile(p_coords, p_use_proxies));
2104 }
2105
2106 return nullptr;
2107}
2108
2109void TileMapLayer::clear() {
2110 // Remove all tiles.
2111 for (KeyValue<Vector2i, CellData> &kv : tile_map) {
2112 erase_cell(kv.key);
2113 }
2114 used_rect_cache_dirty = true;
2115}
2116
2117Ref<TileMapPattern> TileMapLayer::get_pattern(TypedArray<Vector2i> p_coords_array) {
2118 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
2119 ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr);
2120
2121 Ref<TileMapPattern> output;
2122 output.instantiate();
2123 if (p_coords_array.is_empty()) {
2124 return output;
2125 }
2126
2127 Vector2i min = Vector2i(p_coords_array[0]);
2128 for (int i = 1; i < p_coords_array.size(); i++) {
2129 min = min.min(p_coords_array[i]);
2130 }
2131
2132 Vector<Vector2i> coords_in_pattern_array;
2133 coords_in_pattern_array.resize(p_coords_array.size());
2134 Vector2i ensure_positive_offset;
2135 for (int i = 0; i < p_coords_array.size(); i++) {
2136 Vector2i coords = p_coords_array[i];
2137 Vector2i coords_in_pattern = coords - min;
2138 if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE) {
2139 if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED) {
2140 if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(min.y % 2) && bool(coords_in_pattern.y % 2)) {
2141 coords_in_pattern.x -= 1;
2142 if (coords_in_pattern.x < 0) {
2143 ensure_positive_offset.x = 1;
2144 }
2145 } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(min.x % 2) && bool(coords_in_pattern.x % 2)) {
2146 coords_in_pattern.y -= 1;
2147 if (coords_in_pattern.y < 0) {
2148 ensure_positive_offset.y = 1;
2149 }
2150 }
2151 } else if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED_OFFSET) {
2152 if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(min.y % 2) && bool(coords_in_pattern.y % 2)) {
2153 coords_in_pattern.x += 1;
2154 } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(min.x % 2) && bool(coords_in_pattern.x % 2)) {
2155 coords_in_pattern.y += 1;
2156 }
2157 }
2158 }
2159 coords_in_pattern_array.write[i] = coords_in_pattern;
2160 }
2161
2162 for (int i = 0; i < coords_in_pattern_array.size(); i++) {
2163 Vector2i coords = p_coords_array[i];
2164 Vector2i coords_in_pattern = coords_in_pattern_array[i];
2165 output->set_cell(coords_in_pattern + ensure_positive_offset, get_cell_source_id(coords), get_cell_atlas_coords(coords), get_cell_alternative_tile(coords));
2166 }
2167
2168 return output;
2169}
2170
2171void TileMapLayer::set_pattern(const Vector2i &p_position, const Ref<TileMapPattern> p_pattern) {
2172 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
2173 ERR_FAIL_COND(tile_set.is_null());
2174 ERR_FAIL_COND(p_pattern.is_null());
2175
2176 TypedArray<Vector2i> used_cells = p_pattern->get_used_cells();
2177 for (int i = 0; i < used_cells.size(); i++) {
2178 Vector2i coords = tile_map_node->map_pattern(p_position, used_cells[i], p_pattern);
2179 set_cell(coords, p_pattern->get_cell_source_id(used_cells[i]), p_pattern->get_cell_atlas_coords(used_cells[i]), p_pattern->get_cell_alternative_tile(used_cells[i]));
2180 }
2181}
2182
2183void TileMapLayer::set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
2184 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
2185 ERR_FAIL_COND(!tile_set.is_valid());
2186 ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count());
2187
2188 Vector<Vector2i> cells_vector;
2189 HashSet<Vector2i> painted_set;
2190 for (int i = 0; i < p_cells.size(); i++) {
2191 cells_vector.push_back(p_cells[i]);
2192 painted_set.insert(p_cells[i]);
2193 }
2194 HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(cells_vector, p_terrain_set, p_terrain, p_ignore_empty_terrains);
2195 for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
2196 if (painted_set.has(kv.key)) {
2197 // Paint a random tile with the correct terrain for the painted path.
2198 TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
2199 set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
2200 } else {
2201 // Avoids updating the painted path from the output if the new pattern is the same as before.
2202 TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
2203 TileMapCell cell = get_cell(kv.key);
2204 if (cell.source_id != TileSet::INVALID_SOURCE) {
2205 TileSetSource *source = *tile_set->get_source(cell.source_id);
2206 TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
2207 if (atlas_source) {
2208 // Get tile data.
2209 TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
2210 if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
2211 in_map_terrain_pattern = tile_data->get_terrains_pattern();
2212 }
2213 }
2214 }
2215 if (in_map_terrain_pattern != kv.value) {
2216 TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
2217 set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
2218 }
2219 }
2220 }
2221}
2222
2223void TileMapLayer::set_cells_terrain_path(TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
2224 const Ref<TileSet> &tile_set = tile_map_node->get_tileset();
2225 ERR_FAIL_COND(!tile_set.is_valid());
2226 ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count());
2227
2228 Vector<Vector2i> vector_path;
2229 HashSet<Vector2i> painted_set;
2230 for (int i = 0; i < p_path.size(); i++) {
2231 vector_path.push_back(p_path[i]);
2232 painted_set.insert(p_path[i]);
2233 }
2234
2235 HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_path(vector_path, p_terrain_set, p_terrain, p_ignore_empty_terrains);
2236 for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
2237 if (painted_set.has(kv.key)) {
2238 // Paint a random tile with the correct terrain for the painted path.
2239 TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
2240 set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
2241 } else {
2242 // Avoids updating the painted path from the output if the new pattern is the same as before.
2243 TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
2244 TileMapCell cell = get_cell(kv.key);
2245 if (cell.source_id != TileSet::INVALID_SOURCE) {
2246 TileSetSource *source = *tile_set->get_source(cell.source_id);
2247 TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
2248 if (atlas_source) {
2249 // Get tile data.
2250 TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
2251 if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
2252 in_map_terrain_pattern = tile_data->get_terrains_pattern();
2253 }
2254 }
2255 }
2256 if (in_map_terrain_pattern != kv.value) {
2257 TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
2258 set_cell(kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
2259 }
2260 }
2261 }
2262}
2263
2264TypedArray<Vector2i> TileMapLayer::get_used_cells() const {
2265 // Returns the cells used in the tilemap.
2266 TypedArray<Vector2i> a;
2267 a.resize(tile_map.size());
2268 int i = 0;
2269 for (const KeyValue<Vector2i, CellData> &E : tile_map) {
2270 Vector2i p(E.key.x, E.key.y);
2271 a[i++] = p;
2272 }
2273
2274 return a;
2275}
2276
2277TypedArray<Vector2i> TileMapLayer::get_used_cells_by_id(int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) const {
2278 // Returns the cells used in the tilemap.
2279 TypedArray<Vector2i> a;
2280 for (const KeyValue<Vector2i, CellData> &E : tile_map) {
2281 if ((p_source_id == TileSet::INVALID_SOURCE || p_source_id == E.value.cell.source_id) &&
2282 (p_atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || p_atlas_coords == E.value.cell.get_atlas_coords()) &&
2283 (p_alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE || p_alternative_tile == E.value.cell.alternative_tile)) {
2284 a.push_back(E.key);
2285 }
2286 }
2287
2288 return a;
2289}
2290
2291Rect2i TileMapLayer::get_used_rect() const {
2292 // Return the rect of the currently used area.
2293 if (used_rect_cache_dirty) {
2294 used_rect_cache = Rect2i();
2295
2296 if (tile_map.size() > 0) {
2297 used_rect_cache = Rect2i(tile_map.begin()->key.x, tile_map.begin()->key.y, 0, 0);
2298
2299 for (const KeyValue<Vector2i, CellData> &E : tile_map) {
2300 used_rect_cache.expand_to(E.key);
2301 }
2302 used_rect_cache.size += Vector2i(1, 1); // The cache expands to top-left coordinate, so we add one full tile.
2303 }
2304 used_rect_cache_dirty = false;
2305 }
2306
2307 return used_rect_cache;
2308}
2309
2310void TileMapLayer::set_name(String p_name) {
2311 if (name == p_name) {
2312 return;
2313 }
2314 name = p_name;
2315 tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed);
2316}
2317
2318String TileMapLayer::get_name() const {
2319 return name;
2320}
2321
2322void TileMapLayer::set_enabled(bool p_enabled) {
2323 if (enabled == p_enabled) {
2324 return;
2325 }
2326 enabled = p_enabled;
2327 dirty.flags[DIRTY_FLAGS_LAYER_ENABLED] = true;
2328 tile_map_node->queue_internal_update();
2329 tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed);
2330
2331 tile_map_node->update_configuration_warnings();
2332}
2333
2334bool TileMapLayer::is_enabled() const {
2335 return enabled;
2336}
2337
2338void TileMapLayer::set_modulate(Color p_modulate) {
2339 if (modulate == p_modulate) {
2340 return;
2341 }
2342 modulate = p_modulate;
2343 dirty.flags[DIRTY_FLAGS_LAYER_MODULATE] = true;
2344 tile_map_node->queue_internal_update();
2345 tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed);
2346}
2347
2348Color TileMapLayer::get_modulate() const {
2349 return modulate;
2350}
2351
2352void TileMapLayer::set_y_sort_enabled(bool p_y_sort_enabled) {
2353 if (y_sort_enabled == p_y_sort_enabled) {
2354 return;
2355 }
2356 y_sort_enabled = p_y_sort_enabled;
2357 dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] = true;
2358 tile_map_node->queue_internal_update();
2359 tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed);
2360
2361 tile_map_node->update_configuration_warnings();
2362}
2363
2364bool TileMapLayer::is_y_sort_enabled() const {
2365 return y_sort_enabled;
2366}
2367
2368void TileMapLayer::set_y_sort_origin(int p_y_sort_origin) {
2369 if (y_sort_origin == p_y_sort_origin) {
2370 return;
2371 }
2372 y_sort_origin = p_y_sort_origin;
2373 dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] = true;
2374 tile_map_node->queue_internal_update();
2375 tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed);
2376}
2377
2378int TileMapLayer::get_y_sort_origin() const {
2379 return y_sort_origin;
2380}
2381
2382void TileMapLayer::set_z_index(int p_z_index) {
2383 if (z_index == p_z_index) {
2384 return;
2385 }
2386 z_index = p_z_index;
2387 dirty.flags[DIRTY_FLAGS_LAYER_Z_INDEX] = true;
2388 tile_map_node->queue_internal_update();
2389 tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed);
2390
2391 tile_map_node->update_configuration_warnings();
2392}
2393
2394int TileMapLayer::get_z_index() const {
2395 return z_index;
2396}
2397
2398void TileMapLayer::set_navigation_map(RID p_map) {
2399 ERR_FAIL_COND_MSG(!tile_map_node->is_inside_tree(), "A TileMap navigation map can only be changed while inside the SceneTree.");
2400 navigation_map = p_map;
2401 uses_world_navigation_map = p_map == tile_map_node->get_world_2d()->get_navigation_map();
2402}
2403
2404RID TileMapLayer::get_navigation_map() const {
2405 if (navigation_map.is_valid()) {
2406 return navigation_map;
2407 }
2408 return RID();
2409}
2410
2411void TileMapLayer::fix_invalid_tiles() {
2412 Ref<TileSet> tileset = tile_map_node->get_tileset();
2413 ERR_FAIL_COND_MSG(tileset.is_null(), "Cannot call fix_invalid_tiles() on a TileMap without a valid TileSet.");
2414
2415 RBSet<Vector2i> coords;
2416 for (const KeyValue<Vector2i, CellData> &E : tile_map) {
2417 TileSetSource *source = *tileset->get_source(E.value.cell.source_id);
2418 if (!source || !source->has_tile(E.value.cell.get_atlas_coords()) || !source->has_alternative_tile(E.value.cell.get_atlas_coords(), E.value.cell.alternative_tile)) {
2419 coords.insert(E.key);
2420 }
2421 }
2422 for (const Vector2i &E : coords) {
2423 set_cell(E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
2424 }
2425}
2426
2427bool TileMapLayer::has_body_rid(RID p_physics_body) const {
2428 return bodies_coords.has(p_physics_body);
2429}
2430
2431Vector2i TileMapLayer::get_coords_for_body_rid(RID p_physics_body) const {
2432 return bodies_coords[p_physics_body];
2433}
2434
2435TileMapLayer::~TileMapLayer() {
2436 in_destructor = true;
2437 clear();
2438 internal_update();
2439}
2440
2441HashMap<Vector2i, TileSet::CellNeighbor> TerrainConstraint::get_overlapping_coords_and_peering_bits() const {
2442 HashMap<Vector2i, TileSet::CellNeighbor> output;
2443
2444 ERR_FAIL_COND_V(is_center_bit(), output);
2445
2446 Ref<TileSet> ts = tile_map->get_tileset();
2447 ERR_FAIL_COND_V(!ts.is_valid(), output);
2448
2449 TileSet::TileShape shape = ts->get_tile_shape();
2450 if (shape == TileSet::TILE_SHAPE_SQUARE) {
2451 switch (bit) {
2452 case 1:
2453 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE;
2454 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE;
2455 break;
2456 case 2:
2457 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
2458 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
2459 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
2460 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
2461 break;
2462 case 3:
2463 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE;
2464 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE;
2465 break;
2466 default:
2467 ERR_FAIL_V(output);
2468 }
2469 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
2470 switch (bit) {
2471 case 1:
2472 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
2473 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
2474 break;
2475 case 2:
2476 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER;
2477 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER;
2478 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_CORNER;
2479 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER;
2480 break;
2481 case 3:
2482 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
2483 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
2484 break;
2485 default:
2486 ERR_FAIL_V(output);
2487 }
2488 } else {
2489 // Half offset shapes.
2490 TileSet::TileOffsetAxis offset_axis = ts->get_tile_offset_axis();
2491 if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
2492 switch (bit) {
2493 case 1:
2494 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE;
2495 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE;
2496 break;
2497 case 2:
2498 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
2499 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
2500 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_CORNER;
2501 break;
2502 case 3:
2503 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
2504 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
2505 break;
2506 case 4:
2507 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER;
2508 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
2509 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
2510 break;
2511 case 5:
2512 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
2513 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
2514 break;
2515 default:
2516 ERR_FAIL_V(output);
2517 }
2518 } else {
2519 switch (bit) {
2520 case 1:
2521 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER;
2522 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
2523 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
2524 break;
2525 case 2:
2526 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
2527 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
2528 break;
2529 case 3:
2530 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
2531 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER;
2532 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
2533 break;
2534 case 4:
2535 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE;
2536 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE;
2537 break;
2538 case 5:
2539 output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
2540 output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
2541 break;
2542 default:
2543 ERR_FAIL_V(output);
2544 }
2545 }
2546 }
2547 return output;
2548}
2549
2550TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain) {
2551 tile_map = p_tile_map;
2552
2553 Ref<TileSet> ts = tile_map->get_tileset();
2554 ERR_FAIL_COND(!ts.is_valid());
2555
2556 bit = 0;
2557 base_cell_coords = p_position;
2558 terrain = p_terrain;
2559}
2560
2561TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain) {
2562 // The way we build the constraint make it easy to detect conflicting constraints.
2563 tile_map = p_tile_map;
2564
2565 Ref<TileSet> ts = tile_map->get_tileset();
2566 ERR_FAIL_COND(!ts.is_valid());
2567
2568 TileSet::TileShape shape = ts->get_tile_shape();
2569 if (shape == TileSet::TILE_SHAPE_SQUARE) {
2570 switch (p_bit) {
2571 case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
2572 bit = 1;
2573 base_cell_coords = p_position;
2574 break;
2575 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
2576 bit = 2;
2577 base_cell_coords = p_position;
2578 break;
2579 case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
2580 bit = 3;
2581 base_cell_coords = p_position;
2582 break;
2583 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
2584 bit = 2;
2585 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
2586 break;
2587 case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
2588 bit = 1;
2589 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
2590 break;
2591 case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
2592 bit = 2;
2593 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER);
2594 break;
2595 case TileSet::CELL_NEIGHBOR_TOP_SIDE:
2596 bit = 3;
2597 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
2598 break;
2599 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
2600 bit = 2;
2601 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
2602 break;
2603 default:
2604 ERR_FAIL();
2605 break;
2606 }
2607 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
2608 switch (p_bit) {
2609 case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
2610 bit = 2;
2611 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
2612 break;
2613 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
2614 bit = 1;
2615 base_cell_coords = p_position;
2616 break;
2617 case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
2618 bit = 2;
2619 base_cell_coords = p_position;
2620 break;
2621 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
2622 bit = 3;
2623 base_cell_coords = p_position;
2624 break;
2625 case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
2626 bit = 2;
2627 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
2628 break;
2629 case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
2630 bit = 1;
2631 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
2632 break;
2633 case TileSet::CELL_NEIGHBOR_TOP_CORNER:
2634 bit = 2;
2635 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_CORNER);
2636 break;
2637 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
2638 bit = 3;
2639 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
2640 break;
2641 default:
2642 ERR_FAIL();
2643 break;
2644 }
2645 } else {
2646 // Half-offset shapes.
2647 TileSet::TileOffsetAxis offset_axis = ts->get_tile_offset_axis();
2648 if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
2649 switch (p_bit) {
2650 case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
2651 bit = 1;
2652 base_cell_coords = p_position;
2653 break;
2654 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
2655 bit = 2;
2656 base_cell_coords = p_position;
2657 break;
2658 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
2659 bit = 3;
2660 base_cell_coords = p_position;
2661 break;
2662 case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
2663 bit = 4;
2664 base_cell_coords = p_position;
2665 break;
2666 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
2667 bit = 5;
2668 base_cell_coords = p_position;
2669 break;
2670 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
2671 bit = 2;
2672 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
2673 break;
2674 case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
2675 bit = 1;
2676 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
2677 break;
2678 case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
2679 bit = 4;
2680 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
2681 break;
2682 case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
2683 bit = 3;
2684 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
2685 break;
2686 case TileSet::CELL_NEIGHBOR_TOP_CORNER:
2687 bit = 2;
2688 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
2689 break;
2690 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
2691 bit = 5;
2692 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
2693 break;
2694 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
2695 bit = 4;
2696 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
2697 break;
2698 default:
2699 ERR_FAIL();
2700 break;
2701 }
2702 } else {
2703 switch (p_bit) {
2704 case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
2705 bit = 1;
2706 base_cell_coords = p_position;
2707 break;
2708 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
2709 bit = 2;
2710 base_cell_coords = p_position;
2711 break;
2712 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
2713 bit = 3;
2714 base_cell_coords = p_position;
2715 break;
2716 case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
2717 bit = 4;
2718 base_cell_coords = p_position;
2719 break;
2720 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
2721 bit = 1;
2722 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE);
2723 break;
2724 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
2725 bit = 5;
2726 base_cell_coords = p_position;
2727 break;
2728 case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
2729 bit = 3;
2730 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
2731 break;
2732 case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
2733 bit = 2;
2734 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
2735 break;
2736 case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
2737 bit = 1;
2738 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
2739 break;
2740 case TileSet::CELL_NEIGHBOR_TOP_SIDE:
2741 bit = 4;
2742 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
2743 break;
2744 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
2745 bit = 3;
2746 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
2747 break;
2748 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
2749 bit = 5;
2750 base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
2751 break;
2752 default:
2753 ERR_FAIL();
2754 break;
2755 }
2756 }
2757 }
2758 terrain = p_terrain;
2759}
2760
2761#define TILEMAP_CALL_FOR_LAYER(layer, function, ...) \
2762 if (layer < 0) { \
2763 layer = layers.size() + layer; \
2764 }; \
2765 ERR_FAIL_INDEX(layer, (int)layers.size()); \
2766 layers[layer]->function(__VA_ARGS__);
2767
2768#define TILEMAP_CALL_FOR_LAYER_V(layer, err_value, function, ...) \
2769 if (layer < 0) { \
2770 layer = layers.size() + layer; \
2771 }; \
2772 ERR_FAIL_INDEX_V(layer, (int)layers.size(), err_value); \
2773 return layers[layer]->function(__VA_ARGS__);
2774
2775Vector2i TileMap::transform_coords_layout(const Vector2i &p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout) {
2776 // Transform to stacked layout.
2777 Vector2i output = p_coords;
2778 if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
2779 SWAP(output.x, output.y);
2780 }
2781 switch (p_from_layout) {
2782 case TileSet::TILE_LAYOUT_STACKED:
2783 break;
2784 case TileSet::TILE_LAYOUT_STACKED_OFFSET:
2785 if (output.y % 2) {
2786 output.x -= 1;
2787 }
2788 break;
2789 case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
2790 case TileSet::TILE_LAYOUT_STAIRS_DOWN:
2791 if ((p_from_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
2792 if (output.y < 0 && bool(output.y % 2)) {
2793 output = Vector2i(output.x + output.y / 2 - 1, output.y);
2794 } else {
2795 output = Vector2i(output.x + output.y / 2, output.y);
2796 }
2797 } else {
2798 if (output.x < 0 && bool(output.x % 2)) {
2799 output = Vector2i(output.x / 2 - 1, output.x + output.y * 2);
2800 } else {
2801 output = Vector2i(output.x / 2, output.x + output.y * 2);
2802 }
2803 }
2804 break;
2805 case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
2806 case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
2807 if ((p_from_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
2808 if ((output.x + output.y) < 0 && (output.x - output.y) % 2) {
2809 output = Vector2i((output.x + output.y) / 2 - 1, output.y - output.x);
2810 } else {
2811 output = Vector2i((output.x + output.y) / 2, -output.x + output.y);
2812 }
2813 } else {
2814 if ((output.x - output.y) < 0 && (output.x + output.y) % 2) {
2815 output = Vector2i((output.x - output.y) / 2 - 1, output.x + output.y);
2816 } else {
2817 output = Vector2i((output.x - output.y) / 2, output.x + output.y);
2818 }
2819 }
2820 break;
2821 }
2822
2823 switch (p_to_layout) {
2824 case TileSet::TILE_LAYOUT_STACKED:
2825 break;
2826 case TileSet::TILE_LAYOUT_STACKED_OFFSET:
2827 if (output.y % 2) {
2828 output.x += 1;
2829 }
2830 break;
2831 case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
2832 case TileSet::TILE_LAYOUT_STAIRS_DOWN:
2833 if ((p_to_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
2834 if (output.y < 0 && (output.y % 2)) {
2835 output = Vector2i(output.x - output.y / 2 + 1, output.y);
2836 } else {
2837 output = Vector2i(output.x - output.y / 2, output.y);
2838 }
2839 } else {
2840 if (output.y % 2) {
2841 if (output.y < 0) {
2842 output = Vector2i(2 * output.x + 1, -output.x + output.y / 2 - 1);
2843 } else {
2844 output = Vector2i(2 * output.x + 1, -output.x + output.y / 2);
2845 }
2846 } else {
2847 output = Vector2i(2 * output.x, -output.x + output.y / 2);
2848 }
2849 }
2850 break;
2851 case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
2852 case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
2853 if ((p_to_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
2854 if (output.y % 2) {
2855 if (output.y > 0) {
2856 output = Vector2i(output.x - output.y / 2, output.x + output.y / 2 + 1);
2857 } else {
2858 output = Vector2i(output.x - output.y / 2 + 1, output.x + output.y / 2);
2859 }
2860 } else {
2861 output = Vector2i(output.x - output.y / 2, output.x + output.y / 2);
2862 }
2863 } else {
2864 if (output.y % 2) {
2865 if (output.y < 0) {
2866 output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2 - 1);
2867 } else {
2868 output = Vector2i(output.x + output.y / 2 + 1, -output.x + output.y / 2);
2869 }
2870 } else {
2871 output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2);
2872 }
2873 }
2874 break;
2875 }
2876
2877 if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
2878 SWAP(output.x, output.y);
2879 }
2880
2881 return output;
2882}
2883
2884void TileMap::set_selected_layer(int p_layer_id) {
2885 ERR_FAIL_COND(p_layer_id < -1 || p_layer_id >= (int)layers.size());
2886 if (selected_layer == p_layer_id) {
2887 return;
2888 }
2889 selected_layer = p_layer_id;
2890 emit_signal(CoreStringNames::get_singleton()->changed);
2891
2892 // Update the layers modulation.
2893 for (Ref<TileMapLayer> &layer : layers) {
2894 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_SELECTED_LAYER);
2895 }
2896}
2897
2898int TileMap::get_selected_layer() const {
2899 return selected_layer;
2900}
2901
2902void TileMap::_notification(int p_what) {
2903 switch (p_what) {
2904 case NOTIFICATION_ENTER_TREE: {
2905 for (Ref<TileMapLayer> &layer : layers) {
2906 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_IN_TREE);
2907 }
2908 } break;
2909
2910 case NOTIFICATION_EXIT_TREE: {
2911 for (Ref<TileMapLayer> &layer : layers) {
2912 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_IN_TREE);
2913 }
2914 } break;
2915
2916 case TileMap::NOTIFICATION_ENTER_CANVAS: {
2917 for (Ref<TileMapLayer> &layer : layers) {
2918 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_IN_CANVAS);
2919 }
2920 } break;
2921
2922 case TileMap::NOTIFICATION_EXIT_CANVAS: {
2923 for (Ref<TileMapLayer> &layer : layers) {
2924 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_IN_CANVAS);
2925 }
2926 } break;
2927
2928 case NOTIFICATION_DRAW: {
2929 // Rendering.
2930 if (tile_set.is_valid()) {
2931 RenderingServer::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), is_y_sort_enabled());
2932 }
2933 } break;
2934
2935 case TileMap::NOTIFICATION_VISIBILITY_CHANGED: {
2936 for (Ref<TileMapLayer> &layer : layers) {
2937 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_VISIBILITY);
2938 }
2939 } break;
2940
2941 case TileMap::NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
2942 // Physics.
2943 bool in_editor = false;
2944#ifdef TOOLS_ENABLED
2945 in_editor = Engine::get_singleton()->is_editor_hint();
2946#endif
2947 if (is_inside_tree() && collision_animatable && !in_editor) {
2948 // Update transform on the physics tick when in animatable mode.
2949 last_valid_transform = new_transform;
2950 set_notify_local_transform(false);
2951 set_global_transform(new_transform);
2952 set_notify_local_transform(true);
2953 }
2954 } break;
2955
2956 case NOTIFICATION_TRANSFORM_CHANGED: {
2957 // Physics.
2958 for (Ref<TileMapLayer> &layer : layers) {
2959 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_XFORM);
2960 }
2961 } break;
2962
2963 case TileMap::NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
2964 for (Ref<TileMapLayer> &layer : layers) {
2965 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_LOCAL_XFORM);
2966 }
2967
2968 // Physics.
2969 bool in_editor = false;
2970#ifdef TOOLS_ENABLED
2971 in_editor = Engine::get_singleton()->is_editor_hint();
2972#endif
2973
2974 // Only active when animatable. Send the new transform to the physics...
2975 if (is_inside_tree() && collision_animatable && !in_editor) {
2976 // Store last valid transform.
2977 new_transform = get_global_transform();
2978
2979 // ... but then revert changes.
2980 set_notify_local_transform(false);
2981 set_global_transform(last_valid_transform);
2982 set_notify_local_transform(true);
2983 }
2984 } break;
2985 }
2986}
2987
2988#ifndef DISABLE_DEPRECATED
2989// Deprecated methods.
2990void TileMap::force_update(int p_layer) {
2991 notify_runtime_tile_data_update(p_layer);
2992 update_internals();
2993}
2994#endif
2995
2996void TileMap::queue_internal_update() {
2997 if (pending_update) {
2998 return;
2999 }
3000 pending_update = true;
3001 callable_mp(this, &TileMap::_internal_update).call_deferred();
3002}
3003
3004void TileMap::_internal_update() {
3005 // Other updates.
3006 if (!pending_update) {
3007 return;
3008 }
3009
3010 // Update dirty quadrants on layers.
3011 polygon_cache.clear();
3012 for (Ref<TileMapLayer> &layer : layers) {
3013 layer->internal_update();
3014 }
3015
3016 pending_update = false;
3017}
3018
3019void TileMap::set_tileset(const Ref<TileSet> &p_tileset) {
3020 if (p_tileset == tile_set) {
3021 return;
3022 }
3023
3024 // Set the tileset, registering to its changes.
3025 if (tile_set.is_valid()) {
3026 tile_set->disconnect_changed(callable_mp(this, &TileMap::_tile_set_changed));
3027 }
3028
3029 tile_set = p_tileset;
3030
3031 if (tile_set.is_valid()) {
3032 tile_set->connect_changed(callable_mp(this, &TileMap::_tile_set_changed));
3033 }
3034
3035 for (Ref<TileMapLayer> &layer : layers) {
3036 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_TILE_SET);
3037 }
3038
3039 emit_signal(CoreStringNames::get_singleton()->changed);
3040}
3041
3042Ref<TileSet> TileMap::get_tileset() const {
3043 return tile_set;
3044}
3045
3046void TileMap::set_rendering_quadrant_size(int p_size) {
3047 ERR_FAIL_COND_MSG(p_size < 1, "TileMapQuadrant size cannot be smaller than 1.");
3048
3049 rendering_quadrant_size = p_size;
3050 for (Ref<TileMapLayer> &layer : layers) {
3051 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE);
3052 }
3053 emit_signal(CoreStringNames::get_singleton()->changed);
3054}
3055
3056int TileMap::get_rendering_quadrant_size() const {
3057 return rendering_quadrant_size;
3058}
3059
3060void TileMap::draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame, Color p_modulation, const TileData *p_tile_data_override, real_t p_animation_offset) {
3061 ERR_FAIL_COND(!p_tile_set.is_valid());
3062 ERR_FAIL_COND(!p_tile_set->has_source(p_atlas_source_id));
3063 ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_tile(p_atlas_coords));
3064 ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_alternative_tile(p_atlas_coords, p_alternative_tile));
3065 TileSetSource *source = *p_tile_set->get_source(p_atlas_source_id);
3066 TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
3067 if (atlas_source) {
3068 // Check for the frame.
3069 if (p_frame >= 0) {
3070 ERR_FAIL_INDEX(p_frame, atlas_source->get_tile_animation_frames_count(p_atlas_coords));
3071 }
3072
3073 // Get the texture.
3074 Ref<Texture2D> tex = atlas_source->get_runtime_texture();
3075 if (!tex.is_valid()) {
3076 return;
3077 }
3078
3079 // Check if we are in the texture, return otherwise.
3080 Vector2i grid_size = atlas_source->get_atlas_grid_size();
3081 if (p_atlas_coords.x >= grid_size.x || p_atlas_coords.y >= grid_size.y) {
3082 return;
3083 }
3084
3085 // Get tile data.
3086 const TileData *tile_data = p_tile_data_override ? p_tile_data_override : atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile);
3087
3088 // Get the tile modulation.
3089 Color modulate = tile_data->get_modulate() * p_modulation;
3090
3091 // Compute the offset.
3092 Vector2 tile_offset = tile_data->get_texture_origin();
3093
3094 // Get destination rect.
3095 Rect2 dest_rect;
3096 dest_rect.size = atlas_source->get_runtime_tile_texture_region(p_atlas_coords).size;
3097 dest_rect.size.x += FP_ADJUST;
3098 dest_rect.size.y += FP_ADJUST;
3099
3100 bool transpose = tile_data->get_transpose() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
3101 if (transpose) {
3102 dest_rect.position = (p_position - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset);
3103 } else {
3104 dest_rect.position = (p_position - dest_rect.size / 2 - tile_offset);
3105 }
3106
3107 if (tile_data->get_flip_h() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H)) {
3108 dest_rect.size.x = -dest_rect.size.x;
3109 }
3110
3111 if (tile_data->get_flip_v() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V)) {
3112 dest_rect.size.y = -dest_rect.size.y;
3113 }
3114
3115 // Draw the tile.
3116 if (p_frame >= 0) {
3117 Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, p_frame);
3118 tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
3119 } else if (atlas_source->get_tile_animation_frames_count(p_atlas_coords) == 1) {
3120 Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, 0);
3121 tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
3122 } else {
3123 real_t speed = atlas_source->get_tile_animation_speed(p_atlas_coords);
3124 real_t animation_duration = atlas_source->get_tile_animation_total_duration(p_atlas_coords) / speed;
3125 real_t time = 0.0;
3126 for (int frame = 0; frame < atlas_source->get_tile_animation_frames_count(p_atlas_coords); frame++) {
3127 real_t frame_duration = atlas_source->get_tile_animation_frame_duration(p_atlas_coords, frame) / speed;
3128 RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, animation_duration, time, time + frame_duration, p_animation_offset);
3129
3130 Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, frame);
3131 tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
3132
3133 time += frame_duration;
3134 }
3135 RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, 1.0, 0.0, 1.0, 0.0);
3136 }
3137 }
3138}
3139
3140int TileMap::get_layers_count() const {
3141 return layers.size();
3142}
3143
3144void TileMap::add_layer(int p_to_pos) {
3145 if (p_to_pos < 0) {
3146 p_to_pos = layers.size() + p_to_pos + 1;
3147 }
3148
3149 ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1);
3150
3151 // Must clear before adding the layer.
3152 Ref<TileMapLayer> new_layer;
3153 new_layer.instantiate();
3154 new_layer->set_tile_map(this);
3155 layers.insert(p_to_pos, new_layer);
3156 for (unsigned int i = 0; i < layers.size(); i++) {
3157 layers[i]->set_layer_index_in_tile_map_node(i);
3158 }
3159 queue_internal_update();
3160 notify_property_list_changed();
3161
3162 emit_signal(CoreStringNames::get_singleton()->changed);
3163
3164 update_configuration_warnings();
3165}
3166
3167void TileMap::move_layer(int p_layer, int p_to_pos) {
3168 ERR_FAIL_INDEX(p_layer, (int)layers.size());
3169 ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1);
3170
3171 // Clear before shuffling layers.
3172 Ref<TileMapLayer> layer = layers[p_layer];
3173 layers.insert(p_to_pos, layer);
3174 layers.remove_at(p_to_pos < p_layer ? p_layer + 1 : p_layer);
3175 for (unsigned int i = 0; i < layers.size(); i++) {
3176 layers[i]->set_layer_index_in_tile_map_node(i);
3177 }
3178 queue_internal_update();
3179 notify_property_list_changed();
3180
3181 if (selected_layer == p_layer) {
3182 selected_layer = p_to_pos < p_layer ? p_to_pos - 1 : p_to_pos;
3183 }
3184
3185 emit_signal(CoreStringNames::get_singleton()->changed);
3186
3187 update_configuration_warnings();
3188}
3189
3190void TileMap::remove_layer(int p_layer) {
3191 ERR_FAIL_INDEX(p_layer, (int)layers.size());
3192
3193 // Clear before removing the layer.
3194 layers.remove_at(p_layer);
3195 for (unsigned int i = 0; i < layers.size(); i++) {
3196 layers[i]->set_layer_index_in_tile_map_node(i);
3197 }
3198 queue_internal_update();
3199 notify_property_list_changed();
3200
3201 if (selected_layer >= p_layer) {
3202 selected_layer -= 1;
3203 }
3204
3205 emit_signal(CoreStringNames::get_singleton()->changed);
3206
3207 update_configuration_warnings();
3208}
3209
3210void TileMap::set_layer_name(int p_layer, String p_name) {
3211 TILEMAP_CALL_FOR_LAYER(p_layer, set_name, p_name);
3212}
3213
3214String TileMap::get_layer_name(int p_layer) const {
3215 TILEMAP_CALL_FOR_LAYER_V(p_layer, "", get_name);
3216}
3217
3218void TileMap::set_layer_enabled(int p_layer, bool p_enabled) {
3219 TILEMAP_CALL_FOR_LAYER(p_layer, set_enabled, p_enabled);
3220}
3221
3222bool TileMap::is_layer_enabled(int p_layer) const {
3223 TILEMAP_CALL_FOR_LAYER_V(p_layer, false, is_enabled);
3224}
3225
3226void TileMap::set_layer_modulate(int p_layer, Color p_modulate) {
3227 TILEMAP_CALL_FOR_LAYER(p_layer, set_modulate, p_modulate);
3228}
3229
3230Color TileMap::get_layer_modulate(int p_layer) const {
3231 TILEMAP_CALL_FOR_LAYER_V(p_layer, Color(), get_modulate);
3232}
3233
3234void TileMap::set_layer_y_sort_enabled(int p_layer, bool p_y_sort_enabled) {
3235 TILEMAP_CALL_FOR_LAYER(p_layer, set_y_sort_enabled, p_y_sort_enabled);
3236}
3237
3238bool TileMap::is_layer_y_sort_enabled(int p_layer) const {
3239 TILEMAP_CALL_FOR_LAYER_V(p_layer, false, is_y_sort_enabled);
3240}
3241
3242void TileMap::set_layer_y_sort_origin(int p_layer, int p_y_sort_origin) {
3243 TILEMAP_CALL_FOR_LAYER(p_layer, set_y_sort_origin, p_y_sort_origin);
3244}
3245
3246int TileMap::get_layer_y_sort_origin(int p_layer) const {
3247 TILEMAP_CALL_FOR_LAYER_V(p_layer, 0, get_y_sort_origin);
3248}
3249
3250void TileMap::set_layer_z_index(int p_layer, int p_z_index) {
3251 TILEMAP_CALL_FOR_LAYER(p_layer, set_z_index, p_z_index);
3252}
3253
3254int TileMap::get_layer_z_index(int p_layer) const {
3255 TILEMAP_CALL_FOR_LAYER_V(p_layer, 0, get_z_index);
3256}
3257
3258void TileMap::set_layer_navigation_map(int p_layer, RID p_map) {
3259 TILEMAP_CALL_FOR_LAYER(p_layer, set_navigation_map, p_map);
3260}
3261
3262RID TileMap::get_layer_navigation_map(int p_layer) const {
3263 TILEMAP_CALL_FOR_LAYER_V(p_layer, RID(), get_navigation_map);
3264}
3265
3266void TileMap::set_collision_animatable(bool p_enabled) {
3267 if (collision_animatable == p_enabled) {
3268 return;
3269 }
3270 collision_animatable = p_enabled;
3271 set_notify_local_transform(p_enabled);
3272 set_physics_process_internal(p_enabled);
3273 for (Ref<TileMapLayer> &layer : layers) {
3274 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_COLLISION_ANIMATABLE);
3275 }
3276 emit_signal(CoreStringNames::get_singleton()->changed);
3277}
3278
3279bool TileMap::is_collision_animatable() const {
3280 return collision_animatable;
3281}
3282
3283void TileMap::set_collision_visibility_mode(TileMap::VisibilityMode p_show_collision) {
3284 if (collision_visibility_mode == p_show_collision) {
3285 return;
3286 }
3287 collision_visibility_mode = p_show_collision;
3288 for (Ref<TileMapLayer> &layer : layers) {
3289 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_COLLISION_VISIBILITY_MODE);
3290 }
3291 emit_signal(CoreStringNames::get_singleton()->changed);
3292}
3293
3294TileMap::VisibilityMode TileMap::get_collision_visibility_mode() {
3295 return collision_visibility_mode;
3296}
3297
3298void TileMap::set_navigation_visibility_mode(TileMap::VisibilityMode p_show_navigation) {
3299 if (navigation_visibility_mode == p_show_navigation) {
3300 return;
3301 }
3302 navigation_visibility_mode = p_show_navigation;
3303 for (Ref<TileMapLayer> &layer : layers) {
3304 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_NAVIGATION_VISIBILITY_MODE);
3305 }
3306 emit_signal(CoreStringNames::get_singleton()->changed);
3307}
3308
3309TileMap::VisibilityMode TileMap::get_navigation_visibility_mode() {
3310 return navigation_visibility_mode;
3311}
3312
3313void TileMap::set_y_sort_enabled(bool p_enable) {
3314 if (is_y_sort_enabled() == p_enable) {
3315 return;
3316 }
3317 Node2D::set_y_sort_enabled(p_enable);
3318 for (Ref<TileMapLayer> &layer : layers) {
3319 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED);
3320 }
3321 emit_signal(CoreStringNames::get_singleton()->changed);
3322 update_configuration_warnings();
3323}
3324
3325void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
3326 TILEMAP_CALL_FOR_LAYER(p_layer, set_cell, p_coords, p_source_id, p_atlas_coords, p_alternative_tile);
3327}
3328
3329void TileMap::erase_cell(int p_layer, const Vector2i &p_coords) {
3330 TILEMAP_CALL_FOR_LAYER(p_layer, set_cell, p_coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
3331}
3332
3333int TileMap::get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
3334 TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSet::INVALID_SOURCE, get_cell_source_id, p_coords, p_use_proxies);
3335}
3336
3337Vector2i TileMap::get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
3338 TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSetSource::INVALID_ATLAS_COORDS, get_cell_atlas_coords, p_coords, p_use_proxies);
3339}
3340
3341int TileMap::get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
3342 TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSetSource::INVALID_TILE_ALTERNATIVE, get_cell_alternative_tile, p_coords, p_use_proxies);
3343}
3344
3345TileData *TileMap::get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
3346 TILEMAP_CALL_FOR_LAYER_V(p_layer, nullptr, get_cell_tile_data, p_coords, p_use_proxies);
3347}
3348
3349Ref<TileMapPattern> TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array) {
3350 TILEMAP_CALL_FOR_LAYER_V(p_layer, Ref<TileMapPattern>(), get_pattern, p_coords_array);
3351}
3352
3353Vector2i TileMap::map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern) {
3354 ERR_FAIL_COND_V(p_pattern.is_null(), Vector2i());
3355 ERR_FAIL_COND_V(!p_pattern->has_cell(p_coords_in_pattern), Vector2i());
3356
3357 Vector2i output = p_position_in_tilemap + p_coords_in_pattern;
3358 if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE) {
3359 if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED) {
3360 if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(p_position_in_tilemap.y % 2) && bool(p_coords_in_pattern.y % 2)) {
3361 output.x += 1;
3362 } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(p_position_in_tilemap.x % 2) && bool(p_coords_in_pattern.x % 2)) {
3363 output.y += 1;
3364 }
3365 } else if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED_OFFSET) {
3366 if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(p_position_in_tilemap.y % 2) && bool(p_coords_in_pattern.y % 2)) {
3367 output.x -= 1;
3368 } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(p_position_in_tilemap.x % 2) && bool(p_coords_in_pattern.x % 2)) {
3369 output.y -= 1;
3370 }
3371 }
3372 }
3373
3374 return output;
3375}
3376
3377void TileMap::set_pattern(int p_layer, const Vector2i &p_position, const Ref<TileMapPattern> p_pattern) {
3378 TILEMAP_CALL_FOR_LAYER(p_layer, set_pattern, p_position, p_pattern);
3379}
3380
3381HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(int p_layer, const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints) {
3382 HashMap<Vector2i, TileSet::TerrainsPattern> err_value;
3383 TILEMAP_CALL_FOR_LAYER_V(p_layer, err_value, terrain_fill_constraints, p_to_replace, p_terrain_set, p_constraints);
3384}
3385
3386HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
3387 HashMap<Vector2i, TileSet::TerrainsPattern> err_value;
3388 TILEMAP_CALL_FOR_LAYER_V(p_layer, err_value, terrain_fill_connect, p_coords_array, p_terrain_set, p_terrain, p_ignore_empty_terrains);
3389}
3390
3391HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
3392 HashMap<Vector2i, TileSet::TerrainsPattern> err_value;
3393 TILEMAP_CALL_FOR_LAYER_V(p_layer, err_value, terrain_fill_path, p_coords_array, p_terrain_set, p_terrain, p_ignore_empty_terrains);
3394}
3395
3396HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains) {
3397 HashMap<Vector2i, TileSet::TerrainsPattern> err_value;
3398 TILEMAP_CALL_FOR_LAYER_V(p_layer, err_value, terrain_fill_pattern, p_coords_array, p_terrain_set, p_terrains_pattern, p_ignore_empty_terrains);
3399}
3400
3401void TileMap::set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
3402 TILEMAP_CALL_FOR_LAYER(p_layer, set_cells_terrain_connect, p_cells, p_terrain_set, p_terrain, p_ignore_empty_terrains);
3403}
3404
3405void TileMap::set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
3406 TILEMAP_CALL_FOR_LAYER(p_layer, set_cells_terrain_path, p_path, p_terrain_set, p_terrain, p_ignore_empty_terrains);
3407}
3408
3409TileMapCell TileMap::get_cell(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
3410 TILEMAP_CALL_FOR_LAYER_V(p_layer, TileMapCell(), get_cell, p_coords, p_use_proxies);
3411}
3412
3413Vector2i TileMap::get_coords_for_body_rid(RID p_physics_body) {
3414 for (const Ref<TileMapLayer> &layer : layers) {
3415 if (layer->has_body_rid(p_physics_body)) {
3416 return layer->get_coords_for_body_rid(p_physics_body);
3417 }
3418 }
3419 ERR_FAIL_V_MSG(Vector2i(), vformat("No tiles for the given body RID %d.", p_physics_body.get_id()));
3420}
3421
3422int TileMap::get_layer_for_body_rid(RID p_physics_body) {
3423 for (unsigned int i = 0; i < layers.size(); i++) {
3424 if (layers[i]->has_body_rid(p_physics_body)) {
3425 return i;
3426 }
3427 }
3428 ERR_FAIL_V_MSG(-1, vformat("No tiles for the given body RID %d.", p_physics_body.get_id()));
3429}
3430
3431void TileMap::fix_invalid_tiles() {
3432 for (Ref<TileMapLayer> &layer : layers) {
3433 layer->fix_invalid_tiles();
3434 }
3435}
3436
3437void TileMap::clear_layer(int p_layer) {
3438 TILEMAP_CALL_FOR_LAYER(p_layer, clear)
3439}
3440
3441void TileMap::clear() {
3442 for (Ref<TileMapLayer> &layer : layers) {
3443 layer->clear();
3444 }
3445}
3446
3447void TileMap::update_internals() {
3448 pending_update = true;
3449 _internal_update();
3450}
3451
3452void TileMap::notify_runtime_tile_data_update(int p_layer) {
3453 if (p_layer >= 0) {
3454 TILEMAP_CALL_FOR_LAYER(p_layer, notify_tile_map_change, TileMapLayer::DIRTY_FLAGS_TILE_MAP_RUNTIME_UPDATE);
3455 } else {
3456 for (Ref<TileMapLayer> &layer : layers) {
3457 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_RUNTIME_UPDATE);
3458 }
3459 }
3460}
3461
3462#ifdef TOOLS_ENABLED
3463Rect2 TileMap::_edit_get_rect() const {
3464 // Return the visible rect of the tilemap.
3465 if (layers.is_empty()) {
3466 return Rect2();
3467 }
3468
3469 bool any_changed = false;
3470 bool changed = false;
3471 Rect2 rect = layers[0]->get_rect(changed);
3472 any_changed |= changed;
3473 for (unsigned int i = 1; i < layers.size(); i++) {
3474 rect = rect.merge(layers[i]->get_rect(changed));
3475 any_changed |= changed;
3476 }
3477 const_cast<TileMap *>(this)->item_rect_changed(any_changed);
3478 return rect;
3479}
3480#endif
3481
3482PackedVector2Array TileMap::_get_transformed_vertices(const PackedVector2Array &p_vertices, int p_alternative_id) {
3483 const Vector2 *r = p_vertices.ptr();
3484 int size = p_vertices.size();
3485
3486 PackedVector2Array new_points;
3487 new_points.resize(size);
3488 Vector2 *w = new_points.ptrw();
3489
3490 bool flip_h = (p_alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H);
3491 bool flip_v = (p_alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V);
3492 bool transpose = (p_alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
3493
3494 for (int i = 0; i < size; i++) {
3495 Vector2 v;
3496 if (transpose) {
3497 v = Vector2(r[i].y, r[i].x);
3498 } else {
3499 v = r[i];
3500 }
3501
3502 if (flip_h) {
3503 v.x *= -1;
3504 }
3505 if (flip_v) {
3506 v.y *= -1;
3507 }
3508 w[i] = v;
3509 }
3510 return new_points;
3511}
3512
3513bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
3514 Vector<String> components = String(p_name).split("/", true, 2);
3515 if (p_name == "format") {
3516 if (p_value.get_type() == Variant::INT) {
3517 format = (TileMapLayer::DataFormat)(p_value.operator int64_t()); // Set format used for loading.
3518 return true;
3519 }
3520#ifndef DISABLE_DEPRECATED
3521 } else if (p_name == "tile_data") { // Kept for compatibility reasons.
3522 if (p_value.is_array()) {
3523 if (layers.size() == 0) {
3524 Ref<TileMapLayer> new_layer;
3525 new_layer.instantiate();
3526 new_layer->set_tile_map(this);
3527 new_layer->set_layer_index_in_tile_map_node(0);
3528 layers.push_back(new_layer);
3529 }
3530 layers[0]->set_tile_data(format, p_value);
3531 emit_signal(CoreStringNames::get_singleton()->changed);
3532 return true;
3533 }
3534 return false;
3535 } else if (p_name == "rendering_quadrant_size") {
3536 set_rendering_quadrant_size(p_value);
3537#endif // DISABLE_DEPRECATED
3538 } else if (components.size() == 2 && components[0].begins_with("layer_") && components[0].trim_prefix("layer_").is_valid_int()) {
3539 int index = components[0].trim_prefix("layer_").to_int();
3540 if (index < 0) {
3541 return false;
3542 }
3543
3544 if (index >= (int)layers.size()) {
3545 while (index >= (int)layers.size()) {
3546 Ref<TileMapLayer> new_layer;
3547 new_layer.instantiate();
3548 new_layer->set_tile_map(this);
3549 new_layer->set_layer_index_in_tile_map_node(index);
3550 layers.push_back(new_layer);
3551 }
3552
3553 notify_property_list_changed();
3554 emit_signal(CoreStringNames::get_singleton()->changed);
3555 update_configuration_warnings();
3556 }
3557
3558 if (components[1] == "name") {
3559 set_layer_name(index, p_value);
3560 return true;
3561 } else if (components[1] == "enabled") {
3562 set_layer_enabled(index, p_value);
3563 return true;
3564 } else if (components[1] == "modulate") {
3565 set_layer_modulate(index, p_value);
3566 return true;
3567 } else if (components[1] == "y_sort_enabled") {
3568 set_layer_y_sort_enabled(index, p_value);
3569 return true;
3570 } else if (components[1] == "y_sort_origin") {
3571 set_layer_y_sort_origin(index, p_value);
3572 return true;
3573 } else if (components[1] == "z_index") {
3574 set_layer_z_index(index, p_value);
3575 return true;
3576 } else if (components[1] == "tile_data") {
3577 layers[index]->set_tile_data(format, p_value);
3578 emit_signal(CoreStringNames::get_singleton()->changed);
3579 return true;
3580 } else {
3581 return false;
3582 }
3583 }
3584 return false;
3585}
3586
3587bool TileMap::_get(const StringName &p_name, Variant &r_ret) const {
3588 Vector<String> components = String(p_name).split("/", true, 2);
3589 if (p_name == "format") {
3590 r_ret = TileMapLayer::FORMAT_MAX - 1; // When saving, always save highest format.
3591 return true;
3592 } else if (components.size() == 2 && components[0].begins_with("layer_") && components[0].trim_prefix("layer_").is_valid_int()) {
3593 int index = components[0].trim_prefix("layer_").to_int();
3594 if (index < 0 || index >= (int)layers.size()) {
3595 return false;
3596 }
3597
3598 if (components[1] == "name") {
3599 r_ret = get_layer_name(index);
3600 return true;
3601 } else if (components[1] == "enabled") {
3602 r_ret = is_layer_enabled(index);
3603 return true;
3604 } else if (components[1] == "modulate") {
3605 r_ret = get_layer_modulate(index);
3606 return true;
3607 } else if (components[1] == "y_sort_enabled") {
3608 r_ret = is_layer_y_sort_enabled(index);
3609 return true;
3610 } else if (components[1] == "y_sort_origin") {
3611 r_ret = get_layer_y_sort_origin(index);
3612 return true;
3613 } else if (components[1] == "z_index") {
3614 r_ret = get_layer_z_index(index);
3615 return true;
3616 } else if (components[1] == "tile_data") {
3617 r_ret = layers[index]->get_tile_data();
3618 return true;
3619 } else {
3620 return false;
3621 }
3622 }
3623 return false;
3624}
3625
3626void TileMap::_get_property_list(List<PropertyInfo> *p_list) const {
3627 p_list->push_back(PropertyInfo(Variant::INT, "format", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
3628 p_list->push_back(PropertyInfo(Variant::NIL, "Layers", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
3629 for (unsigned int i = 0; i < layers.size(); i++) {
3630 p_list->push_back(PropertyInfo(Variant::STRING, vformat("layer_%d/name", i), PROPERTY_HINT_NONE));
3631 p_list->push_back(PropertyInfo(Variant::BOOL, vformat("layer_%d/enabled", i), PROPERTY_HINT_NONE));
3632 p_list->push_back(PropertyInfo(Variant::COLOR, vformat("layer_%d/modulate", i), PROPERTY_HINT_NONE));
3633 p_list->push_back(PropertyInfo(Variant::BOOL, vformat("layer_%d/y_sort_enabled", i), PROPERTY_HINT_NONE));
3634 p_list->push_back(PropertyInfo(Variant::INT, vformat("layer_%d/y_sort_origin", i), PROPERTY_HINT_NONE, "suffix:px"));
3635 p_list->push_back(PropertyInfo(Variant::INT, vformat("layer_%d/z_index", i), PROPERTY_HINT_NONE));
3636 p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("layer_%d/tile_data", i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
3637 }
3638}
3639
3640Vector2 TileMap::map_to_local(const Vector2i &p_pos) const {
3641 // SHOULD RETURN THE CENTER OF THE CELL.
3642 ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2());
3643
3644 Vector2 ret = p_pos;
3645 TileSet::TileShape tile_shape = tile_set->get_tile_shape();
3646 TileSet::TileOffsetAxis tile_offset_axis = tile_set->get_tile_offset_axis();
3647
3648 if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
3649 // Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap.
3650 // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap.
3651 if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
3652 switch (tile_set->get_tile_layout()) {
3653 case TileSet::TILE_LAYOUT_STACKED:
3654 ret = Vector2(ret.x + (Math::posmod(ret.y, 2) == 0 ? 0.0 : 0.5), ret.y);
3655 break;
3656 case TileSet::TILE_LAYOUT_STACKED_OFFSET:
3657 ret = Vector2(ret.x + (Math::posmod(ret.y, 2) == 1 ? 0.0 : 0.5), ret.y);
3658 break;
3659 case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
3660 ret = Vector2(ret.x + ret.y / 2, ret.y);
3661 break;
3662 case TileSet::TILE_LAYOUT_STAIRS_DOWN:
3663 ret = Vector2(ret.x / 2, ret.y * 2 + ret.x);
3664 break;
3665 case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
3666 ret = Vector2((ret.x + ret.y) / 2, ret.y - ret.x);
3667 break;
3668 case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
3669 ret = Vector2((ret.x - ret.y) / 2, ret.y + ret.x);
3670 break;
3671 }
3672 } else { // TILE_OFFSET_AXIS_VERTICAL.
3673 switch (tile_set->get_tile_layout()) {
3674 case TileSet::TILE_LAYOUT_STACKED:
3675 ret = Vector2(ret.x, ret.y + (Math::posmod(ret.x, 2) == 0 ? 0.0 : 0.5));
3676 break;
3677 case TileSet::TILE_LAYOUT_STACKED_OFFSET:
3678 ret = Vector2(ret.x, ret.y + (Math::posmod(ret.x, 2) == 1 ? 0.0 : 0.5));
3679 break;
3680 case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
3681 ret = Vector2(ret.x * 2 + ret.y, ret.y / 2);
3682 break;
3683 case TileSet::TILE_LAYOUT_STAIRS_DOWN:
3684 ret = Vector2(ret.x, ret.y + ret.x / 2);
3685 break;
3686 case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
3687 ret = Vector2(ret.x + ret.y, (ret.y - ret.x) / 2);
3688 break;
3689 case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
3690 ret = Vector2(ret.x - ret.y, (ret.y + ret.x) / 2);
3691 break;
3692 }
3693 }
3694 }
3695
3696 // Multiply by the overlapping ratio.
3697 double overlapping_ratio = 1.0;
3698 if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
3699 if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
3700 overlapping_ratio = 0.5;
3701 } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
3702 overlapping_ratio = 0.75;
3703 }
3704 ret.y *= overlapping_ratio;
3705 } else { // TILE_OFFSET_AXIS_VERTICAL.
3706 if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
3707 overlapping_ratio = 0.5;
3708 } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
3709 overlapping_ratio = 0.75;
3710 }
3711 ret.x *= overlapping_ratio;
3712 }
3713
3714 return (ret + Vector2(0.5, 0.5)) * tile_set->get_tile_size();
3715}
3716
3717Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const {
3718 ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2i());
3719
3720 Vector2 ret = p_local_position;
3721 ret /= tile_set->get_tile_size();
3722
3723 TileSet::TileShape tile_shape = tile_set->get_tile_shape();
3724 TileSet::TileOffsetAxis tile_offset_axis = tile_set->get_tile_offset_axis();
3725 TileSet::TileLayout tile_layout = tile_set->get_tile_layout();
3726
3727 // Divide by the overlapping ratio.
3728 double overlapping_ratio = 1.0;
3729 if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
3730 if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
3731 overlapping_ratio = 0.5;
3732 } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
3733 overlapping_ratio = 0.75;
3734 }
3735 ret.y /= overlapping_ratio;
3736 } else { // TILE_OFFSET_AXIS_VERTICAL.
3737 if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
3738 overlapping_ratio = 0.5;
3739 } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
3740 overlapping_ratio = 0.75;
3741 }
3742 ret.x /= overlapping_ratio;
3743 }
3744
3745 // For each half-offset shape, we check if we are in the corner of the tile, and thus should correct the local position accordingly.
3746 if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
3747 // Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap.
3748 // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap.
3749 if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
3750 // Smart floor of the position
3751 Vector2 raw_pos = ret;
3752 if (Math::posmod(Math::floor(ret.y), 2) ^ (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET)) {
3753 ret = Vector2(Math::floor(ret.x + 0.5) - 0.5, Math::floor(ret.y));
3754 } else {
3755 ret = ret.floor();
3756 }
3757
3758 // Compute the tile offset, and if we might the output for a neighbor top tile.
3759 Vector2 in_tile_pos = raw_pos - ret;
3760 bool in_top_left_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(-0.5, 1.0 / overlapping_ratio - 1)) <= 0;
3761 bool in_top_right_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(0.5, 1.0 / overlapping_ratio - 1)) > 0;
3762
3763 switch (tile_layout) {
3764 case TileSet::TILE_LAYOUT_STACKED:
3765 ret = ret.floor();
3766 if (in_top_left_triangle) {
3767 ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 0 : -1, -1);
3768 } else if (in_top_right_triangle) {
3769 ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 1 : 0, -1);
3770 }
3771 break;
3772 case TileSet::TILE_LAYOUT_STACKED_OFFSET:
3773 ret = ret.floor();
3774 if (in_top_left_triangle) {
3775 ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? -1 : 0, -1);
3776 } else if (in_top_right_triangle) {
3777 ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 0 : 1, -1);
3778 }
3779 break;
3780 case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
3781 ret = Vector2(ret.x - ret.y / 2, ret.y).floor();
3782 if (in_top_left_triangle) {
3783 ret += Vector2i(0, -1);
3784 } else if (in_top_right_triangle) {
3785 ret += Vector2i(1, -1);
3786 }
3787 break;
3788 case TileSet::TILE_LAYOUT_STAIRS_DOWN:
3789 ret = Vector2(ret.x * 2, ret.y / 2 - ret.x).floor();
3790 if (in_top_left_triangle) {
3791 ret += Vector2i(-1, 0);
3792 } else if (in_top_right_triangle) {
3793 ret += Vector2i(1, -1);
3794 }
3795 break;
3796 case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
3797 ret = Vector2(ret.x - ret.y / 2, ret.y / 2 + ret.x).floor();
3798 if (in_top_left_triangle) {
3799 ret += Vector2i(0, -1);
3800 } else if (in_top_right_triangle) {
3801 ret += Vector2i(1, 0);
3802 }
3803 break;
3804 case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
3805 ret = Vector2(ret.x + ret.y / 2, ret.y / 2 - ret.x).floor();
3806 if (in_top_left_triangle) {
3807 ret += Vector2i(-1, 0);
3808 } else if (in_top_right_triangle) {
3809 ret += Vector2i(0, -1);
3810 }
3811 break;
3812 }
3813 } else { // TILE_OFFSET_AXIS_VERTICAL.
3814 // Smart floor of the position.
3815 Vector2 raw_pos = ret;
3816 if (Math::posmod(Math::floor(ret.x), 2) ^ (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET)) {
3817 ret = Vector2(Math::floor(ret.x), Math::floor(ret.y + 0.5) - 0.5);
3818 } else {
3819 ret = ret.floor();
3820 }
3821
3822 // Compute the tile offset, and if we might the output for a neighbor top tile.
3823 Vector2 in_tile_pos = raw_pos - ret;
3824 bool in_top_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, -0.5)) > 0;
3825 bool in_bottom_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, 0.5)) <= 0;
3826
3827 switch (tile_layout) {
3828 case TileSet::TILE_LAYOUT_STACKED:
3829 ret = ret.floor();
3830 if (in_top_left_triangle) {
3831 ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 0 : -1);
3832 } else if (in_bottom_left_triangle) {
3833 ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 1 : 0);
3834 }
3835 break;
3836 case TileSet::TILE_LAYOUT_STACKED_OFFSET:
3837 ret = ret.floor();
3838 if (in_top_left_triangle) {
3839 ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? -1 : 0);
3840 } else if (in_bottom_left_triangle) {
3841 ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 0 : 1);
3842 }
3843 break;
3844 case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
3845 ret = Vector2(ret.x / 2 - ret.y, ret.y * 2).floor();
3846 if (in_top_left_triangle) {
3847 ret += Vector2i(0, -1);
3848 } else if (in_bottom_left_triangle) {
3849 ret += Vector2i(-1, 1);
3850 }
3851 break;
3852 case TileSet::TILE_LAYOUT_STAIRS_DOWN:
3853 ret = Vector2(ret.x, ret.y - ret.x / 2).floor();
3854 if (in_top_left_triangle) {
3855 ret += Vector2i(-1, 0);
3856 } else if (in_bottom_left_triangle) {
3857 ret += Vector2i(-1, 1);
3858 }
3859 break;
3860 case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
3861 ret = Vector2(ret.x / 2 - ret.y, ret.y + ret.x / 2).floor();
3862 if (in_top_left_triangle) {
3863 ret += Vector2i(0, -1);
3864 } else if (in_bottom_left_triangle) {
3865 ret += Vector2i(-1, 0);
3866 }
3867 break;
3868 case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
3869 ret = Vector2(ret.x / 2 + ret.y, ret.y - ret.x / 2).floor();
3870 if (in_top_left_triangle) {
3871 ret += Vector2i(-1, 0);
3872 } else if (in_bottom_left_triangle) {
3873 ret += Vector2i(0, 1);
3874 }
3875 break;
3876 }
3877 }
3878 } else {
3879 ret = (ret + Vector2(0.00005, 0.00005)).floor();
3880 }
3881 return Vector2i(ret);
3882}
3883
3884bool TileMap::is_existing_neighbor(TileSet::CellNeighbor p_cell_neighbor) const {
3885 ERR_FAIL_COND_V(!tile_set.is_valid(), false);
3886
3887 TileSet::TileShape shape = tile_set->get_tile_shape();
3888 if (shape == TileSet::TILE_SHAPE_SQUARE) {
3889 return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
3890 p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER ||
3891 p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE ||
3892 p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER ||
3893 p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE ||
3894 p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER ||
3895 p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE ||
3896 p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
3897
3898 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
3899 return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER ||
3900 p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
3901 p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER ||
3902 p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
3903 p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER ||
3904 p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
3905 p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER ||
3906 p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
3907 } else {
3908 if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
3909 return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
3910 p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
3911 p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
3912 p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE ||
3913 p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
3914 p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
3915 } else {
3916 return p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
3917 p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE ||
3918 p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
3919 p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
3920 p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE ||
3921 p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
3922 }
3923 }
3924}
3925
3926Vector2i TileMap::get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const {
3927 ERR_FAIL_COND_V(!tile_set.is_valid(), p_coords);
3928
3929 TileSet::TileShape shape = tile_set->get_tile_shape();
3930 if (shape == TileSet::TILE_SHAPE_SQUARE) {
3931 switch (p_cell_neighbor) {
3932 case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
3933 return p_coords + Vector2i(1, 0);
3934 case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
3935 return p_coords + Vector2i(1, 1);
3936 case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
3937 return p_coords + Vector2i(0, 1);
3938 case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
3939 return p_coords + Vector2i(-1, 1);
3940 case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
3941 return p_coords + Vector2i(-1, 0);
3942 case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
3943 return p_coords + Vector2i(-1, -1);
3944 case TileSet::CELL_NEIGHBOR_TOP_SIDE:
3945 return p_coords + Vector2i(0, -1);
3946 case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
3947 return p_coords + Vector2i(1, -1);
3948 default:
3949 ERR_FAIL_V(p_coords);
3950 }
3951 } else { // Half-offset shapes (square and hexagon).
3952 switch (tile_set->get_tile_layout()) {
3953 case TileSet::TILE_LAYOUT_STACKED: {
3954 if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
3955 bool is_offset = p_coords.y % 2;
3956 if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
3957 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
3958 return p_coords + Vector2i(1, 0);
3959 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
3960 return p_coords + Vector2i(is_offset ? 1 : 0, 1);
3961 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
3962 return p_coords + Vector2i(0, 2);
3963 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
3964 return p_coords + Vector2i(is_offset ? 0 : -1, 1);
3965 } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
3966 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
3967 return p_coords + Vector2i(-1, 0);
3968 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
3969 return p_coords + Vector2i(is_offset ? 0 : -1, -1);
3970 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
3971 return p_coords + Vector2i(0, -2);
3972 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
3973 return p_coords + Vector2i(is_offset ? 1 : 0, -1);
3974 } else {
3975 ERR_FAIL_V(p_coords);
3976 }
3977 } else {
3978 bool is_offset = p_coords.x % 2;
3979
3980 if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
3981 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
3982 return p_coords + Vector2i(0, 1);
3983 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
3984 return p_coords + Vector2i(1, is_offset ? 1 : 0);
3985 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
3986 return p_coords + Vector2i(2, 0);
3987 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
3988 return p_coords + Vector2i(1, is_offset ? 0 : -1);
3989 } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
3990 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
3991 return p_coords + Vector2i(0, -1);
3992 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
3993 return p_coords + Vector2i(-1, is_offset ? 0 : -1);
3994 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
3995 return p_coords + Vector2i(-2, 0);
3996 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
3997 return p_coords + Vector2i(-1, is_offset ? 1 : 0);
3998 } else {
3999 ERR_FAIL_V(p_coords);
4000 }
4001 }
4002 } break;
4003 case TileSet::TILE_LAYOUT_STACKED_OFFSET: {
4004 if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
4005 bool is_offset = p_coords.y % 2;
4006
4007 if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
4008 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
4009 return p_coords + Vector2i(1, 0);
4010 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
4011 return p_coords + Vector2i(is_offset ? 0 : 1, 1);
4012 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
4013 return p_coords + Vector2i(0, 2);
4014 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
4015 return p_coords + Vector2i(is_offset ? -1 : 0, 1);
4016 } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
4017 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
4018 return p_coords + Vector2i(-1, 0);
4019 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
4020 return p_coords + Vector2i(is_offset ? -1 : 0, -1);
4021 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
4022 return p_coords + Vector2i(0, -2);
4023 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
4024 return p_coords + Vector2i(is_offset ? 0 : 1, -1);
4025 } else {
4026 ERR_FAIL_V(p_coords);
4027 }
4028 } else {
4029 bool is_offset = p_coords.x % 2;
4030
4031 if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
4032 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
4033 return p_coords + Vector2i(0, 1);
4034 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
4035 return p_coords + Vector2i(1, is_offset ? 0 : 1);
4036 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
4037 return p_coords + Vector2i(2, 0);
4038 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
4039 return p_coords + Vector2i(1, is_offset ? -1 : 0);
4040 } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
4041 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
4042 return p_coords + Vector2i(0, -1);
4043 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
4044 return p_coords + Vector2i(-1, is_offset ? -1 : 0);
4045 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
4046 return p_coords + Vector2i(-2, 0);
4047 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
4048 return p_coords + Vector2i(-1, is_offset ? 0 : 1);
4049 } else {
4050 ERR_FAIL_V(p_coords);
4051 }
4052 }
4053 } break;
4054 case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
4055 case TileSet::TILE_LAYOUT_STAIRS_DOWN: {
4056 if ((tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
4057 if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
4058 if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
4059 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
4060 return p_coords + Vector2i(1, 0);
4061 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
4062 return p_coords + Vector2i(0, 1);
4063 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
4064 return p_coords + Vector2i(-1, 2);
4065 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
4066 return p_coords + Vector2i(-1, 1);
4067 } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
4068 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
4069 return p_coords + Vector2i(-1, 0);
4070 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
4071 return p_coords + Vector2i(0, -1);
4072 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
4073 return p_coords + Vector2i(1, -2);
4074 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
4075 return p_coords + Vector2i(1, -1);
4076 } else {
4077 ERR_FAIL_V(p_coords);
4078 }
4079
4080 } else {
4081 if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
4082 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
4083 return p_coords + Vector2i(0, 1);
4084 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
4085 return p_coords + Vector2i(1, 0);
4086 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
4087 return p_coords + Vector2i(2, -1);
4088 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
4089 return p_coords + Vector2i(1, -1);
4090 } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
4091 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
4092 return p_coords + Vector2i(0, -1);
4093 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
4094 return p_coords + Vector2i(-1, 0);
4095 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
4096 return p_coords + Vector2i(-2, 1);
4097
4098 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
4099 return p_coords + Vector2i(-1, 1);
4100 } else {
4101 ERR_FAIL_V(p_coords);
4102 }
4103 }
4104 } else {
4105 if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
4106 if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
4107 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
4108 return p_coords + Vector2i(2, -1);
4109 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
4110 return p_coords + Vector2i(1, 0);
4111 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
4112 return p_coords + Vector2i(0, 1);
4113 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
4114 return p_coords + Vector2i(-1, 1);
4115 } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
4116 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
4117 return p_coords + Vector2i(-2, 1);
4118 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
4119 return p_coords + Vector2i(-1, 0);
4120 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
4121 return p_coords + Vector2i(0, -1);
4122 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
4123 return p_coords + Vector2i(1, -1);
4124 } else {
4125 ERR_FAIL_V(p_coords);
4126 }
4127
4128 } else {
4129 if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
4130 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
4131 return p_coords + Vector2i(-1, 2);
4132 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
4133 return p_coords + Vector2i(0, 1);
4134 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
4135 return p_coords + Vector2i(1, 0);
4136 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
4137 return p_coords + Vector2i(1, -1);
4138 } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
4139 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
4140 return p_coords + Vector2i(1, -2);
4141 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
4142 return p_coords + Vector2i(0, -1);
4143 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
4144 return p_coords + Vector2i(-1, 0);
4145
4146 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
4147 return p_coords + Vector2i(-1, 1);
4148 } else {
4149 ERR_FAIL_V(p_coords);
4150 }
4151 }
4152 }
4153 } break;
4154 case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
4155 case TileSet::TILE_LAYOUT_DIAMOND_DOWN: {
4156 if ((tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
4157 if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
4158 if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
4159 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
4160 return p_coords + Vector2i(1, 1);
4161 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
4162 return p_coords + Vector2i(0, 1);
4163 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
4164 return p_coords + Vector2i(-1, 1);
4165 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
4166 return p_coords + Vector2i(-1, 0);
4167 } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
4168 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
4169 return p_coords + Vector2i(-1, -1);
4170 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
4171 return p_coords + Vector2i(0, -1);
4172 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
4173 return p_coords + Vector2i(1, -1);
4174 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
4175 return p_coords + Vector2i(1, 0);
4176 } else {
4177 ERR_FAIL_V(p_coords);
4178 }
4179
4180 } else {
4181 if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
4182 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
4183 return p_coords + Vector2i(1, 1);
4184 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
4185 return p_coords + Vector2i(1, 0);
4186 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
4187 return p_coords + Vector2i(1, -1);
4188 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
4189 return p_coords + Vector2i(0, -1);
4190 } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
4191 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
4192 return p_coords + Vector2i(-1, -1);
4193 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
4194 return p_coords + Vector2i(-1, 0);
4195 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
4196 return p_coords + Vector2i(-1, 1);
4197
4198 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
4199 return p_coords + Vector2i(0, 1);
4200 } else {
4201 ERR_FAIL_V(p_coords);
4202 }
4203 }
4204 } else {
4205 if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
4206 if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
4207 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
4208 return p_coords + Vector2i(1, -1);
4209 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
4210 return p_coords + Vector2i(1, 0);
4211 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
4212 return p_coords + Vector2i(1, 1);
4213 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
4214 return p_coords + Vector2i(0, 1);
4215 } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
4216 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
4217 return p_coords + Vector2i(-1, 1);
4218 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
4219 return p_coords + Vector2i(-1, 0);
4220 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
4221 return p_coords + Vector2i(-1, -1);
4222 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
4223 return p_coords + Vector2i(0, -1);
4224 } else {
4225 ERR_FAIL_V(p_coords);
4226 }
4227
4228 } else {
4229 if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
4230 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
4231 return p_coords + Vector2i(-1, 1);
4232 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
4233 return p_coords + Vector2i(0, 1);
4234 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
4235 return p_coords + Vector2i(1, 1);
4236 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
4237 return p_coords + Vector2i(1, 0);
4238 } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
4239 (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
4240 return p_coords + Vector2i(1, -1);
4241 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
4242 return p_coords + Vector2i(0, -1);
4243 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
4244 return p_coords + Vector2i(-1, -1);
4245
4246 } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
4247 return p_coords + Vector2i(-1, 0);
4248 } else {
4249 ERR_FAIL_V(p_coords);
4250 }
4251 }
4252 }
4253 } break;
4254 default:
4255 ERR_FAIL_V(p_coords);
4256 }
4257 }
4258}
4259
4260TypedArray<Vector2i> TileMap::get_used_cells(int p_layer) const {
4261 TILEMAP_CALL_FOR_LAYER_V(p_layer, TypedArray<Vector2i>(), get_used_cells);
4262}
4263
4264TypedArray<Vector2i> TileMap::get_used_cells_by_id(int p_layer, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) const {
4265 TILEMAP_CALL_FOR_LAYER_V(p_layer, TypedArray<Vector2i>(), get_used_cells_by_id, p_source_id, p_atlas_coords, p_alternative_tile);
4266}
4267
4268Rect2i TileMap::get_used_rect() const {
4269 // Return the visible rect of the tilemap.
4270 bool first = true;
4271 Rect2i rect = Rect2i();
4272 for (const Ref<TileMapLayer> &layer : layers) {
4273 Rect2i layer_rect = layer->get_used_rect();
4274 if (layer_rect == Rect2i()) {
4275 continue;
4276 }
4277 if (first) {
4278 rect = layer_rect;
4279 first = false;
4280 } else {
4281 rect = rect.merge(layer_rect);
4282 }
4283 }
4284 return rect;
4285}
4286
4287// --- Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems ---
4288
4289void TileMap::set_light_mask(int p_light_mask) {
4290 // Occlusion: set light mask.
4291 CanvasItem::set_light_mask(p_light_mask);
4292 for (Ref<TileMapLayer> &layer : layers) {
4293 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_LIGHT_MASK);
4294 }
4295}
4296
4297void TileMap::set_material(const Ref<Material> &p_material) {
4298 // Set material for the whole tilemap.
4299 CanvasItem::set_material(p_material);
4300
4301 // Update material for the whole tilemap.
4302 for (Ref<TileMapLayer> &layer : layers) {
4303 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_MATERIAL);
4304 }
4305}
4306
4307void TileMap::set_use_parent_material(bool p_use_parent_material) {
4308 // Set use_parent_material for the whole tilemap.
4309 CanvasItem::set_use_parent_material(p_use_parent_material);
4310
4311 // Update use_parent_material for the whole tilemap.
4312 for (Ref<TileMapLayer> &layer : layers) {
4313 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_USE_PARENT_MATERIAL);
4314 }
4315}
4316
4317void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
4318 // Set a default texture filter for the whole tilemap.
4319 CanvasItem::set_texture_filter(p_texture_filter);
4320 for (Ref<TileMapLayer> &layer : layers) {
4321 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_TEXTURE_FILTER);
4322 }
4323}
4324
4325void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
4326 // Set a default texture repeat for the whole tilemap.
4327 CanvasItem::set_texture_repeat(p_texture_repeat);
4328 for (Ref<TileMapLayer> &layer : layers) {
4329 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT);
4330 }
4331}
4332
4333TypedArray<Vector2i> TileMap::get_surrounding_cells(const Vector2i &coords) {
4334 if (!tile_set.is_valid()) {
4335 return TypedArray<Vector2i>();
4336 }
4337
4338 TypedArray<Vector2i> around;
4339 TileSet::TileShape shape = tile_set->get_tile_shape();
4340 if (shape == TileSet::TILE_SHAPE_SQUARE) {
4341 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE));
4342 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE));
4343 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_LEFT_SIDE));
4344 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_SIDE));
4345 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
4346 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE));
4347 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE));
4348 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE));
4349 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE));
4350 } else {
4351 if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
4352 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE));
4353 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE));
4354 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE));
4355 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_LEFT_SIDE));
4356 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE));
4357 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE));
4358 } else {
4359 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE));
4360 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE));
4361 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE));
4362 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE));
4363 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_SIDE));
4364 around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE));
4365 }
4366 }
4367
4368 return around;
4369}
4370
4371void TileMap::draw_cells_outline(Control *p_control, const RBSet<Vector2i> &p_cells, Color p_color, Transform2D p_transform) {
4372 if (!tile_set.is_valid()) {
4373 return;
4374 }
4375
4376 // Create a set.
4377 Vector2i tile_size = tile_set->get_tile_size();
4378 Vector<Vector2> polygon = tile_set->get_tile_shape_polygon();
4379 TileSet::TileShape shape = tile_set->get_tile_shape();
4380
4381 for (const Vector2i &E : p_cells) {
4382 Vector2 center = map_to_local(E);
4383
4384#define DRAW_SIDE_IF_NEEDED(side, polygon_index_from, polygon_index_to) \
4385 if (!p_cells.has(get_neighbor_cell(E, side))) { \
4386 Vector2 from = p_transform.xform(center + polygon[polygon_index_from] * tile_size); \
4387 Vector2 to = p_transform.xform(center + polygon[polygon_index_to] * tile_size); \
4388 p_control->draw_line(from, to, p_color); \
4389 }
4390
4391 if (shape == TileSet::TILE_SHAPE_SQUARE) {
4392 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 1, 2);
4393 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 2, 3);
4394 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 3, 0);
4395 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 0, 1);
4396 } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
4397 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 2, 3);
4398 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 1, 2);
4399 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
4400 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 3, 0);
4401 } else {
4402 if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
4403 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4);
4404 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 2, 3);
4405 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 1, 2);
4406 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
4407 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 5, 0);
4408 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 4, 5);
4409 } else {
4410 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4);
4411 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 4, 5);
4412 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 5, 0);
4413 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
4414 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 1, 2);
4415 DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 2, 3);
4416 }
4417 }
4418 }
4419#undef DRAW_SIDE_IF_NEEDED
4420}
4421
4422Ref<Resource> TileMap::get_transformed_polygon(Ref<Resource> p_polygon, int p_alternative_id) {
4423 if (!bool(p_alternative_id & (TileSetAtlasSource::TRANSFORM_FLIP_H | TileSetAtlasSource::TRANSFORM_FLIP_V | TileSetAtlasSource::TRANSFORM_TRANSPOSE))) {
4424 return p_polygon;
4425 }
4426
4427 {
4428 HashMap<Pair<Ref<Resource>, int>, Ref<Resource>, PairHash<Ref<Resource>, int>>::Iterator E = polygon_cache.find(Pair<Ref<Resource>, int>(p_polygon, p_alternative_id));
4429 if (E) {
4430 return E->value;
4431 }
4432 }
4433
4434 Ref<ConvexPolygonShape2D> col = p_polygon;
4435 if (col.is_valid()) {
4436 Ref<ConvexPolygonShape2D> ret;
4437 ret.instantiate();
4438 ret->set_points(_get_transformed_vertices(col->get_points(), p_alternative_id));
4439 polygon_cache[Pair<Ref<Resource>, int>(p_polygon, p_alternative_id)] = ret;
4440 return ret;
4441 }
4442
4443 Ref<NavigationPolygon> nav = p_polygon;
4444 if (nav.is_valid()) {
4445 PackedVector2Array new_points = _get_transformed_vertices(nav->get_vertices(), p_alternative_id);
4446 Ref<NavigationPolygon> ret;
4447 ret.instantiate();
4448 ret->set_vertices(new_points);
4449
4450 PackedInt32Array indices;
4451 indices.resize(new_points.size());
4452 int *w = indices.ptrw();
4453 for (int i = 0; i < new_points.size(); i++) {
4454 w[i] = i;
4455 }
4456 ret->add_polygon(indices);
4457 polygon_cache[Pair<Ref<Resource>, int>(p_polygon, p_alternative_id)] = ret;
4458 return ret;
4459 }
4460
4461 Ref<OccluderPolygon2D> ocd = p_polygon;
4462 if (ocd.is_valid()) {
4463 Ref<OccluderPolygon2D> ret;
4464 ret.instantiate();
4465 ret->set_polygon(_get_transformed_vertices(ocd->get_polygon(), p_alternative_id));
4466 polygon_cache[Pair<Ref<Resource>, int>(p_polygon, p_alternative_id)] = ret;
4467 return ret;
4468 }
4469
4470 return p_polygon;
4471}
4472
4473PackedStringArray TileMap::get_configuration_warnings() const {
4474 PackedStringArray warnings = Node::get_configuration_warnings();
4475
4476 // Retrieve the set of Z index values with a Y-sorted layer.
4477 RBSet<int> y_sorted_z_index;
4478 for (const Ref<TileMapLayer> &layer : layers) {
4479 if (layer->is_y_sort_enabled()) {
4480 y_sorted_z_index.insert(layer->get_z_index());
4481 }
4482 }
4483
4484 // Check if we have a non-sorted layer in a Z-index with a Y-sorted layer.
4485 for (const Ref<TileMapLayer> &layer : layers) {
4486 if (!layer->is_y_sort_enabled() && y_sorted_z_index.has(layer->get_z_index())) {
4487 warnings.push_back(RTR("A Y-sorted layer has the same Z-index value as a not Y-sorted layer.\nThis may lead to unwanted behaviors, as a layer that is not Y-sorted will be Y-sorted as a whole with tiles from Y-sorted layers."));
4488 break;
4489 }
4490 }
4491
4492 // Check if Y-sort is enabled on a layer but not on the node.
4493 if (!is_y_sort_enabled()) {
4494 for (const Ref<TileMapLayer> &layer : layers) {
4495 if (layer->is_y_sort_enabled()) {
4496 warnings.push_back(RTR("A TileMap layer is set as Y-sorted, but Y-sort is not enabled on the TileMap node itself."));
4497 break;
4498 }
4499 }
4500 }
4501
4502 // Check if we are in isometric mode without Y-sort enabled.
4503 if (tile_set.is_valid() && tile_set->get_tile_shape() == TileSet::TILE_SHAPE_ISOMETRIC) {
4504 bool warn = !is_y_sort_enabled();
4505 if (!warn) {
4506 for (const Ref<TileMapLayer> &layer : layers) {
4507 if (!layer->is_y_sort_enabled()) {
4508 warn = true;
4509 break;
4510 }
4511 }
4512 }
4513
4514 if (warn) {
4515 warnings.push_back(RTR("Isometric TileSet will likely not look as intended without Y-sort enabled for the TileMap and all of its layers."));
4516 }
4517 }
4518
4519 return warnings;
4520}
4521
4522void TileMap::_bind_methods() {
4523#ifndef DISABLE_DEPRECATED
4524 ClassDB::bind_method(D_METHOD("set_navigation_map", "layer", "map"), &TileMap::set_layer_navigation_map);
4525 ClassDB::bind_method(D_METHOD("get_navigation_map", "layer"), &TileMap::get_layer_navigation_map);
4526 ClassDB::bind_method(D_METHOD("force_update", "layer"), &TileMap::force_update, DEFVAL(-1));
4527#endif // DISABLE_DEPRECATED
4528
4529 ClassDB::bind_method(D_METHOD("set_tileset", "tileset"), &TileMap::set_tileset);
4530 ClassDB::bind_method(D_METHOD("get_tileset"), &TileMap::get_tileset);
4531
4532 ClassDB::bind_method(D_METHOD("set_rendering_quadrant_size", "size"), &TileMap::set_rendering_quadrant_size);
4533 ClassDB::bind_method(D_METHOD("get_rendering_quadrant_size"), &TileMap::get_rendering_quadrant_size);
4534
4535 ClassDB::bind_method(D_METHOD("get_layers_count"), &TileMap::get_layers_count);
4536 ClassDB::bind_method(D_METHOD("add_layer", "to_position"), &TileMap::add_layer);
4537 ClassDB::bind_method(D_METHOD("move_layer", "layer", "to_position"), &TileMap::move_layer);
4538 ClassDB::bind_method(D_METHOD("remove_layer", "layer"), &TileMap::remove_layer);
4539 ClassDB::bind_method(D_METHOD("set_layer_name", "layer", "name"), &TileMap::set_layer_name);
4540 ClassDB::bind_method(D_METHOD("get_layer_name", "layer"), &TileMap::get_layer_name);
4541 ClassDB::bind_method(D_METHOD("set_layer_enabled", "layer", "enabled"), &TileMap::set_layer_enabled);
4542 ClassDB::bind_method(D_METHOD("is_layer_enabled", "layer"), &TileMap::is_layer_enabled);
4543 ClassDB::bind_method(D_METHOD("set_layer_modulate", "layer", "modulate"), &TileMap::set_layer_modulate);
4544 ClassDB::bind_method(D_METHOD("get_layer_modulate", "layer"), &TileMap::get_layer_modulate);
4545 ClassDB::bind_method(D_METHOD("set_layer_y_sort_enabled", "layer", "y_sort_enabled"), &TileMap::set_layer_y_sort_enabled);
4546 ClassDB::bind_method(D_METHOD("is_layer_y_sort_enabled", "layer"), &TileMap::is_layer_y_sort_enabled);
4547 ClassDB::bind_method(D_METHOD("set_layer_y_sort_origin", "layer", "y_sort_origin"), &TileMap::set_layer_y_sort_origin);
4548 ClassDB::bind_method(D_METHOD("get_layer_y_sort_origin", "layer"), &TileMap::get_layer_y_sort_origin);
4549 ClassDB::bind_method(D_METHOD("set_layer_z_index", "layer", "z_index"), &TileMap::set_layer_z_index);
4550 ClassDB::bind_method(D_METHOD("get_layer_z_index", "layer"), &TileMap::get_layer_z_index);
4551 ClassDB::bind_method(D_METHOD("set_layer_navigation_map", "layer", "map"), &TileMap::set_layer_navigation_map);
4552 ClassDB::bind_method(D_METHOD("get_layer_navigation_map", "layer"), &TileMap::get_layer_navigation_map);
4553
4554 ClassDB::bind_method(D_METHOD("set_collision_animatable", "enabled"), &TileMap::set_collision_animatable);
4555 ClassDB::bind_method(D_METHOD("is_collision_animatable"), &TileMap::is_collision_animatable);
4556 ClassDB::bind_method(D_METHOD("set_collision_visibility_mode", "collision_visibility_mode"), &TileMap::set_collision_visibility_mode);
4557 ClassDB::bind_method(D_METHOD("get_collision_visibility_mode"), &TileMap::get_collision_visibility_mode);
4558
4559 ClassDB::bind_method(D_METHOD("set_navigation_visibility_mode", "navigation_visibility_mode"), &TileMap::set_navigation_visibility_mode);
4560 ClassDB::bind_method(D_METHOD("get_navigation_visibility_mode"), &TileMap::get_navigation_visibility_mode);
4561
4562 ClassDB::bind_method(D_METHOD("set_cell", "layer", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMap::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(0));
4563 ClassDB::bind_method(D_METHOD("erase_cell", "layer", "coords"), &TileMap::erase_cell);
4564 ClassDB::bind_method(D_METHOD("get_cell_source_id", "layer", "coords", "use_proxies"), &TileMap::get_cell_source_id, DEFVAL(false));
4565 ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "layer", "coords", "use_proxies"), &TileMap::get_cell_atlas_coords, DEFVAL(false));
4566 ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "layer", "coords", "use_proxies"), &TileMap::get_cell_alternative_tile, DEFVAL(false));
4567 ClassDB::bind_method(D_METHOD("get_cell_tile_data", "layer", "coords", "use_proxies"), &TileMap::get_cell_tile_data, DEFVAL(false));
4568
4569 ClassDB::bind_method(D_METHOD("get_coords_for_body_rid", "body"), &TileMap::get_coords_for_body_rid);
4570 ClassDB::bind_method(D_METHOD("get_layer_for_body_rid", "body"), &TileMap::get_layer_for_body_rid);
4571
4572 ClassDB::bind_method(D_METHOD("get_pattern", "layer", "coords_array"), &TileMap::get_pattern);
4573 ClassDB::bind_method(D_METHOD("map_pattern", "position_in_tilemap", "coords_in_pattern", "pattern"), &TileMap::map_pattern);
4574 ClassDB::bind_method(D_METHOD("set_pattern", "layer", "position", "pattern"), &TileMap::set_pattern);
4575
4576 ClassDB::bind_method(D_METHOD("set_cells_terrain_connect", "layer", "cells", "terrain_set", "terrain", "ignore_empty_terrains"), &TileMap::set_cells_terrain_connect, DEFVAL(true));
4577 ClassDB::bind_method(D_METHOD("set_cells_terrain_path", "layer", "path", "terrain_set", "terrain", "ignore_empty_terrains"), &TileMap::set_cells_terrain_path, DEFVAL(true));
4578
4579 ClassDB::bind_method(D_METHOD("fix_invalid_tiles"), &TileMap::fix_invalid_tiles);
4580 ClassDB::bind_method(D_METHOD("clear_layer", "layer"), &TileMap::clear_layer);
4581 ClassDB::bind_method(D_METHOD("clear"), &TileMap::clear);
4582
4583 ClassDB::bind_method(D_METHOD("update_internals"), &TileMap::update_internals);
4584 ClassDB::bind_method(D_METHOD("notify_runtime_tile_data_update", "layer"), &TileMap::notify_runtime_tile_data_update, DEFVAL(-1));
4585
4586 ClassDB::bind_method(D_METHOD("get_surrounding_cells", "coords"), &TileMap::get_surrounding_cells);
4587
4588 ClassDB::bind_method(D_METHOD("get_used_cells", "layer"), &TileMap::get_used_cells);
4589 ClassDB::bind_method(D_METHOD("get_used_cells_by_id", "layer", "source_id", "atlas_coords", "alternative_tile"), &TileMap::get_used_cells_by_id, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE));
4590 ClassDB::bind_method(D_METHOD("get_used_rect"), &TileMap::get_used_rect);
4591
4592 ClassDB::bind_method(D_METHOD("map_to_local", "map_position"), &TileMap::map_to_local);
4593 ClassDB::bind_method(D_METHOD("local_to_map", "local_position"), &TileMap::local_to_map);
4594
4595 ClassDB::bind_method(D_METHOD("get_neighbor_cell", "coords", "neighbor"), &TileMap::get_neighbor_cell);
4596
4597 GDVIRTUAL_BIND(_use_tile_data_runtime_update, "layer", "coords");
4598 GDVIRTUAL_BIND(_tile_data_runtime_update, "layer", "coords", "tile_data");
4599
4600 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_set", PROPERTY_HINT_RESOURCE_TYPE, "TileSet"), "set_tileset", "get_tileset");
4601 ADD_PROPERTY(PropertyInfo(Variant::INT, "rendering_quadrant_size", PROPERTY_HINT_RANGE, "1,128,1"), "set_rendering_quadrant_size", "get_rendering_quadrant_size");
4602 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_animatable"), "set_collision_animatable", "is_collision_animatable");
4603 ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_visibility_mode", PROPERTY_HINT_ENUM, "Default,Force Show,Force Hide"), "set_collision_visibility_mode", "get_collision_visibility_mode");
4604 ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_visibility_mode", PROPERTY_HINT_ENUM, "Default,Force Show,Force Hide"), "set_navigation_visibility_mode", "get_navigation_visibility_mode");
4605
4606 ADD_ARRAY("layers", "layer_");
4607
4608 ADD_PROPERTY_DEFAULT("format", TileMapLayer::FORMAT_1);
4609
4610 ADD_SIGNAL(MethodInfo(CoreStringNames::get_singleton()->changed));
4611
4612 BIND_ENUM_CONSTANT(VISIBILITY_MODE_DEFAULT);
4613 BIND_ENUM_CONSTANT(VISIBILITY_MODE_FORCE_HIDE);
4614 BIND_ENUM_CONSTANT(VISIBILITY_MODE_FORCE_SHOW);
4615}
4616
4617void TileMap::_tile_set_changed() {
4618 emit_signal(CoreStringNames::get_singleton()->changed);
4619 for (Ref<TileMapLayer> layer : layers) {
4620 layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_TILE_SET);
4621 }
4622 update_configuration_warnings();
4623}
4624
4625TileMap::TileMap() {
4626 set_notify_transform(true);
4627 set_notify_local_transform(false);
4628
4629 Ref<TileMapLayer> new_layer;
4630 new_layer.instantiate();
4631 new_layer->set_tile_map(this);
4632 new_layer->set_layer_index_in_tile_map_node(0);
4633 layers.push_back(new_layer);
4634}
4635
4636TileMap::~TileMap() {
4637 if (tile_set.is_valid()) {
4638 tile_set->disconnect_changed(callable_mp(this, &TileMap::_tile_set_changed));
4639 }
4640}
4641
4642#undef TILEMAP_CALL_FOR_LAYER
4643#undef TILEMAP_CALL_FOR_LAYER_V
4644