diff --git a/doc/classes/TileMapLayer.xml b/doc/classes/TileMapLayer.xml
index b9acef20952..957024ba29e 100644
--- a/doc/classes/TileMapLayer.xml
+++ b/doc/classes/TileMapLayer.xml
@@ -185,6 +185,19 @@
[b]Note:[/b] This does not trigger a direct update of the [TileMapLayer], the update will be done at the end of the frame as usual (unless you call [method update_internals]).
+
+
+
+
+
+
+
+ Places random tiles within a specified region.
+ The [param atlas_coords_array] is an array of [Vector4i] elements, where the first element is the source ID of the atlas, the second element is the X-index, and the third element is the Y-index for the desired atlas tile, the fourth element is the optional alternative tile to use. If the atlas source ID is a scene collection, the first element is the scene collection source ID, the next element is the scene ID within that collection, and the last two values are ignored.
+ The [param scattering_probability] is a [float] from 0 to 1 that defines the probability of placing a tile in a cell. If set to [code]0[/code], all cells in the region will be filled with a random tile from the [param atlas_coords_array].
+ The [param replace_tile] parameter defines whether to replace existing tiles in the region. If set to [code]true[/code], existing tiles will be replaced with random tiles from the [param atlas_coords_array], otherwise, no existing tiles will be replaced.
+
+
diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp
index 437790bb999..1400fe13bdd 100644
--- a/scene/2d/tile_map_layer.cpp
+++ b/scene/2d/tile_map_layer.cpp
@@ -1764,6 +1764,7 @@ void TileMapLayer::_bind_methods() {
// --- Cells manipulation ---
// Generic cells manipulations and access.
ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMapLayer::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("place_random_tiles", "atlas_coords_array", "region", "scattering_probability", "replace_tile"), &TileMapLayer::place_random_tiles);
ClassDB::bind_method(D_METHOD("erase_cell", "coords"), &TileMapLayer::erase_cell);
ClassDB::bind_method(D_METHOD("fix_invalid_tiles"), &TileMapLayer::fix_invalid_tiles);
ClassDB::bind_method(D_METHOD("clear"), &TileMapLayer::clear);
@@ -2355,6 +2356,110 @@ void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vec
used_rect_cache_dirty = true;
}
+void TileMapLayer::place_random_tiles(Array atlas_coords_array, Rect2i region, float scattering_probability, bool replace_tile) {
+ // Validate the input
+ if (atlas_coords_array.is_empty()) {
+ return;
+ }
+
+ // Initialize the maximum coordinates for the region
+ int max_x = region.position.x + region.size.x;
+ int max_y = region.position.y + region.size.y;
+
+ // Precompute the sum of probabilities and store them in a vector for quick access
+ Vector probabilities;
+ probabilities.resize(atlas_coords_array.size());
+ double sum = 0.0;
+
+ for (int i = 0; i < atlas_coords_array.size(); ++i) {
+ Vector4i tile_info = atlas_coords_array[i];
+ int source_id = tile_info.x;
+ int scene_id = tile_info.y; // Used for scene collections
+ Vector2i atlas_coords(tile_info.z, tile_info.w); // Used for 2D tile atlases
+
+ Ref source = tile_set->get_source(source_id);
+
+ // Check if the source is a TileSetAtlasSource
+ Ref atlas_source = source;
+ if (atlas_source.is_valid()) {
+ if (atlas_source->has_tile(atlas_coords)) {
+ TileData *tile_data = atlas_source->get_tile_data(atlas_coords, 0);
+ if (tile_data) {
+ sum += tile_data->get_probability();
+ probabilities.set(i, sum);
+ }
+ }
+ } else {
+ // Handle scene collections
+ Ref scenes_collection_source = source;
+ if (scenes_collection_source.is_valid()) {
+ if (scenes_collection_source->has_scene_tile_id(scene_id)) {
+ // For scene collections, we don’t need to calculate probability
+ sum += 1.0; // Treat each scene as having equal probability
+ probabilities.set(i, sum);
+ }
+ }
+ }
+ }
+
+ // Loop through each cell in the specified region
+ for (int x = region.position.x; x < max_x; ++x) {
+ for (int y = region.position.y; y < max_y; ++y) {
+ // Use the scattering value to decide whether to place a tile
+ if (Math::randf() > scattering_probability) {
+ continue; // Skip placing a tile in this cell
+ }
+
+ // Check if we should replace existing tiles
+ if (!replace_tile) {
+ int existing_source_id = get_cell_source_id(Vector2i(x, y));
+ if (existing_source_id != -1) {
+ continue; // Skip this cell if it already has a tile and we shouldn't replace it
+ }
+ }
+
+ // Generate a random number to pick a tile based on precomputed probabilities
+ double picked = Math::randf() * sum;
+ for (int i = 0; i < probabilities.size(); ++i) {
+ if (picked <= probabilities[i]) {
+ Vector4i tile_info = atlas_coords_array[i];
+ int source_id = tile_info.x;
+ int scene_id = tile_info.y; // Used for scene collections
+ Vector2i atlas_coords(tile_info.z, tile_info.w); // Used for 2D tile atlases
+
+ Ref source = tile_set->get_source(source_id);
+ Ref atlas_source = source;
+
+ if (atlas_source.is_valid()) {
+ if (atlas_source->has_tile(atlas_coords)) {
+ set_cell(Vector2i(x, y), source_id, atlas_coords, 0);
+ }
+ } else {
+ // Handle scene collections
+ Ref scenes_collection_source = source;
+ if (scenes_collection_source.is_valid()) {
+ if (scenes_collection_source->has_scene_tile_id(scene_id)) {
+ Ref scene = scenes_collection_source->get_scene_tile_scene(scene_id);
+ if (scene.is_valid()) {
+ // Create an instance of the scene
+ Node2D *node = Object::cast_to(scene->instantiate());
+ if (node) {
+ // Set the position of the node
+ Vector2 local_position = map_to_local(Vector2(x, y));
+ node->set_position(local_position);
+ add_child(node);
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
void TileMapLayer::erase_cell(const Vector2i &p_coords) {
set_cell(p_coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
}
diff --git a/scene/2d/tile_map_layer.h b/scene/2d/tile_map_layer.h
index c71f13d7beb..c1180588631 100644
--- a/scene/2d/tile_map_layer.h
+++ b/scene/2d/tile_map_layer.h
@@ -425,6 +425,7 @@ public:
// --- Cells manipulation ---
// Generic cells manipulations and data access.
void set_cell(const Vector2i &p_coords, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i &p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0);
+ void place_random_tiles(Array atlas_coords_array, Rect2i region, float scattering_probability, bool replace_tile);
void erase_cell(const Vector2i &p_coords);
void fix_invalid_tiles();
void clear();