From 6a399302c34fd21fbdb087d72e20d91338910bdc Mon Sep 17 00:00:00 2001 From: DexterFstone Date: Sat, 28 Jun 2025 07:15:15 -0700 Subject: [PATCH] Add support for rotating scene tiles in TileMapLayer --- .../scene/2d/tiles/tile_map_layer_editor.cpp | 13 +----- scene/2d/tile_map_layer.cpp | 44 +++++++++++++++++++ scene/2d/tile_map_layer.h | 1 + scene/resources/2d/tile_set.cpp | 7 +-- 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/editor/scene/2d/tiles/tile_map_layer_editor.cpp b/editor/scene/2d/tiles/tile_map_layer_editor.cpp index 678787f8566..6d2c20eb773 100644 --- a/editor/scene/2d/tiles/tile_map_layer_editor.cpp +++ b/editor/scene/2d/tiles/tile_map_layer_editor.cpp @@ -127,18 +127,7 @@ void TileMapLayerEditorTilesPlugin::_update_transform_buttons() { return; } - bool has_scene_tile = false; - for (const KeyValue &E : selection_pattern->get_pattern()) { - if (Object::cast_to(tile_set->get_source(E.value.source_id).ptr())) { - has_scene_tile = true; - break; - } - } - - if (has_scene_tile) { - _set_transform_buttons_state({}, { transform_button_rotate_left, transform_button_rotate_right, transform_button_flip_h, transform_button_flip_v }, - TTR("Can't transform scene tiles.")); - } else if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE && selection_pattern->get_size() != Vector2i(1, 1)) { + if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE && selection_pattern->get_size() != Vector2i(1, 1)) { _set_transform_buttons_state({ transform_button_flip_h, transform_button_flip_v }, { transform_button_rotate_left, transform_button_rotate_right }, TTR("Can't rotate patterns when using non-square tile grid.")); } else { diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp index add18f490c9..3827d00148f 100644 --- a/scene/2d/tile_map_layer.cpp +++ b/scene/2d/tile_map_layer.cpp @@ -1571,6 +1571,7 @@ void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) { Transform2D xform; xform.set_origin(tile_set->map_to_local(r_cell_data.coords)); scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform()); + _set_scene_transformed_alternative(c.alternative_tile, scene_as_node2d); } if (tile_map_node) { // Compatibility with TileMap. @@ -1631,6 +1632,49 @@ void TileMapLayer::_scenes_draw_cell_debug(const RID &p_canvas_item, const Vecto } #endif // DEBUG_ENABLED +void TileMapLayer::_set_scene_transformed_alternative(const int p_alternative_id, Node2D *p_scene) { + // Determine the transformations based on the alternative ID. + bool transform_flip_h = p_alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H; + bool transform_flip_v = p_alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V; + bool transform_transpose = p_alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE; + + double scene_rotation = 0.0; + Vector2 scene_scale = p_scene->get_scale(); + + // Determine the scene rotation and scale based on the transformation flags. + if (!transform_flip_h && !transform_flip_v && !transform_transpose) { + scene_rotation = 0.0; + scene_scale.x = 1; + } else if (transform_flip_h && !transform_flip_v && transform_transpose) { + scene_rotation = 90.0; + scene_scale.x = 1; + } else if (transform_flip_h && transform_flip_v && !transform_transpose) { + scene_rotation = 180.0; + scene_scale.x = 1; + } else if (!transform_flip_h && transform_flip_v && transform_transpose) { + scene_rotation = 270.0; + scene_scale.x = 1; + } else if (transform_flip_h && !transform_flip_v && !transform_transpose) { + scene_rotation = 0.0; + scene_scale.x = -1; + } else if (transform_flip_h && transform_flip_v && transform_transpose) { + scene_rotation = 90.0; + scene_scale.x = -1; + } else if (!transform_flip_h && transform_flip_v && !transform_transpose) { + scene_rotation = 180.0; + scene_scale.x = -1; + } else if (!transform_flip_h && !transform_flip_v && transform_transpose) { + scene_rotation = 270.0; + scene_scale.x = -1; + } + + // Apply the transformations to the scene. + double current_rotation = p_scene->get_rotation_degrees() + scene_rotation; + Vector2 current_scale = p_scene->get_scale() + scene_scale; + p_scene->set_rotation_degrees(current_rotation); + p_scene->set_scale(current_scale); +} + ///////////////////////////////////////////////////////////////////// void TileMapLayer::_build_runtime_update_tile_data(bool p_force_cleanup) { diff --git a/scene/2d/tile_map_layer.h b/scene/2d/tile_map_layer.h index 7bca54d5cbe..6a4a35999a5 100644 --- a/scene/2d/tile_map_layer.h +++ b/scene/2d/tile_map_layer.h @@ -474,6 +474,7 @@ private: #ifdef DEBUG_ENABLED void _scenes_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data); #endif // DEBUG_ENABLED + void _set_scene_transformed_alternative(const int p_alternative_id, Node2D *p_scene); // Terrains. TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet &p_constraints, TileSet::TerrainsPattern p_current_pattern) const; diff --git a/scene/resources/2d/tile_set.cpp b/scene/resources/2d/tile_set.cpp index 71d74780a68..b8e037005fd 100644 --- a/scene/resources/2d/tile_set.cpp +++ b/scene/resources/2d/tile_set.cpp @@ -5775,7 +5775,7 @@ int TileSetScenesCollectionSource::get_alternative_tile_id(const Vector2i p_atla 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); + return scenes.has(TileSetAtlasSource::alternative_no_transform(p_alternative_tile)); } int TileSetScenesCollectionSource::create_scene_tile(Ref p_packed_scene, int p_id_override) { @@ -5837,8 +5837,9 @@ void TileSetScenesCollectionSource::set_scene_tile_scene(int p_id, Ref TileSetScenesCollectionSource::get_scene_tile_scene(int p_id) const { - ERR_FAIL_COND_V(!scenes.has(p_id), Ref()); - return scenes[p_id].scene; + int scene_tile = TileSetAtlasSource::alternative_no_transform(p_id); + ERR_FAIL_COND_V(!scenes.has(scene_tile), Ref()); + return scenes[scene_tile].scene; } void TileSetScenesCollectionSource::set_scene_tile_display_placeholder(int p_id, bool p_display_placeholder) {