diff options
author | Gilles Roudière <gilles.roudiere@gmail.com> | 2021-05-18 15:40:52 +0200 |
---|---|---|
committer | Gilles Roudière <gilles.roudiere@gmail.com> | 2021-05-20 13:12:03 +0200 |
commit | d8bb53cd2194fed58f1a55e60b9f1b863c6e9cc7 (patch) | |
tree | 448a1ccc61f858a3892a34e611d0af28e92a9d93 /scene | |
parent | 9004943559cdcbe4bdf455f11d9602fa377d938a (diff) |
Implement scenes tiles in TileMaps
Diffstat (limited to 'scene')
-rw-r--r-- | scene/2d/tile_map.cpp | 22 | ||||
-rw-r--r-- | scene/2d/tile_map.h | 11 | ||||
-rw-r--r-- | scene/register_scene_types.cpp | 1 | ||||
-rw-r--r-- | scene/resources/tile_set.cpp | 466 | ||||
-rw-r--r-- | scene/resources/tile_set.h | 92 |
5 files changed, 511 insertions, 81 deletions
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 0afead0863..188f8d300d 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -64,13 +64,13 @@ int TileMapPattern::get_cell_source_id(const Vector2i &p_coords) const { } Vector2i TileMapPattern::get_cell_atlas_coords(const Vector2i &p_coords) const { - ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetAtlasSource::INVALID_ATLAS_COORDS); + ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetSource::INVALID_ATLAS_COORDS); return pattern[p_coords].get_atlas_coords(); } int TileMapPattern::get_cell_alternative_tile(const Vector2i &p_coords) const { - ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetAtlasSource::INVALID_TILE_ALTERNATIVE); + ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetSource::INVALID_TILE_ALTERNATIVE); return pattern[p_coords].alternative_tile; } @@ -113,7 +113,7 @@ void TileMapPattern::clear() { }; void TileMapPattern::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMapPattern::set_cell, DEFVAL(-1), DEFVAL(TileSetAtlasSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetAtlasSource::INVALID_TILE_ALTERNATIVE)); + ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMapPattern::set_cell, DEFVAL(-1), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE)); ClassDB::bind_method(D_METHOD("has_cell", "coords"), &TileMapPattern::has_cell); ClassDB::bind_method(D_METHOD("remove_cell", "coords"), &TileMapPattern::remove_cell); ClassDB::bind_method(D_METHOD("get_cell_source_id", "coords"), &TileMapPattern::get_cell_source_id); @@ -520,12 +520,12 @@ void TileMap::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i Vector2i atlas_coords = p_atlas_coords; int alternative_tile = p_alternative_tile; - if ((source_id == -1 || atlas_coords == TileSetAtlasSource::INVALID_ATLAS_COORDS || alternative_tile == TileSetAtlasSource::INVALID_TILE_ALTERNATIVE) && - (source_id != -1 || atlas_coords != TileSetAtlasSource::INVALID_ATLAS_COORDS || alternative_tile != TileSetAtlasSource::INVALID_TILE_ALTERNATIVE)) { + if ((source_id == -1 || atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE) && + (source_id != -1 || atlas_coords != TileSetSource::INVALID_ATLAS_COORDS || alternative_tile != TileSetSource::INVALID_TILE_ALTERNATIVE)) { WARN_PRINT("Setting a cell a cell as empty requires both source_id, atlas_coord and alternative_tile to be set to their respective \"invalid\" values. Values were thus changes accordingly."); source_id = -1; - atlas_coords = TileSetAtlasSource::INVALID_ATLAS_COORDS; - alternative_tile = TileSetAtlasSource::INVALID_TILE_ALTERNATIVE; + atlas_coords = TileSetSource::INVALID_ATLAS_COORDS; + alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE; } if (!E && source_id == -1) { @@ -602,7 +602,7 @@ Vector2i TileMap::get_cell_atlas_coords(const Vector2i &p_coords) const { const Map<Vector2i, TileMapCell>::Element *E = tile_map.find(p_coords); if (!E) { - return TileSetAtlasSource::INVALID_ATLAS_COORDS; + return TileSetSource::INVALID_ATLAS_COORDS; } return E->get().get_atlas_coords(); @@ -613,7 +613,7 @@ int TileMap::get_cell_alternative_tile(const Vector2i &p_coords) const { const Map<Vector2i, TileMapCell>::Element *E = tile_map.find(p_coords); if (!E) { - return TileSetAtlasSource::INVALID_TILE_ALTERNATIVE; + return TileSetSource::INVALID_TILE_ALTERNATIVE; } return E->get().alternative_tile; @@ -721,7 +721,7 @@ void TileMap::fix_invalid_tiles() { for (Map<Vector2i, TileMapCell>::Element *E = tile_map.front(); E; E = E->next()) { TileSetSource *source = *tile_set->get_source(E->get().source_id); if (!source || !source->has_tile(E->get().get_atlas_coords()) || !source->has_alternative_tile(E->get().get_atlas_coords(), E->get().alternative_tile)) { - set_cell(E->key(), -1, TileSetAtlasSource::INVALID_ATLAS_COORDS, TileSetAtlasSource::INVALID_TILE_ALTERNATIVE); + set_cell(E->key(), -1, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); } } } @@ -1716,7 +1716,7 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_quadrant_size", "size"), &TileMap::set_quadrant_size); ClassDB::bind_method(D_METHOD("get_quadrant_size"), &TileMap::get_quadrant_size); - ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMap::set_cell, DEFVAL(-1), DEFVAL(TileSetAtlasSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetAtlasSource::INVALID_TILE_ALTERNATIVE)); + ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMap::set_cell, DEFVAL(-1), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE)); ClassDB::bind_method(D_METHOD("get_cell_source_id", "coords"), &TileMap::get_cell_source_id); ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "coords"), &TileMap::get_cell_atlas_coords); ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "coords"), &TileMap::get_cell_alternative_tile); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index e9dbccbdb9..2703e1980e 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -48,7 +48,7 @@ union TileMapCell { }; uint64_t _u64t; - TileMapCell(int p_source_id = -1, Vector2i p_atlas_coords = TileSetAtlasSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetAtlasSource::INVALID_TILE_ALTERNATIVE) { + TileMapCell(int p_source_id = -1, Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) { source_id = p_source_id; set_atlas_coords(p_atlas_coords); alternative_tile = p_alternative_tile; @@ -112,16 +112,19 @@ struct TileMapQuadrant { // Debug. RID debug_canvas_item; - // Rendering + // Rendering. List<RID> canvas_items; List<RID> occluders; // Physics. List<RID> bodies; - // Navigation + // Navigation. Map<Vector2i, Vector<RID>> navigation_regions; + // Scenes. + Map<Vector2i, String> scenes; + void operator=(const TileMapQuadrant &q) { coords = q.coords; debug_canvas_item = q.debug_canvas_item; @@ -248,7 +251,7 @@ public: void set_quadrant_size(int p_size); int get_quadrant_size() const; - void set_cell(const Vector2i &p_coords, int p_source_id = -1, const Vector2i p_atlas_coords = TileSetAtlasSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetAtlasSource::INVALID_TILE_ALTERNATIVE); + void set_cell(const Vector2i &p_coords, int p_source_id = -1, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE); int get_cell_source_id(const Vector2i &p_coords) const; Vector2i get_cell_atlas_coords(const Vector2i &p_coords) const; int get_cell_alternative_tile(const Vector2i &p_coords) const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index f24ea7e39b..b9c1659fd1 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -657,6 +657,7 @@ void register_scene_types() { ClassDB::register_class<TileSet>(); ClassDB::register_virtual_class<TileSetSource>(); ClassDB::register_class<TileSetAtlasSource>(); + ClassDB::register_class<TileSetScenesCollectionSource>(); ClassDB::register_class<TileData>(); ClassDB::register_class<TileMap>(); ClassDB::register_class<ParallaxBackground>(); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index c4b8a56f54..3cc9627af3 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -106,15 +106,15 @@ void TileSet::_compute_next_source_id() { } // Sources management -int TileSet::add_source(Ref<TileSetAtlasSource> p_tile_atlas_source, int p_atlas_source_id_override) { - ERR_FAIL_COND_V(!p_tile_atlas_source.is_valid(), -1); +int TileSet::add_source(Ref<TileSetSource> p_tile_set_source, int p_atlas_source_id_override) { + ERR_FAIL_COND_V(!p_tile_set_source.is_valid(), -1); ERR_FAIL_COND_V_MSG(p_atlas_source_id_override >= 0 && (sources.has(p_atlas_source_id_override)), -1, vformat("Cannot create TileSet atlas source. Another atlas source exists with id %d.", p_atlas_source_id_override)); int new_source_id = p_atlas_source_id_override >= 0 ? p_atlas_source_id_override : next_source_id; - sources[new_source_id] = p_tile_atlas_source; + sources[new_source_id] = p_tile_set_source; source_ids.append(new_source_id); source_ids.sort(); - p_tile_atlas_source->set_tile_set(this); + p_tile_set_source->set_tile_set(this); _compute_next_source_id(); sources[new_source_id]->connect("changed", callable_mp(this, &TileSet::_source_changed)); @@ -668,8 +668,8 @@ void TileSet::reset_state() { custom_data_layers.clear(); } -const Vector2i TileSetAtlasSource::INVALID_ATLAS_COORDS = Vector2i(-1, -1); -const int TileSetAtlasSource::INVALID_TILE_ALTERNATIVE = -1; +const Vector2i TileSetSource::INVALID_ATLAS_COORDS = Vector2i(-1, -1); +const int TileSetSource::INVALID_TILE_ALTERNATIVE = -1; #ifndef DISABLE_DEPRECATED void TileSet::compatibility_conversion() { @@ -1086,7 +1086,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { return true; } } else if (components.size() == 2 && components[0] == "sources" && components[1].is_valid_integer()) { - // Create atlas if it does not exists. + // Create source only if it does not exists. int source_id = components[1].to_int(); if (!has_source(source_id)) { @@ -1399,10 +1399,11 @@ void TileSet::_bind_methods() { TileSet::TileSet() { // Instanciatie and list all plugins. - tile_set_plugins_vector.append(memnew(TileSetAtlasPluginRendering)); - tile_set_plugins_vector.append(memnew(TileSetAtlasPluginPhysics)); - tile_set_plugins_vector.append(memnew(TileSetAtlasPluginTerrain)); - tile_set_plugins_vector.append(memnew(TileSetAtlasPluginNavigation)); + tile_set_plugins_vector.append(memnew(TileSetPluginAtlasRendering)); + tile_set_plugins_vector.append(memnew(TileSetPluginAtlasPhysics)); + tile_set_plugins_vector.append(memnew(TileSetPluginAtlasTerrain)); + tile_set_plugins_vector.append(memnew(TileSetPluginAtlasNavigation)); + tile_set_plugins_vector.append(memnew(TileSetPluginScenesCollections)); } TileSet::~TileSet() { @@ -1530,13 +1531,13 @@ bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value) // Compute the vector2i if we have coordinates. Vector<String> coords_split = components[0].split(":"); - Vector2i coords = TileSetAtlasSource::INVALID_ATLAS_COORDS; + Vector2i coords = TileSetSource::INVALID_ATLAS_COORDS; if (coords_split.size() == 2 && coords_split[0].is_valid_integer() && coords_split[1].is_valid_integer()) { coords = Vector2i(coords_split[0].to_int(), coords_split[1].to_int()); } // Properties. - if (coords != TileSetAtlasSource::INVALID_ATLAS_COORDS) { + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { // Create the tile if needed. if (!has_tile(coords)) { create_tile(coords); @@ -1549,7 +1550,7 @@ bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value) tiles[coords].next_alternative_id = p_value; } else if (components[1].is_valid_integer()) { int alternative_id = components[1].to_int(); - if (alternative_id != TileSetAtlasSource::INVALID_TILE_ALTERNATIVE) { + if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE) { // Create the alternative if needed ? if (!has_alternative_tile(coords, alternative_id)) { create_alternative_tile(coords, alternative_id); @@ -1594,7 +1595,7 @@ bool TileSetAtlasSource::_get(const StringName &p_name, Variant &r_ret) const { return true; } else if (components[1].is_valid_integer()) { int alternative_id = components[1].to_int(); - if (alternative_id != TileSetAtlasSource::INVALID_TILE_ALTERNATIVE && tiles[coords].alternatives.has(alternative_id)) { + if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE && tiles[coords].alternatives.has(alternative_id)) { if (components.size() >= 3) { bool valid; r_ret = tiles[coords].alternatives[alternative_id]->get(components[2], &valid); @@ -1745,7 +1746,7 @@ int TileSetAtlasSource::get_tiles_count() const { } Vector2i TileSetAtlasSource::get_tile_id(int p_index) const { - ERR_FAIL_INDEX_V(p_index, tiles_ids.size(), TileSetAtlasSource::INVALID_ATLAS_COORDS); + ERR_FAIL_INDEX_V(p_index, tiles_ids.size(), TileSetSource::INVALID_ATLAS_COORDS); return tiles_ids[p_index]; } @@ -1798,7 +1799,7 @@ bool TileSetAtlasSource::can_move_tile_in_atlas(Vector2i p_atlas_coords, Vector2 for (int x = new_rect.position.x; x < new_rect.get_end().x; x++) { for (int y = new_rect.position.y; y < new_rect.get_end().y; y++) { Vector2i coords = get_tile_at_coords(Vector2i(x, y)); - if (coords != p_atlas_coords && coords != TileSetAtlasSource::INVALID_ATLAS_COORDS) { + if (coords != p_atlas_coords && coords != TileSetSource::INVALID_ATLAS_COORDS) { return false; } } @@ -1880,7 +1881,7 @@ void TileSetAtlasSource::clear_tiles_outside_texture() { int TileSetAtlasSource::create_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_id_override) { ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), -1, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords))); - ERR_FAIL_COND_V_MSG(p_alternative_id_override >= 0 && (tiles[p_atlas_coords].alternatives.has(p_alternative_id_override) || tiles[p_atlas_coords].alternatives.has(p_alternative_id_override)), -1, vformat("Cannot create alternative tile. Another alternative exists with id %d.", p_alternative_id_override)); + ERR_FAIL_COND_V_MSG(p_alternative_id_override >= 0 && tiles[p_atlas_coords].alternatives.has(p_alternative_id_override), -1, vformat("Cannot create alternative tile. Another alternative exists with id %d.", p_alternative_id_override)); int new_alternative_id = p_alternative_id_override >= 0 ? p_alternative_id_override : tiles[p_atlas_coords].next_alternative_id; @@ -2034,6 +2035,202 @@ void TileSetAtlasSource::_compute_next_alternative_id(const Vector2i p_atlas_coo }; } +/////////////////////////////// TileSetScenesCollectionSource ////////////////////////////////////// + +void TileSetScenesCollectionSource::_compute_next_alternative_id() { + while (scenes.has(next_scene_id)) { + next_scene_id = (next_scene_id % 1073741823) + 1; // 2 ** 30 + }; +} + +int TileSetScenesCollectionSource::get_tiles_count() const { + return 1; +} + +Vector2i TileSetScenesCollectionSource::get_tile_id(int p_tile_index) const { + ERR_FAIL_COND_V(p_tile_index != 0, TileSetSource::INVALID_ATLAS_COORDS); + return Vector2i(); +} + +bool TileSetScenesCollectionSource::has_tile(Vector2i p_atlas_coords) const { + return p_atlas_coords == Vector2i(); +} + +int TileSetScenesCollectionSource::get_alternative_tiles_count(const Vector2i p_atlas_coords) const { + return scenes_ids.size(); +} + +int TileSetScenesCollectionSource::get_alternative_tile_id(const Vector2i p_atlas_coords, int p_index) const { + ERR_FAIL_COND_V(p_atlas_coords != Vector2i(), TileSetSource::INVALID_TILE_ALTERNATIVE); + ERR_FAIL_INDEX_V(p_index, scenes_ids.size(), TileSetSource::INVALID_TILE_ALTERNATIVE); + + return scenes_ids[p_index]; +} + +bool TileSetScenesCollectionSource::has_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) const { + ERR_FAIL_COND_V(p_atlas_coords != Vector2i(), false); + return scenes.has(p_alternative_tile); +} + +int TileSetScenesCollectionSource::create_scene_tile(Ref<PackedScene> p_packed_scene, int p_id_override) { + ERR_FAIL_COND_V_MSG(p_id_override >= 0 && scenes.has(p_id_override), -1, vformat("Cannot create scene tile. Another scene tile exists with id %d.", p_id_override)); + + int new_scene_id = p_id_override >= 0 ? p_id_override : next_scene_id; + + scenes[new_scene_id] = SceneData(); + scenes_ids.append(new_scene_id); + scenes_ids.sort(); + set_scene_tile_scene(new_scene_id, p_packed_scene); + _compute_next_alternative_id(); + + emit_signal("changed"); + + return new_scene_id; +} + +void TileSetScenesCollectionSource::set_scene_tile_id(int p_id, int p_new_id) { + ERR_FAIL_COND(p_new_id < 0); + ERR_FAIL_COND(!has_scene_tile_id(p_id)); + ERR_FAIL_COND(has_scene_tile_id(p_new_id)); + + scenes[p_new_id] = SceneData(); + scenes[p_new_id] = scenes[p_id]; + scenes_ids.append(p_new_id); + scenes_ids.sort(); + + _compute_next_alternative_id(); + + scenes.erase(p_id); + scenes_ids.erase(p_id); + + emit_signal("changed"); +} + +void TileSetScenesCollectionSource::set_scene_tile_scene(int p_id, Ref<PackedScene> p_packed_scene) { + ERR_FAIL_COND(!scenes.has(p_id)); + if (p_packed_scene.is_valid()) { + // Make sure we have a root node. Supposed to be at 0 index because find_node_by_path() does not seem to work. + ERR_FAIL_COND(!p_packed_scene->get_state().is_valid()); + ERR_FAIL_COND(p_packed_scene->get_state()->get_node_count() < 1); + + // Check if it extends CanvasItem. + String type = p_packed_scene->get_state()->get_node_type(0); + bool extends_correct_class = ClassDB::is_parent_class(type, "Control") || ClassDB::is_parent_class(type, "Node2D"); + ERR_FAIL_COND_MSG(!extends_correct_class, vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Root node should extend Control or Node2D.", p_packed_scene->get_path())); + + scenes[p_id].scene = p_packed_scene; + } else { + scenes[p_id].scene = Ref<PackedScene>(); + } + emit_signal("changed"); +} + +Ref<PackedScene> TileSetScenesCollectionSource::get_scene_tile_scene(int p_id) const { + ERR_FAIL_COND_V(!scenes.has(p_id), Ref<PackedScene>()); + return scenes[p_id].scene; +} + +void TileSetScenesCollectionSource::set_scene_tile_display_placeholder(int p_id, bool p_display_placeholder) { + ERR_FAIL_COND(!scenes.has(p_id)); + + scenes[p_id].display_placeholder = p_display_placeholder; + + emit_signal("changed"); +} + +bool TileSetScenesCollectionSource::get_scene_tile_display_placeholder(int p_id) const { + ERR_FAIL_COND_V(!scenes.has(p_id), false); + return scenes[p_id].display_placeholder; +} + +void TileSetScenesCollectionSource::remove_scene_tile(int p_id) { + ERR_FAIL_COND(!scenes.has(p_id)); + + scenes.erase(p_id); + scenes_ids.erase(p_id); + emit_signal("changed"); +} + +int TileSetScenesCollectionSource::get_next_scene_tile_id() const { + return next_scene_id; +} + +bool TileSetScenesCollectionSource::_set(const StringName &p_name, const Variant &p_value) { + Vector<String> components = String(p_name).split("/", true, 2); + + if (components.size() >= 2 && components[0] == "scenes" && components[1].is_valid_integer()) { + int scene_id = components[1].to_int(); + if (components.size() >= 3 && components[2] == "scene") { + if (has_scene_tile_id(scene_id)) { + set_scene_tile_scene(scene_id, p_value); + } else { + create_scene_tile(p_value, scene_id); + } + return true; + } else if (components.size() >= 3 && components[2] == "display_placeholder") { + if (!has_scene_tile_id(scene_id)) { + create_scene_tile(p_value, scene_id); + } + + return true; + } + } + + return false; +} + +bool TileSetScenesCollectionSource::_get(const StringName &p_name, Variant &r_ret) const { + Vector<String> components = String(p_name).split("/", true, 2); + + if (components.size() >= 2 && components[0] == "scenes" && components[1].is_valid_integer() && scenes.has(components[1].to_int())) { + if (components.size() >= 3 && components[2] == "scene") { + r_ret = scenes[components[1].to_int()].scene; + return true; + } else if (components.size() >= 3 && components[2] == "display_placeholder") { + r_ret = scenes[components[1].to_int()].scene; + return true; + } + } + + return false; +} + +void TileSetScenesCollectionSource::_get_property_list(List<PropertyInfo> *p_list) const { + for (int i = 0; i < scenes_ids.size(); i++) { + p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("scenes/%d/scene", scenes_ids[i]), PROPERTY_HINT_RESOURCE_TYPE, "TileSetScenesCollectionSource")); + + PropertyInfo property_info = PropertyInfo(Variant::BOOL, vformat("scenes/%d/display_placeholder", scenes_ids[i])); + if (scenes[scenes_ids[i]].display_placeholder == false) { + property_info.usage ^= PROPERTY_USAGE_STORAGE; + } + p_list->push_back(property_info); + } +} + +void TileSetScenesCollectionSource::_bind_methods() { + // Base tiles + ClassDB::bind_method(D_METHOD("get_tiles_count"), &TileSetScenesCollectionSource::get_tiles_count); + ClassDB::bind_method(D_METHOD("get_tile_id", "index"), &TileSetScenesCollectionSource::get_tile_id); + ClassDB::bind_method(D_METHOD("has_tile", "atlas_coords"), &TileSetScenesCollectionSource::has_tile); + + // Alternative tiles + ClassDB::bind_method(D_METHOD("get_alternative_tiles_count", "atlas_coords"), &TileSetScenesCollectionSource::get_alternative_tiles_count); + ClassDB::bind_method(D_METHOD("get_alternative_tile_id", "atlas_coords", "index"), &TileSetScenesCollectionSource::get_alternative_tile_id); + ClassDB::bind_method(D_METHOD("has_alternative_tile", "atlas_coords", "alternative_tile"), &TileSetScenesCollectionSource::has_alternative_tile); + + ClassDB::bind_method(D_METHOD("get_scene_tiles_count"), &TileSetScenesCollectionSource::get_scene_tiles_count); + ClassDB::bind_method(D_METHOD("get_scene_tile_id", "index"), &TileSetScenesCollectionSource::get_scene_tile_id); + ClassDB::bind_method(D_METHOD("has_scene_tile_id", "id"), &TileSetScenesCollectionSource::has_scene_tile_id); + ClassDB::bind_method(D_METHOD("create_scene_tile", "packed_scene", "id_override"), &TileSetScenesCollectionSource::create_scene_tile, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("set_scene_tile_id", "id", "new_id"), &TileSetScenesCollectionSource::set_scene_tile_id); + ClassDB::bind_method(D_METHOD("set_scene_tile_scene", "id", "packed_scene"), &TileSetScenesCollectionSource::set_scene_tile_scene); + ClassDB::bind_method(D_METHOD("get_scene_tile_scene", "id"), &TileSetScenesCollectionSource::get_scene_tile_scene); + ClassDB::bind_method(D_METHOD("set_scene_tile_display_placeholder", "id", "display_placeholder"), &TileSetScenesCollectionSource::set_scene_tile_display_placeholder); + ClassDB::bind_method(D_METHOD("get_scene_tile_display_placeholder", "id"), &TileSetScenesCollectionSource::get_scene_tile_display_placeholder); + ClassDB::bind_method(D_METHOD("remove_scene_tile", "id"), &TileSetScenesCollectionSource::remove_scene_tile); + ClassDB::bind_method(D_METHOD("get_next_scene_tile_id"), &TileSetScenesCollectionSource::get_next_scene_tile_id); +} + /////////////////////////////// TileData ////////////////////////////////////// void TileData::set_tile_set(const TileSet *p_tile_set) { @@ -2834,10 +3031,10 @@ void TileData::_bind_methods() { ADD_SIGNAL(MethodInfo("changed")); } -/////////////////////////////// TileSetAtlasPluginTerrain ////////////////////////////////////// +/////////////////////////////// TileSetPluginAtlasTerrain ////////////////////////////////////// // --- PLUGINS --- -void TileSetAtlasPluginTerrain::_draw_square_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { +void TileSetPluginAtlasTerrain::_draw_square_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { Rect2 bit_rect; bit_rect.size = Vector2(p_size) / 3; switch (p_bit) { @@ -2872,7 +3069,7 @@ void TileSetAtlasPluginTerrain::_draw_square_corner_or_side_terrain_bit(CanvasIt p_canvas_item->draw_rect(bit_rect, p_color); } -void TileSetAtlasPluginTerrain::_draw_square_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { +void TileSetPluginAtlasTerrain::_draw_square_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { PackedColorArray color_array; color_array.push_back(p_color); @@ -2919,7 +3116,7 @@ void TileSetAtlasPluginTerrain::_draw_square_corner_terrain_bit(CanvasItem *p_ca } } -void TileSetAtlasPluginTerrain::_draw_square_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { +void TileSetPluginAtlasTerrain::_draw_square_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { PackedColorArray color_array; color_array.push_back(p_color); @@ -2958,7 +3155,7 @@ void TileSetAtlasPluginTerrain::_draw_square_side_terrain_bit(CanvasItem *p_canv } } -void TileSetAtlasPluginTerrain::_draw_isometric_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { +void TileSetPluginAtlasTerrain::_draw_isometric_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { PackedColorArray color_array; color_array.push_back(p_color); @@ -3021,7 +3218,7 @@ void TileSetAtlasPluginTerrain::_draw_isometric_corner_or_side_terrain_bit(Canva } } -void TileSetAtlasPluginTerrain::_draw_isometric_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { +void TileSetPluginAtlasTerrain::_draw_isometric_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { PackedColorArray color_array; color_array.push_back(p_color); @@ -3068,7 +3265,7 @@ void TileSetAtlasPluginTerrain::_draw_isometric_corner_terrain_bit(CanvasItem *p } } -void TileSetAtlasPluginTerrain::_draw_isometric_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { +void TileSetPluginAtlasTerrain::_draw_isometric_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { PackedColorArray color_array; color_array.push_back(p_color); @@ -3107,7 +3304,7 @@ void TileSetAtlasPluginTerrain::_draw_isometric_side_terrain_bit(CanvasItem *p_c } } -void TileSetAtlasPluginTerrain::_draw_half_offset_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { +void TileSetPluginAtlasTerrain::_draw_half_offset_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { PackedColorArray color_array; color_array.push_back(p_color); @@ -3272,7 +3469,7 @@ void TileSetAtlasPluginTerrain::_draw_half_offset_corner_or_side_terrain_bit(Can } } -void TileSetAtlasPluginTerrain::_draw_half_offset_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { +void TileSetPluginAtlasTerrain::_draw_half_offset_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { PackedColorArray color_array; color_array.push_back(p_color); @@ -3383,7 +3580,7 @@ void TileSetAtlasPluginTerrain::_draw_half_offset_corner_terrain_bit(CanvasItem } } -void TileSetAtlasPluginTerrain::_draw_half_offset_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { +void TileSetPluginAtlasTerrain::_draw_half_offset_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { PackedColorArray color_array; color_array.push_back(p_color); @@ -3498,7 +3695,7 @@ void TileSetAtlasPluginTerrain::_draw_half_offset_side_terrain_bit(CanvasItem *p } \ } -void TileSetAtlasPluginTerrain::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, const TileData *p_tile_data) { +void TileSetPluginAtlasTerrain::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, const TileData *p_tile_data) { ERR_FAIL_COND(!p_tile_set); ERR_FAIL_COND(!p_tile_data); @@ -3632,9 +3829,9 @@ void TileSetAtlasPluginTerrain::draw_terrains(CanvasItem *p_canvas_item, Transfo RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D()); } -/////////////////////////////// TileSetAtlasPluginRendering ////////////////////////////////////// +/////////////////////////////// TileSetPluginAtlasRendering ////////////////////////////////////// -void TileSetAtlasPluginRendering::tilemap_notification(TileMap *p_tile_map, int p_what) { +void TileSetPluginAtlasRendering::tilemap_notification(TileMap *p_tile_map, int p_what) { switch (p_what) { case CanvasItem::NOTIFICATION_VISIBILITY_CHANGED: { bool visible = p_tile_map->is_visible_in_tree(); @@ -3672,7 +3869,7 @@ void TileSetAtlasPluginRendering::tilemap_notification(TileMap *p_tile_map, int } } -void TileSetAtlasPluginRendering::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation) { +void TileSetPluginAtlasRendering::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation) { ERR_FAIL_COND(!p_tile_set.is_valid()); ERR_FAIL_COND(!p_tile_set->has_source(p_atlas_source_id)); ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_tile(p_atlas_coords)); @@ -3687,6 +3884,12 @@ void TileSetAtlasPluginRendering::draw_tile(RID p_canvas_item, Vector2i p_positi return; } + // Check if we are in the texture, return otherwise. + Vector2i grid_size = atlas_source->get_atlas_grid_size(); + if (p_atlas_coords.x >= grid_size.x || p_atlas_coords.y >= grid_size.y) { + return; + } + // Get tile data. TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile)); @@ -3724,7 +3927,7 @@ void TileSetAtlasPluginRendering::draw_tile(RID p_canvas_item, Vector2i p_positi } } -void TileSetAtlasPluginRendering::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) { +void TileSetPluginAtlasRendering::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) { ERR_FAIL_COND(!p_tile_map); ERR_FAIL_COND(!p_tile_map->is_inside_tree()); Ref<TileSet> tile_set = p_tile_map->get_tileset(); @@ -3858,14 +4061,14 @@ void TileSetAtlasPluginRendering::update_dirty_quadrants(TileMap *p_tile_map, Se } } -void TileSetAtlasPluginRendering::create_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { +void TileSetPluginAtlasRendering::create_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { Ref<TileSet> tile_set = p_tile_map->get_tileset(); ERR_FAIL_COND(!tile_set.is_valid()); quadrant_order_dirty = true; } -void TileSetAtlasPluginRendering::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { +void TileSetPluginAtlasRendering::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { // Free the canvas items. for (List<RID>::Element *E = p_quadrant->canvas_items.front(); E; E = E->next()) { RenderingServer::get_singleton()->free(E->get()); @@ -3879,9 +4082,60 @@ void TileSetAtlasPluginRendering::cleanup_quadrant(TileMap *p_tile_map, TileMapQ p_quadrant->occluders.clear(); } -/////////////////////////////// TileSetAtlasPluginPhysics ////////////////////////////////////// +void TileSetPluginAtlasRendering::draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { + Ref<TileSet> tile_set = p_tile_map->get_tileset(); + ERR_FAIL_COND(!tile_set.is_valid()); + + if (!Engine::get_singleton()->is_editor_hint()) { + return; + } + + // Draw a placeholder for scenes needing one. + RenderingServer *rs = RenderingServer::get_singleton(); + Vector2 quadrant_pos = p_tile_map->map_to_world(p_quadrant->coords * p_tile_map->get_effective_quadrant_size()); + for (Set<Vector2i>::Element *E_cell = p_quadrant->cells.front(); E_cell; E_cell = E_cell->next()) { + const TileMapCell &c = p_tile_map->get_cell(E_cell->get()); -void TileSetAtlasPluginPhysics::tilemap_notification(TileMap *p_tile_map, int p_what) { + TileSetSource *source; + if (tile_set->has_source(c.source_id)) { + source = *tile_set->get_source(c.source_id); + + if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { + continue; + } + + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source) { + Vector2i grid_size = atlas_source->get_atlas_grid_size(); + if (!atlas_source->get_texture().is_valid() || c.get_atlas_coords().x >= grid_size.x || c.get_atlas_coords().y >= grid_size.y) { + // Generate a random color from the hashed values of the tiles. + Array to_hash; + to_hash.push_back(c.source_id); + to_hash.push_back(c.get_atlas_coords()); + to_hash.push_back(c.alternative_tile); + uint32_t hash = RandomPCG(to_hash.hash()).rand(); + + Color color; + color = color.from_hsv( + (float)((hash >> 24) & 0xFF) / 256.0, + Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0), + Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0), + 0.8); + + // Draw a placeholder tile. + Transform2D xform; + xform.set_origin(p_tile_map->map_to_world(E_cell->get()) - quadrant_pos); + rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform); + rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color); + } + } + } + } +} + +/////////////////////////////// TileSetPluginAtlasPhysics ////////////////////////////////////// + +void TileSetPluginAtlasPhysics::tilemap_notification(TileMap *p_tile_map, int p_what) { switch (p_what) { case CanvasItem::NOTIFICATION_TRANSFORM_CHANGED: { // Update the bodies transforms. @@ -3905,7 +4159,7 @@ void TileSetAtlasPluginPhysics::tilemap_notification(TileMap *p_tile_map, int p_ } } -void TileSetAtlasPluginPhysics::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) { +void TileSetPluginAtlasPhysics::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) { ERR_FAIL_COND(!p_tile_map); ERR_FAIL_COND(!p_tile_map->is_inside_tree()); Ref<TileSet> tile_set = p_tile_map->get_tileset(); @@ -3971,7 +4225,7 @@ void TileSetAtlasPluginPhysics::update_dirty_quadrants(TileMap *p_tile_map, Self } } -void TileSetAtlasPluginPhysics::create_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { +void TileSetPluginAtlasPhysics::create_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { Ref<TileSet> tile_set = p_tile_map->get_tileset(); ERR_FAIL_COND(!tile_set.is_valid()); @@ -4016,7 +4270,7 @@ void TileSetAtlasPluginPhysics::create_quadrant(TileMap *p_tile_map, TileMapQuad } } -void TileSetAtlasPluginPhysics::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { +void TileSetPluginAtlasPhysics::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { // Remove a quadrant. for (int body_index = 0; body_index < p_quadrant->bodies.size(); body_index++) { PhysicsServer2D::get_singleton()->free(p_quadrant->bodies[body_index]); @@ -4024,7 +4278,7 @@ void TileSetAtlasPluginPhysics::cleanup_quadrant(TileMap *p_tile_map, TileMapQua p_quadrant->bodies.clear(); } -void TileSetAtlasPluginPhysics::draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { +void TileSetPluginAtlasPhysics::draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { // Draw the debug collision shapes. Ref<TileSet> tile_set = p_tile_map->get_tileset(); ERR_FAIL_COND(!tile_set.is_valid()); @@ -4071,9 +4325,9 @@ void TileSetAtlasPluginPhysics::draw_quadrant_debug(TileMap *p_tile_map, TileMap } }; -/////////////////////////////// TileSetAtlasPluginNavigation ////////////////////////////////////// +/////////////////////////////// TileSetPluginAtlasNavigation ////////////////////////////////////// -void TileSetAtlasPluginNavigation::tilemap_notification(TileMap *p_tile_map, int p_what) { +void TileSetPluginAtlasNavigation::tilemap_notification(TileMap *p_tile_map, int p_what) { switch (p_what) { case CanvasItem::NOTIFICATION_TRANSFORM_CHANGED: { if (p_tile_map->is_inside_tree()) { @@ -4098,7 +4352,7 @@ void TileSetAtlasPluginNavigation::tilemap_notification(TileMap *p_tile_map, int } } -void TileSetAtlasPluginNavigation::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) { +void TileSetPluginAtlasNavigation::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) { ERR_FAIL_COND(!p_tile_map); ERR_FAIL_COND(!p_tile_map->is_inside_tree()); Ref<TileSet> tile_set = p_tile_map->get_tileset(); @@ -4169,7 +4423,7 @@ void TileSetAtlasPluginNavigation::update_dirty_quadrants(TileMap *p_tile_map, S } } -void TileSetAtlasPluginNavigation::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { +void TileSetPluginAtlasNavigation::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { // Clear navigation shapes in the quadrant. for (Map<Vector2i, Vector<RID>>::Element *E = p_quadrant->navigation_regions.front(); E; E = E->next()) { for (int i = 0; i < E->get().size(); i++) { @@ -4183,7 +4437,7 @@ void TileSetAtlasPluginNavigation::cleanup_quadrant(TileMap *p_tile_map, TileMap p_quadrant->navigation_regions.clear(); } -void TileSetAtlasPluginNavigation::draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { +void TileSetPluginAtlasNavigation::draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { // Draw the debug collision shapes. Ref<TileSet> tile_set = p_tile_map->get_tileset(); ERR_FAIL_COND(!tile_set.is_valid()); @@ -4240,11 +4494,129 @@ void TileSetAtlasPluginNavigation::draw_quadrant_debug(TileMap *p_tile_map, Tile Vector<Color> colors; colors.push_back(random_variation_color); - RS::get_singleton()->canvas_item_add_polygon(p_quadrant->debug_canvas_item, vertices, colors); + rs->canvas_item_add_polygon(p_quadrant->debug_canvas_item, vertices, colors); + } + } + } + } + } + } +} + +/////////////////////////////// TileSetPluginScenesCollections ////////////////////////////////////// + +void TileSetPluginScenesCollections::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) { + Ref<TileSet> tile_set = p_tile_map->get_tileset(); + ERR_FAIL_COND(!tile_set.is_valid()); + + SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first(); + while (q_list_element) { + TileMapQuadrant &q = *q_list_element->self(); + + // Clear the scenes. + for (Map<Vector2i, String>::Element *E = q.scenes.front(); E; E = E->next()) { + Node *node = p_tile_map->get_node(E->get()); + if (node) { + node->queue_delete(); + } + } + + q.scenes.clear(); + + // Recreate the scenes. + for (Set<Vector2i>::Element *E_cell = q.cells.front(); E_cell; E_cell = E_cell->next()) { + const TileMapCell &c = p_tile_map->get_cell(E_cell->get()); + + TileSetSource *source; + if (tile_set->has_source(c.source_id)) { + source = *tile_set->get_source(c.source_id); + + if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { + continue; + } + + TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source); + if (scenes_collection_source) { + Ref<PackedScene> packed_scene = scenes_collection_source->get_scene_tile_scene(c.alternative_tile); + if (packed_scene.is_valid()) { + Node *scene = packed_scene->instance(); + p_tile_map->add_child(scene); + Control *scene_as_control = Object::cast_to<Control>(scene); + Node2D *scene_as_node2d = Object::cast_to<Node2D>(scene); + if (scene_as_control) { + scene_as_control->set_position(p_tile_map->map_to_world(E_cell->get()) + scene_as_control->get_position()); + } else if (scene_as_node2d) { + Transform2D xform; + xform.set_origin(p_tile_map->map_to_world(E_cell->get())); + scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform()); } + q.scenes[E_cell->get()] = scene->get_name(); } } } } + + q_list_element = q_list_element->next(); + } +} + +void TileSetPluginScenesCollections::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { + // Clear the scenes. + for (Map<Vector2i, String>::Element *E = p_quadrant->scenes.front(); E; E = E->next()) { + Node *node = p_tile_map->get_node(E->get()); + if (node) { + node->queue_delete(); + } + } + + p_quadrant->scenes.clear(); +} + +void TileSetPluginScenesCollections::draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) { + Ref<TileSet> tile_set = p_tile_map->get_tileset(); + ERR_FAIL_COND(!tile_set.is_valid()); + + if (!Engine::get_singleton()->is_editor_hint()) { + return; + } + + // Draw a placeholder for scenes needing one. + RenderingServer *rs = RenderingServer::get_singleton(); + Vector2 quadrant_pos = p_tile_map->map_to_world(p_quadrant->coords * p_tile_map->get_effective_quadrant_size()); + for (Set<Vector2i>::Element *E_cell = p_quadrant->cells.front(); E_cell; E_cell = E_cell->next()) { + const TileMapCell &c = p_tile_map->get_cell(E_cell->get()); + + TileSetSource *source; + if (tile_set->has_source(c.source_id)) { + source = *tile_set->get_source(c.source_id); + + if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) { + continue; + } + + TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source); + if (scenes_collection_source) { + if (!scenes_collection_source->get_scene_tile_scene(c.alternative_tile).is_valid() || scenes_collection_source->get_scene_tile_display_placeholder(c.alternative_tile)) { + // Generate a random color from the hashed values of the tiles. + Array to_hash; + to_hash.push_back(c.source_id); + to_hash.push_back(c.alternative_tile); + uint32_t hash = RandomPCG(to_hash.hash()).rand(); + + Color color; + color = color.from_hsv( + (float)((hash >> 24) & 0xFF) / 256.0, + Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0), + Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0), + 0.8); + + // Draw a placeholder tile. + Transform2D xform; + xform.set_origin(p_tile_map->map_to_world(E_cell->get()) - quadrant_pos); + rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform); + rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color); + } + } + } } } diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 20cf183a20..ae80299d85 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -57,10 +57,10 @@ class TileData; // Forward-declare the plugins. class TileSetPlugin; -class TileSetAtlasPluginRendering; -class TileSetAtlasPluginPhysics; -class TileSetAtlasPluginNavigation; -class TileSetAtlasPluginTerrain; +class TileSetPluginAtlasRendering; +class TileSetPluginAtlasPhysics; +class TileSetPluginAtlasNavigation; +class TileSetPluginAtlasTerrain; class TileSet : public Resource { GDCLASS(TileSet, Resource); @@ -264,7 +264,7 @@ public: int get_next_source_id() const; int get_source_count() const; int get_source_id(int p_index) const; - int add_source(Ref<TileSetAtlasSource> p_tile_atlas_source, int p_source_id_override = -1); + int add_source(Ref<TileSetSource> p_tile_set_source, int p_source_id_override = -1); void set_source_id(int p_source_id, int p_new_id); void remove_source(int p_source_id); bool has_source(int p_source_id) const; @@ -338,6 +338,9 @@ protected: const TileSet *tile_set = nullptr; public: + static const Vector2i INVALID_ATLAS_COORDS; // Vector2i(-1, -1); + static const int INVALID_TILE_ALTERNATIVE; // -1; + // Not exposed. virtual void set_tile_set(const TileSet *p_tile_set); virtual void notify_tile_data_properties_should_change(){}; @@ -358,9 +361,6 @@ class TileSetAtlasSource : public TileSetSource { GDCLASS(TileSetAtlasSource, TileSetSource); public: - static const Vector2i INVALID_ATLAS_COORDS; // Vector2i(-1, -1); - static const int INVALID_TILE_ALTERNATIVE; // -1; - struct TileAlternativesData { Vector2i size_in_atlas = Vector2i(1, 1); Vector2i texture_offset; @@ -443,6 +443,52 @@ public: ~TileSetAtlasSource(); }; +class TileSetScenesCollectionSource : public TileSetSource { + GDCLASS(TileSetScenesCollectionSource, TileSetSource); + +private: + struct SceneData { + Ref<PackedScene> scene; + bool display_placeholder = false; + }; + Vector<int> scenes_ids; + Map<int, SceneData> scenes; + int next_scene_id = 1; + + void _compute_next_alternative_id(); + +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + + static void _bind_methods(); + +public: + // Tiles. + int get_tiles_count() const override; + Vector2i get_tile_id(int p_tile_index) const override; + bool has_tile(Vector2i p_atlas_coords) const override; + + // Alternative tiles. + int get_alternative_tiles_count(const Vector2i p_atlas_coords) const override; + int get_alternative_tile_id(const Vector2i p_atlas_coords, int p_index) const override; + bool has_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) const override; + + // Scenes sccessors. Lot are similar to "Alternative tiles". + int get_scene_tiles_count() { return get_alternative_tiles_count(Vector2i()); } + int get_scene_tile_id(int p_index) { return get_alternative_tile_id(Vector2i(), p_index); }; + bool has_scene_tile_id(int p_id) { return has_alternative_tile(Vector2i(), p_id); }; + int create_scene_tile(Ref<PackedScene> p_packed_scene = Ref<PackedScene>(), int p_id_override = -1); + void set_scene_tile_id(int p_id, int p_new_id); + void set_scene_tile_scene(int p_id, Ref<PackedScene> p_packed_scene); + Ref<PackedScene> get_scene_tile_scene(int p_id) const; + void set_scene_tile_display_placeholder(int p_id, bool p_packed_scene); + bool get_scene_tile_display_placeholder(int p_id) const; + void remove_scene_tile(int p_id); + int get_next_scene_tile_id() const; +}; + class TileData : public Object { GDCLASS(TileData, Object); @@ -572,8 +618,8 @@ public: virtual void draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant){}; }; -class TileSetAtlasPluginRendering : public TileSetPlugin { - GDCLASS(TileSetAtlasPluginRendering, TileSetPlugin); +class TileSetPluginAtlasRendering : public TileSetPlugin { + GDCLASS(TileSetPluginAtlasRendering, TileSetPlugin); private: static constexpr float fp_adjust = 0.00001; @@ -585,13 +631,14 @@ public: virtual void update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) override; virtual void create_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override; virtual void cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override; + virtual void draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override; // Other. static void draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0)); }; -class TileSetAtlasPluginTerrain : public TileSetPlugin { - GDCLASS(TileSetAtlasPluginTerrain, TileSetPlugin); +class TileSetPluginAtlasTerrain : public TileSetPlugin { + GDCLASS(TileSetPluginAtlasTerrain, TileSetPlugin); private: static void _draw_square_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit); @@ -607,13 +654,11 @@ private: static void _draw_half_offset_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis); public: - //virtual void tilemap_notification(const TileMap * p_tile_map, int p_what); - static void draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, const TileData *p_tile_data); }; -class TileSetAtlasPluginPhysics : public TileSetPlugin { - GDCLASS(TileSetAtlasPluginPhysics, TileSetPlugin); +class TileSetPluginAtlasPhysics : public TileSetPlugin { + GDCLASS(TileSetPluginAtlasPhysics, TileSetPlugin); public: // Tilemap updates @@ -624,14 +669,23 @@ public: virtual void draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override; }; -class TileSetAtlasPluginNavigation : public TileSetPlugin { - GDCLASS(TileSetAtlasPluginNavigation, TileSetPlugin); +class TileSetPluginAtlasNavigation : public TileSetPlugin { + GDCLASS(TileSetPluginAtlasNavigation, TileSetPlugin); public: // Tilemap updates virtual void tilemap_notification(TileMap *p_tile_map, int p_what) override; virtual void update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) override; - //virtual void create_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override; + virtual void cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override; + virtual void draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override; +}; + +class TileSetPluginScenesCollections : public TileSetPlugin { + GDCLASS(TileSetPluginScenesCollections, TileSetPlugin); + +public: + // Tilemap updates + virtual void update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) override; virtual void cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override; virtual void draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override; }; |