diff options
Diffstat (limited to 'scene')
-rw-r--r-- | scene/2d/tile_map.compat.inc | 10 | ||||
-rw-r--r-- | scene/2d/tile_map.cpp | 808 | ||||
-rw-r--r-- | scene/2d/tile_map.h | 16 | ||||
-rw-r--r-- | scene/2d/tile_map_layer.cpp | 646 | ||||
-rw-r--r-- | scene/2d/tile_map_layer.h | 60 | ||||
-rw-r--r-- | scene/main/canvas_item.cpp | 2 | ||||
-rw-r--r-- | scene/main/canvas_item.h | 4 | ||||
-rw-r--r-- | scene/resources/tile_set.cpp | 626 | ||||
-rw-r--r-- | scene/resources/tile_set.h | 7 |
9 files changed, 1103 insertions, 1076 deletions
diff --git a/scene/2d/tile_map.compat.inc b/scene/2d/tile_map.compat.inc index ed216173c7..04937bdf7e 100644 --- a/scene/2d/tile_map.compat.inc +++ b/scene/2d/tile_map.compat.inc @@ -42,10 +42,20 @@ int TileMap::_get_quadrant_size_compat_81070() const { return get_rendering_quadrant_size(); } +TileMap::VisibilityMode TileMap::_get_collision_visibility_mode_bind_compat_87115() { + return get_collision_visibility_mode(); +} + +TileMap::VisibilityMode TileMap::_get_navigation_visibility_mode_bind_compat_87115() { + return get_navigation_visibility_mode(); +} + void TileMap::_bind_compatibility_methods() { ClassDB::bind_compatibility_method(D_METHOD("get_used_rect"), &TileMap::_get_used_rect_bind_compat_78328); ClassDB::bind_compatibility_method(D_METHOD("set_quadrant_size", "quadrant_size"), &TileMap::_set_quadrant_size_compat_81070); ClassDB::bind_compatibility_method(D_METHOD("get_quadrant_size"), &TileMap::_get_quadrant_size_compat_81070); + ClassDB::bind_compatibility_method(D_METHOD("get_collision_visibility_mode"), &TileMap::_get_collision_visibility_mode_bind_compat_87115); + ClassDB::bind_compatibility_method(D_METHOD("get_navigation_visibility_mode"), &TileMap::_get_navigation_visibility_mode_bind_compat_87115); } #endif diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index decbbab476..24eefce99d 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -167,7 +167,7 @@ void TileMap::set_selected_layer(int p_layer_id) { emit_signal(CoreStringNames::get_singleton()->changed); // Update the layers modulation. - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_SELECTED_LAYER); } } @@ -178,45 +178,9 @@ int TileMap::get_selected_layer() const { void TileMap::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - for (Ref<TileMapLayer> &layer : layers) { - layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_IN_TREE); - } - } break; - - case NOTIFICATION_EXIT_TREE: { - for (Ref<TileMapLayer> &layer : layers) { - layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_IN_TREE); - } - } break; - - case TileMap::NOTIFICATION_ENTER_CANVAS: { - for (Ref<TileMapLayer> &layer : layers) { - layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_IN_CANVAS); - } - } break; - - case TileMap::NOTIFICATION_EXIT_CANVAS: { - for (Ref<TileMapLayer> &layer : layers) { - layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_IN_CANVAS); - } - } break; - - case NOTIFICATION_DRAW: { - // Rendering. - if (tile_set.is_valid()) { - RenderingServer::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), is_y_sort_enabled()); - } - } break; - - case TileMap::NOTIFICATION_VISIBILITY_CHANGED: { - for (Ref<TileMapLayer> &layer : layers) { - layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_VISIBILITY); - } - } break; - case TileMap::NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { - // Physics. + // This is only executed when collision_animatable is enabled. + bool in_editor = false; #ifdef TOOLS_ENABLED in_editor = Engine::get_singleton()->is_editor_hint(); @@ -224,39 +188,30 @@ void TileMap::_notification(int p_what) { if (is_inside_tree() && collision_animatable && !in_editor) { // Update transform on the physics tick when in animatable mode. last_valid_transform = new_transform; + print_line("Physics: ", new_transform); set_notify_local_transform(false); set_global_transform(new_transform); - _update_notify_local_transform(); - } - } break; - - case NOTIFICATION_TRANSFORM_CHANGED: { - // Physics. - for (Ref<TileMapLayer> &layer : layers) { - layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_XFORM); + set_notify_local_transform(true); } } break; case TileMap::NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - for (Ref<TileMapLayer> &layer : layers) { - layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_LOCAL_XFORM); - } + // This is only executed when collision_animatable is enabled. - // Physics. bool in_editor = false; #ifdef TOOLS_ENABLED in_editor = Engine::get_singleton()->is_editor_hint(); #endif - // Only active when animatable. Send the new transform to the physics... if (is_inside_tree() && collision_animatable && !in_editor) { // Store last valid transform. new_transform = get_global_transform(); + print_line("local XFORM: ", last_valid_transform); // ... but then revert changes. set_notify_local_transform(false); set_global_transform(last_valid_transform); - _update_notify_local_transform(); + set_notify_local_transform(true); } } break; } @@ -285,7 +240,7 @@ void TileMap::_internal_update() { } // Update dirty quadrants on layers. - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->internal_update(); } @@ -308,7 +263,7 @@ void TileMap::set_tileset(const Ref<TileSet> &p_tileset) { tile_set->connect_changed(callable_mp(this, &TileMap::_tile_set_changed)); } - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_TILE_SET); } @@ -323,7 +278,7 @@ void TileMap::set_rendering_quadrant_size(int p_size) { ERR_FAIL_COND_MSG(p_size < 1, "TileMapQuadrant size cannot be smaller than 1."); rendering_quadrant_size = p_size; - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE); } emit_signal(CoreStringNames::get_singleton()->changed); @@ -429,10 +384,11 @@ void TileMap::add_layer(int p_to_pos) { ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1); // Must clear before adding the layer. - Ref<TileMapLayer> new_layer; - new_layer.instantiate(); - new_layer->set_tile_map(this); + TileMapLayer *new_layer = memnew(TileMapLayer); layers.insert(p_to_pos, new_layer); + add_child(new_layer); + new_layer->set_name(vformat("Layer%d", p_to_pos)); + move_child(new_layer, p_to_pos); for (uint32_t i = 0; i < layers.size(); i++) { layers[i]->set_layer_index_in_tile_map_node(i); } @@ -449,10 +405,11 @@ void TileMap::move_layer(int p_layer, int p_to_pos) { ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1); // Clear before shuffling layers. - Ref<TileMapLayer> layer = layers[p_layer]; + TileMapLayer *layer = layers[p_layer]; layers.insert(p_to_pos, layer); layers.remove_at(p_to_pos < p_layer ? p_layer + 1 : p_layer); for (uint32_t i = 0; i < layers.size(); i++) { + move_child(layer, i); layers[i]->set_layer_index_in_tile_map_node(i); } queue_internal_update(); @@ -471,6 +428,7 @@ void TileMap::remove_layer(int p_layer) { ERR_FAIL_INDEX(p_layer, (int)layers.size()); // Clear before removing the layer. + layers[p_layer]->queue_free(); layers.remove_at(p_layer); for (uint32_t i = 0; i < layers.size(); i++) { layers[i]->set_layer_index_in_tile_map_node(i); @@ -513,7 +471,6 @@ Color TileMap::get_layer_modulate(int p_layer) const { void TileMap::set_layer_y_sort_enabled(int p_layer, bool p_y_sort_enabled) { TILEMAP_CALL_FOR_LAYER(p_layer, set_y_sort_enabled, p_y_sort_enabled); - _update_notify_local_transform(); } bool TileMap::is_layer_y_sort_enabled(int p_layer) const { @@ -552,17 +509,16 @@ RID TileMap::get_layer_navigation_map(int p_layer) const { TILEMAP_CALL_FOR_LAYER_V(p_layer, RID(), get_navigation_map); } -void TileMap::set_collision_animatable(bool p_enabled) { - if (collision_animatable == p_enabled) { +void TileMap::set_collision_animatable(bool p_collision_animatable) { + if (collision_animatable == p_collision_animatable) { return; } - collision_animatable = p_enabled; - _update_notify_local_transform(); - set_physics_process_internal(p_enabled); - for (Ref<TileMapLayer> &layer : layers) { - layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_COLLISION_ANIMATABLE); + collision_animatable = p_collision_animatable; + set_notify_local_transform(p_collision_animatable); + set_physics_process_internal(p_collision_animatable); + for (TileMapLayer *layer : layers) { + layer->set_use_kinematic_bodies(layer); } - emit_signal(CoreStringNames::get_singleton()->changed); } bool TileMap::is_collision_animatable() const { @@ -574,13 +530,13 @@ void TileMap::set_collision_visibility_mode(TileMap::VisibilityMode p_show_colli return; } collision_visibility_mode = p_show_collision; - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_COLLISION_VISIBILITY_MODE); } emit_signal(CoreStringNames::get_singleton()->changed); } -TileMap::VisibilityMode TileMap::get_collision_visibility_mode() { +TileMap::VisibilityMode TileMap::get_collision_visibility_mode() const { return collision_visibility_mode; } @@ -589,13 +545,13 @@ void TileMap::set_navigation_visibility_mode(TileMap::VisibilityMode p_show_navi return; } navigation_visibility_mode = p_show_navigation; - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_NAVIGATION_VISIBILITY_MODE); } emit_signal(CoreStringNames::get_singleton()->changed); } -TileMap::VisibilityMode TileMap::get_navigation_visibility_mode() { +TileMap::VisibilityMode TileMap::get_navigation_visibility_mode() const { return navigation_visibility_mode; } @@ -604,7 +560,7 @@ void TileMap::set_y_sort_enabled(bool p_enable) { return; } Node2D::set_y_sort_enabled(p_enable); - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED); } emit_signal(CoreStringNames::get_singleton()->changed); @@ -640,27 +596,8 @@ Ref<TileMapPattern> TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coo } Vector2i TileMap::map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern) { - ERR_FAIL_COND_V(p_pattern.is_null(), Vector2i()); - ERR_FAIL_COND_V(!p_pattern->has_cell(p_coords_in_pattern), Vector2i()); - - Vector2i output = p_position_in_tilemap + p_coords_in_pattern; - if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE) { - if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED) { - 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)) { - output.x += 1; - } 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)) { - output.y += 1; - } - } else if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED_OFFSET) { - 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)) { - output.x -= 1; - } 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)) { - output.y -= 1; - } - } - } - - return output; + ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2i()); + return tile_set->map_pattern(p_position_in_tilemap, p_coords_in_pattern, p_pattern); } void TileMap::set_pattern(int p_layer, const Vector2i &p_position, const Ref<TileMapPattern> p_pattern) { @@ -700,7 +637,7 @@ TileMapCell TileMap::get_cell(int p_layer, const Vector2i &p_coords, bool p_use_ } Vector2i TileMap::get_coords_for_body_rid(RID p_physics_body) { - for (const Ref<TileMapLayer> &layer : layers) { + for (const TileMapLayer *layer : layers) { if (layer->has_body_rid(p_physics_body)) { return layer->get_coords_for_body_rid(p_physics_body); } @@ -718,7 +655,7 @@ int TileMap::get_layer_for_body_rid(RID p_physics_body) { } void TileMap::fix_invalid_tiles() { - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->fix_invalid_tiles(); } } @@ -728,7 +665,7 @@ void TileMap::clear_layer(int p_layer) { } void TileMap::clear() { - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->clear(); } } @@ -742,7 +679,7 @@ void TileMap::notify_runtime_tile_data_update(int p_layer) { if (p_layer >= 0) { TILEMAP_CALL_FOR_LAYER(p_layer, notify_tile_map_change, TileMapLayer::DIRTY_FLAGS_TILE_MAP_RUNTIME_UPDATE); } else { - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_RUNTIME_UPDATE); } } @@ -780,9 +717,9 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { else if (p_name == "tile_data") { // Kept for compatibility reasons. if (p_value.is_array()) { if (layers.size() == 0) { - Ref<TileMapLayer> new_layer; - new_layer.instantiate(); - new_layer->set_tile_map(this); + TileMapLayer *new_layer = memnew(TileMapLayer); + add_child(new_layer); + new_layer->set_name("Layer0"); new_layer->set_layer_index_in_tile_map_node(0); layers.push_back(new_layer); } @@ -804,9 +741,9 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { if (index >= (int)layers.size()) { while (index >= (int)layers.size()) { - Ref<TileMapLayer> new_layer; - new_layer.instantiate(); - new_layer->set_tile_map(this); + TileMapLayer *new_layer = memnew(TileMapLayer); + add_child(new_layer); + new_layer->set_name(vformat("Layer%d", index)); new_layer->set_layer_index_in_tile_map_node(index); layers.push_back(new_layer); } @@ -985,623 +922,23 @@ bool TileMap::_property_get_revert(const StringName &p_name, Variant &r_property } Vector2 TileMap::map_to_local(const Vector2i &p_pos) const { - // SHOULD RETURN THE CENTER OF THE CELL. ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2()); - - Vector2 ret = p_pos; - TileSet::TileShape tile_shape = tile_set->get_tile_shape(); - TileSet::TileOffsetAxis tile_offset_axis = tile_set->get_tile_offset_axis(); - - if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { - // Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap. - // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap. - if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - switch (tile_set->get_tile_layout()) { - case TileSet::TILE_LAYOUT_STACKED: - ret = Vector2(ret.x + (Math::posmod(ret.y, 2) == 0 ? 0.0 : 0.5), ret.y); - break; - case TileSet::TILE_LAYOUT_STACKED_OFFSET: - ret = Vector2(ret.x + (Math::posmod(ret.y, 2) == 1 ? 0.0 : 0.5), ret.y); - break; - case TileSet::TILE_LAYOUT_STAIRS_RIGHT: - ret = Vector2(ret.x + ret.y / 2, ret.y); - break; - case TileSet::TILE_LAYOUT_STAIRS_DOWN: - ret = Vector2(ret.x / 2, ret.y * 2 + ret.x); - break; - case TileSet::TILE_LAYOUT_DIAMOND_RIGHT: - ret = Vector2((ret.x + ret.y) / 2, ret.y - ret.x); - break; - case TileSet::TILE_LAYOUT_DIAMOND_DOWN: - ret = Vector2((ret.x - ret.y) / 2, ret.y + ret.x); - break; - } - } else { // TILE_OFFSET_AXIS_VERTICAL. - switch (tile_set->get_tile_layout()) { - case TileSet::TILE_LAYOUT_STACKED: - ret = Vector2(ret.x, ret.y + (Math::posmod(ret.x, 2) == 0 ? 0.0 : 0.5)); - break; - case TileSet::TILE_LAYOUT_STACKED_OFFSET: - ret = Vector2(ret.x, ret.y + (Math::posmod(ret.x, 2) == 1 ? 0.0 : 0.5)); - break; - case TileSet::TILE_LAYOUT_STAIRS_RIGHT: - ret = Vector2(ret.x * 2 + ret.y, ret.y / 2); - break; - case TileSet::TILE_LAYOUT_STAIRS_DOWN: - ret = Vector2(ret.x, ret.y + ret.x / 2); - break; - case TileSet::TILE_LAYOUT_DIAMOND_RIGHT: - ret = Vector2(ret.x + ret.y, (ret.y - ret.x) / 2); - break; - case TileSet::TILE_LAYOUT_DIAMOND_DOWN: - ret = Vector2(ret.x - ret.y, (ret.y + ret.x) / 2); - break; - } - } - } - - // Multiply by the overlapping ratio. - double overlapping_ratio = 1.0; - if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { - overlapping_ratio = 0.5; - } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) { - overlapping_ratio = 0.75; - } - ret.y *= overlapping_ratio; - } else { // TILE_OFFSET_AXIS_VERTICAL. - if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { - overlapping_ratio = 0.5; - } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) { - overlapping_ratio = 0.75; - } - ret.x *= overlapping_ratio; - } - - return (ret + Vector2(0.5, 0.5)) * tile_set->get_tile_size(); + return tile_set->map_to_local(p_pos); } -Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const { +Vector2i TileMap::local_to_map(const Vector2 &p_pos) const { ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2i()); - - Vector2 ret = p_local_position; - ret /= tile_set->get_tile_size(); - - TileSet::TileShape tile_shape = tile_set->get_tile_shape(); - TileSet::TileOffsetAxis tile_offset_axis = tile_set->get_tile_offset_axis(); - TileSet::TileLayout tile_layout = tile_set->get_tile_layout(); - - // Divide by the overlapping ratio. - double overlapping_ratio = 1.0; - if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { - overlapping_ratio = 0.5; - } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) { - overlapping_ratio = 0.75; - } - ret.y /= overlapping_ratio; - } else { // TILE_OFFSET_AXIS_VERTICAL. - if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { - overlapping_ratio = 0.5; - } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) { - overlapping_ratio = 0.75; - } - ret.x /= overlapping_ratio; - } - - // For each half-offset shape, we check if we are in the corner of the tile, and thus should correct the local position accordingly. - if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { - // Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap. - // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap. - if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - // Smart floor of the position - Vector2 raw_pos = ret; - if (Math::posmod(Math::floor(ret.y), 2) ^ (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET)) { - ret = Vector2(Math::floor(ret.x + 0.5) - 0.5, Math::floor(ret.y)); - } else { - ret = ret.floor(); - } - - // Compute the tile offset, and if we might the output for a neighbor top tile. - Vector2 in_tile_pos = raw_pos - ret; - bool in_top_left_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(-0.5, 1.0 / overlapping_ratio - 1)) <= 0; - bool in_top_right_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(0.5, 1.0 / overlapping_ratio - 1)) > 0; - - switch (tile_layout) { - case TileSet::TILE_LAYOUT_STACKED: - ret = ret.floor(); - if (in_top_left_triangle) { - ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 0 : -1, -1); - } else if (in_top_right_triangle) { - ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 1 : 0, -1); - } - break; - case TileSet::TILE_LAYOUT_STACKED_OFFSET: - ret = ret.floor(); - if (in_top_left_triangle) { - ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? -1 : 0, -1); - } else if (in_top_right_triangle) { - ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 0 : 1, -1); - } - break; - case TileSet::TILE_LAYOUT_STAIRS_RIGHT: - ret = Vector2(ret.x - ret.y / 2, ret.y).floor(); - if (in_top_left_triangle) { - ret += Vector2i(0, -1); - } else if (in_top_right_triangle) { - ret += Vector2i(1, -1); - } - break; - case TileSet::TILE_LAYOUT_STAIRS_DOWN: - ret = Vector2(ret.x * 2, ret.y / 2 - ret.x).floor(); - if (in_top_left_triangle) { - ret += Vector2i(-1, 0); - } else if (in_top_right_triangle) { - ret += Vector2i(1, -1); - } - break; - case TileSet::TILE_LAYOUT_DIAMOND_RIGHT: - ret = Vector2(ret.x - ret.y / 2, ret.y / 2 + ret.x).floor(); - if (in_top_left_triangle) { - ret += Vector2i(0, -1); - } else if (in_top_right_triangle) { - ret += Vector2i(1, 0); - } - break; - case TileSet::TILE_LAYOUT_DIAMOND_DOWN: - ret = Vector2(ret.x + ret.y / 2, ret.y / 2 - ret.x).floor(); - if (in_top_left_triangle) { - ret += Vector2i(-1, 0); - } else if (in_top_right_triangle) { - ret += Vector2i(0, -1); - } - break; - } - } else { // TILE_OFFSET_AXIS_VERTICAL. - // Smart floor of the position. - Vector2 raw_pos = ret; - if (Math::posmod(Math::floor(ret.x), 2) ^ (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET)) { - ret = Vector2(Math::floor(ret.x), Math::floor(ret.y + 0.5) - 0.5); - } else { - ret = ret.floor(); - } - - // Compute the tile offset, and if we might the output for a neighbor top tile. - Vector2 in_tile_pos = raw_pos - ret; - bool in_top_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, -0.5)) > 0; - bool in_bottom_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, 0.5)) <= 0; - - switch (tile_layout) { - case TileSet::TILE_LAYOUT_STACKED: - ret = ret.floor(); - if (in_top_left_triangle) { - ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 0 : -1); - } else if (in_bottom_left_triangle) { - ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 1 : 0); - } - break; - case TileSet::TILE_LAYOUT_STACKED_OFFSET: - ret = ret.floor(); - if (in_top_left_triangle) { - ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? -1 : 0); - } else if (in_bottom_left_triangle) { - ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 0 : 1); - } - break; - case TileSet::TILE_LAYOUT_STAIRS_RIGHT: - ret = Vector2(ret.x / 2 - ret.y, ret.y * 2).floor(); - if (in_top_left_triangle) { - ret += Vector2i(0, -1); - } else if (in_bottom_left_triangle) { - ret += Vector2i(-1, 1); - } - break; - case TileSet::TILE_LAYOUT_STAIRS_DOWN: - ret = Vector2(ret.x, ret.y - ret.x / 2).floor(); - if (in_top_left_triangle) { - ret += Vector2i(-1, 0); - } else if (in_bottom_left_triangle) { - ret += Vector2i(-1, 1); - } - break; - case TileSet::TILE_LAYOUT_DIAMOND_RIGHT: - ret = Vector2(ret.x / 2 - ret.y, ret.y + ret.x / 2).floor(); - if (in_top_left_triangle) { - ret += Vector2i(0, -1); - } else if (in_bottom_left_triangle) { - ret += Vector2i(-1, 0); - } - break; - case TileSet::TILE_LAYOUT_DIAMOND_DOWN: - ret = Vector2(ret.x / 2 + ret.y, ret.y - ret.x / 2).floor(); - if (in_top_left_triangle) { - ret += Vector2i(-1, 0); - } else if (in_bottom_left_triangle) { - ret += Vector2i(0, 1); - } - break; - } - } - } else { - ret = (ret + Vector2(0.00005, 0.00005)).floor(); - } - return Vector2i(ret); + return tile_set->local_to_map(p_pos); } bool TileMap::is_existing_neighbor(TileSet::CellNeighbor p_cell_neighbor) const { ERR_FAIL_COND_V(!tile_set.is_valid(), false); - - TileSet::TileShape shape = tile_set->get_tile_shape(); - if (shape == TileSet::TILE_SHAPE_SQUARE) { - return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER; - - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { - return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; - } else { - if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; - } else { - return p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE || - p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; - } - } + return tile_set->is_existing_neighbor(p_cell_neighbor); } Vector2i TileMap::get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const { - ERR_FAIL_COND_V(!tile_set.is_valid(), p_coords); - - TileSet::TileShape shape = tile_set->get_tile_shape(); - if (shape == TileSet::TILE_SHAPE_SQUARE) { - switch (p_cell_neighbor) { - case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: - return p_coords + Vector2i(1, 0); - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - return p_coords + Vector2i(1, 1); - case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: - return p_coords + Vector2i(0, 1); - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - return p_coords + Vector2i(-1, 1); - case TileSet::CELL_NEIGHBOR_LEFT_SIDE: - return p_coords + Vector2i(-1, 0); - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - return p_coords + Vector2i(-1, -1); - case TileSet::CELL_NEIGHBOR_TOP_SIDE: - return p_coords + Vector2i(0, -1); - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - return p_coords + Vector2i(1, -1); - default: - ERR_FAIL_V(p_coords); - } - } else { // Half-offset shapes (square and hexagon). - switch (tile_set->get_tile_layout()) { - case TileSet::TILE_LAYOUT_STACKED: { - if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - bool is_offset = p_coords.y % 2; - if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { - return p_coords + Vector2i(1, 0); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { - return p_coords + Vector2i(is_offset ? 1 : 0, 1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) { - return p_coords + Vector2i(0, 2); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { - return p_coords + Vector2i(is_offset ? 0 : -1, 1); - } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { - return p_coords + Vector2i(-1, 0); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { - return p_coords + Vector2i(is_offset ? 0 : -1, -1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) { - return p_coords + Vector2i(0, -2); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { - return p_coords + Vector2i(is_offset ? 1 : 0, -1); - } else { - ERR_FAIL_V(p_coords); - } - } else { - bool is_offset = p_coords.x % 2; - - if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { - return p_coords + Vector2i(0, 1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { - return p_coords + Vector2i(1, is_offset ? 1 : 0); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) { - return p_coords + Vector2i(2, 0); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { - return p_coords + Vector2i(1, is_offset ? 0 : -1); - } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) { - return p_coords + Vector2i(0, -1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { - return p_coords + Vector2i(-1, is_offset ? 0 : -1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) { - return p_coords + Vector2i(-2, 0); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { - return p_coords + Vector2i(-1, is_offset ? 1 : 0); - } else { - ERR_FAIL_V(p_coords); - } - } - } break; - case TileSet::TILE_LAYOUT_STACKED_OFFSET: { - if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - bool is_offset = p_coords.y % 2; - - if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { - return p_coords + Vector2i(1, 0); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { - return p_coords + Vector2i(is_offset ? 0 : 1, 1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) { - return p_coords + Vector2i(0, 2); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { - return p_coords + Vector2i(is_offset ? -1 : 0, 1); - } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { - return p_coords + Vector2i(-1, 0); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { - return p_coords + Vector2i(is_offset ? -1 : 0, -1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) { - return p_coords + Vector2i(0, -2); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { - return p_coords + Vector2i(is_offset ? 0 : 1, -1); - } else { - ERR_FAIL_V(p_coords); - } - } else { - bool is_offset = p_coords.x % 2; - - if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { - return p_coords + Vector2i(0, 1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { - return p_coords + Vector2i(1, is_offset ? 0 : 1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) { - return p_coords + Vector2i(2, 0); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { - return p_coords + Vector2i(1, is_offset ? -1 : 0); - } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) { - return p_coords + Vector2i(0, -1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { - return p_coords + Vector2i(-1, is_offset ? -1 : 0); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) { - return p_coords + Vector2i(-2, 0); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { - return p_coords + Vector2i(-1, is_offset ? 0 : 1); - } else { - ERR_FAIL_V(p_coords); - } - } - } break; - case TileSet::TILE_LAYOUT_STAIRS_RIGHT: - case TileSet::TILE_LAYOUT_STAIRS_DOWN: { - if ((tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL)) { - if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { - return p_coords + Vector2i(1, 0); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { - return p_coords + Vector2i(0, 1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) { - return p_coords + Vector2i(-1, 2); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { - return p_coords + Vector2i(-1, 1); - } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { - return p_coords + Vector2i(-1, 0); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { - return p_coords + Vector2i(0, -1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) { - return p_coords + Vector2i(1, -2); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { - return p_coords + Vector2i(1, -1); - } else { - ERR_FAIL_V(p_coords); - } - - } else { - if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { - return p_coords + Vector2i(0, 1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { - return p_coords + Vector2i(1, 0); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) { - return p_coords + Vector2i(2, -1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { - return p_coords + Vector2i(1, -1); - } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) { - return p_coords + Vector2i(0, -1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { - return p_coords + Vector2i(-1, 0); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) { - return p_coords + Vector2i(-2, 1); - - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { - return p_coords + Vector2i(-1, 1); - } else { - ERR_FAIL_V(p_coords); - } - } - } else { - if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { - return p_coords + Vector2i(2, -1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { - return p_coords + Vector2i(1, 0); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) { - return p_coords + Vector2i(0, 1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { - return p_coords + Vector2i(-1, 1); - } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { - return p_coords + Vector2i(-2, 1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { - return p_coords + Vector2i(-1, 0); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) { - return p_coords + Vector2i(0, -1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { - return p_coords + Vector2i(1, -1); - } else { - ERR_FAIL_V(p_coords); - } - - } else { - if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { - return p_coords + Vector2i(-1, 2); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { - return p_coords + Vector2i(0, 1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) { - return p_coords + Vector2i(1, 0); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { - return p_coords + Vector2i(1, -1); - } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) { - return p_coords + Vector2i(1, -2); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { - return p_coords + Vector2i(0, -1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) { - return p_coords + Vector2i(-1, 0); - - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { - return p_coords + Vector2i(-1, 1); - } else { - ERR_FAIL_V(p_coords); - } - } - } - } break; - case TileSet::TILE_LAYOUT_DIAMOND_RIGHT: - case TileSet::TILE_LAYOUT_DIAMOND_DOWN: { - if ((tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL)) { - if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { - return p_coords + Vector2i(1, 1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { - return p_coords + Vector2i(0, 1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) { - return p_coords + Vector2i(-1, 1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { - return p_coords + Vector2i(-1, 0); - } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { - return p_coords + Vector2i(-1, -1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { - return p_coords + Vector2i(0, -1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) { - return p_coords + Vector2i(1, -1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { - return p_coords + Vector2i(1, 0); - } else { - ERR_FAIL_V(p_coords); - } - - } else { - if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { - return p_coords + Vector2i(1, 1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { - return p_coords + Vector2i(1, 0); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) { - return p_coords + Vector2i(1, -1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { - return p_coords + Vector2i(0, -1); - } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) { - return p_coords + Vector2i(-1, -1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { - return p_coords + Vector2i(-1, 0); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) { - return p_coords + Vector2i(-1, 1); - - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { - return p_coords + Vector2i(0, 1); - } else { - ERR_FAIL_V(p_coords); - } - } - } else { - if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { - return p_coords + Vector2i(1, -1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { - return p_coords + Vector2i(1, 0); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) { - return p_coords + Vector2i(1, 1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { - return p_coords + Vector2i(0, 1); - } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { - return p_coords + Vector2i(-1, 1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { - return p_coords + Vector2i(-1, 0); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) { - return p_coords + Vector2i(-1, -1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { - return p_coords + Vector2i(0, -1); - } else { - ERR_FAIL_V(p_coords); - } - - } else { - if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { - return p_coords + Vector2i(-1, 1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { - return p_coords + Vector2i(0, 1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) { - return p_coords + Vector2i(1, 1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { - return p_coords + Vector2i(1, 0); - } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) || - (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) { - return p_coords + Vector2i(1, -1); - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { - return p_coords + Vector2i(0, -1); - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) { - return p_coords + Vector2i(-1, -1); - - } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { - return p_coords + Vector2i(-1, 0); - } else { - ERR_FAIL_V(p_coords); - } - } - } - } break; - default: - ERR_FAIL_V(p_coords); - } - } + ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2i()); + return tile_set->get_neighbor_cell(p_coords, p_cell_neighbor); } TypedArray<Vector2i> TileMap::get_used_cells(int p_layer) const { @@ -1616,7 +953,7 @@ Rect2i TileMap::get_used_rect() const { // Return the visible rect of the tilemap. bool first = true; Rect2i rect = Rect2i(); - for (const Ref<TileMapLayer> &layer : layers) { + for (const TileMapLayer *layer : layers) { Rect2i layer_rect = layer->get_used_rect(); if (layer_rect == Rect2i()) { continue; @@ -1636,7 +973,7 @@ Rect2i TileMap::get_used_rect() const { void TileMap::set_light_mask(int p_light_mask) { // Occlusion: set light mask. CanvasItem::set_light_mask(p_light_mask); - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_LIGHT_MASK); } } @@ -1646,7 +983,7 @@ void TileMap::set_material(const Ref<Material> &p_material) { CanvasItem::set_material(p_material); // Update material for the whole tilemap. - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_MATERIAL); } } @@ -1656,7 +993,7 @@ void TileMap::set_use_parent_material(bool p_use_parent_material) { CanvasItem::set_use_parent_material(p_use_parent_material); // Update use_parent_material for the whole tilemap. - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_USE_PARENT_MATERIAL); } } @@ -1664,7 +1001,7 @@ void TileMap::set_use_parent_material(bool p_use_parent_material) { void TileMap::set_texture_filter(TextureFilter p_texture_filter) { // Set a default texture filter for the whole tilemap. CanvasItem::set_texture_filter(p_texture_filter); - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_TEXTURE_FILTER); } } @@ -1672,7 +1009,7 @@ void TileMap::set_texture_filter(TextureFilter p_texture_filter) { void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) { // Set a default texture repeat for the whole tilemap. CanvasItem::set_texture_repeat(p_texture_repeat); - for (Ref<TileMapLayer> &layer : layers) { + for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT); } } @@ -1771,14 +1108,14 @@ PackedStringArray TileMap::get_configuration_warnings() const { // Retrieve the set of Z index values with a Y-sorted layer. RBSet<int> y_sorted_z_index; - for (const Ref<TileMapLayer> &layer : layers) { + for (const TileMapLayer *layer : layers) { if (layer->is_y_sort_enabled()) { y_sorted_z_index.insert(layer->get_z_index()); } } // Check if we have a non-sorted layer in a Z-index with a Y-sorted layer. - for (const Ref<TileMapLayer> &layer : layers) { + for (const TileMapLayer *layer : layers) { if (!layer->is_y_sort_enabled() && y_sorted_z_index.has(layer->get_z_index())) { 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.")); break; @@ -1787,7 +1124,7 @@ PackedStringArray TileMap::get_configuration_warnings() const { if (!is_y_sort_enabled()) { // Check if Y-sort is enabled on a layer but not on the node. - for (const Ref<TileMapLayer> &layer : layers) { + for (const TileMapLayer *layer : layers) { if (layer->is_y_sort_enabled()) { warnings.push_back(RTR("A TileMap layer is set as Y-sorted, but Y-sort is not enabled on the TileMap node itself.")); break; @@ -1796,7 +1133,7 @@ PackedStringArray TileMap::get_configuration_warnings() const { } else { // Check if Y-sort is enabled on the node, but not on any of the layers. bool need_warning = true; - for (const Ref<TileMapLayer> &layer : layers) { + for (const TileMapLayer *layer : layers) { if (layer->is_y_sort_enabled()) { need_warning = false; break; @@ -1811,7 +1148,7 @@ PackedStringArray TileMap::get_configuration_warnings() const { if (tile_set.is_valid() && tile_set->get_tile_shape() == TileSet::TILE_SHAPE_ISOMETRIC) { bool warn = !is_y_sort_enabled(); if (!warn) { - for (const Ref<TileMapLayer> &layer : layers) { + for (const TileMapLayer *layer : layers) { if (!layer->is_y_sort_enabled()) { warn = true; break; @@ -1926,42 +1263,27 @@ void TileMap::_bind_methods() { void TileMap::_tile_set_changed() { emit_signal(CoreStringNames::get_singleton()->changed); - for (Ref<TileMapLayer> layer : layers) { + for (TileMapLayer *layer : layers) { layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_TILE_SET); } update_configuration_warnings(); } -void TileMap::_update_notify_local_transform() { - bool notify = collision_animatable || is_y_sort_enabled(); - if (!notify) { - for (const Ref<TileMapLayer> &layer : layers) { - if (layer->is_y_sort_enabled()) { - notify = true; - break; - } - } - } - set_notify_local_transform(notify); -} - TileMap::TileMap() { - set_notify_transform(true); - _update_notify_local_transform(); - - Ref<TileMapLayer> new_layer; - new_layer.instantiate(); - new_layer->set_tile_map(this); + TileMapLayer *new_layer = memnew(TileMapLayer); + add_child(new_layer); + new_layer->set_name("Layer0"); new_layer->set_layer_index_in_tile_map_node(0); layers.push_back(new_layer); - default_layer.instantiate(); + default_layer = memnew(TileMapLayer); } TileMap::~TileMap() { if (tile_set.is_valid()) { tile_set->disconnect_changed(callable_mp(this, &TileMap::_tile_set_changed)); } + memdelete(default_layer); } #undef TILEMAP_CALL_FOR_LAYER diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 29af0ad2b1..f2b481cdd1 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -71,18 +71,17 @@ private: VisibilityMode navigation_visibility_mode = VISIBILITY_MODE_DEFAULT; // Layers. - LocalVector<Ref<TileMapLayer>> layers; - Ref<TileMapLayer> default_layer; // Dummy layer to fetch default values. + LocalVector<TileMapLayer *> layers; + TileMapLayer *default_layer; // Dummy layer to fetch default values. int selected_layer = -1; bool pending_update = false; + // Transforms for collision_animatable. Transform2D last_valid_transform; Transform2D new_transform; void _tile_set_changed(); - void _update_notify_local_transform(); - protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; @@ -97,6 +96,8 @@ protected: Rect2i _get_used_rect_bind_compat_78328(); void _set_quadrant_size_compat_81070(int p_quadrant_size); int _get_quadrant_size_compat_81070() const; + VisibilityMode _get_collision_visibility_mode_bind_compat_87115(); + VisibilityMode _get_navigation_visibility_mode_bind_compat_87115(); static void _bind_compatibility_methods(); #endif @@ -150,15 +151,15 @@ public: void set_selected_layer(int p_layer_id); // For editor use. int get_selected_layer() const; - void set_collision_animatable(bool p_enabled); + void set_collision_animatable(bool p_collision_animatable); bool is_collision_animatable() const; // Debug visibility modes. void set_collision_visibility_mode(VisibilityMode p_show_collision); - VisibilityMode get_collision_visibility_mode(); + VisibilityMode get_collision_visibility_mode() const; void set_navigation_visibility_mode(VisibilityMode p_show_navigation); - VisibilityMode get_navigation_visibility_mode(); + VisibilityMode get_navigation_visibility_mode() const; // Cells accessors. void set_cell(int p_layer, 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); @@ -192,7 +193,6 @@ public: Vector2 map_to_local(const Vector2i &p_pos) const; Vector2i local_to_map(const Vector2 &p_pos) const; - bool is_existing_neighbor(TileSet::CellNeighbor p_cell_neighbor) const; Vector2i get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const; diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp index ed93b8d051..df79b3fee6 100644 --- a/scene/2d/tile_map_layer.cpp +++ b/scene/2d/tile_map_layer.cpp @@ -40,6 +40,18 @@ #include "servers/navigation_server_3d.h" #endif // DEBUG_ENABLED +TileMap *TileMapLayer::_fetch_tilemap() const { + return TileMap::cast_to<TileMap>(get_parent()); +} + +Ref<TileSet> TileMapLayer::_fetch_tileset() const { + TileMap *tile_map_node = _fetch_tilemap(); + if (!tile_map_node) { + return Ref<TileSet>(); + } + return tile_map_node->get_tileset(); +} + #ifdef DEBUG_ENABLED /////////////////////////////// Debug ////////////////////////////////////////// constexpr int TILE_MAP_DEBUG_QUADRANT_SIZE = 16; @@ -51,11 +63,11 @@ Vector2i TileMapLayer::_coords_to_debug_quadrant_coords(const Vector2i &p_coords } void TileMapLayer::_debug_update() { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); RenderingServer *rs = RenderingServer::get_singleton(); // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree(); + bool forced_cleanup = in_destructor || !enabled || !tile_set.is_valid() || !is_visible_in_tree(); if (forced_cleanup) { for (KeyValue<Vector2i, Ref<DebugQuadrant>> &kv : debug_quadrant_map) { @@ -120,10 +132,10 @@ void TileMapLayer::_debug_update() { } else { ci = rs->canvas_item_create(); rs->canvas_item_set_z_index(ci, RS::CANVAS_ITEM_Z_MAX - 1); - rs->canvas_item_set_parent(ci, tile_map_node->get_canvas_item()); + rs->canvas_item_set_parent(ci, get_canvas_item()); } - const Vector2 quadrant_pos = tile_map_node->map_to_local(debug_quadrant.quadrant_coords * TILE_MAP_DEBUG_QUADRANT_SIZE); + const Vector2 quadrant_pos = tile_set->map_to_local(debug_quadrant.quadrant_coords * TILE_MAP_DEBUG_QUADRANT_SIZE); Transform2D xform(0, quadrant_pos); rs->canvas_item_set_transform(ci, xform); @@ -179,48 +191,33 @@ void TileMapLayer::_debug_quadrants_update_cell(CellData &r_cell_data, SelfList< /////////////////////////////// Rendering ////////////////////////////////////// void TileMapLayer::_rendering_update() { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const TileMap *tile_map_node = _fetch_tilemap(); + const Ref<TileSet> &tile_set = _fetch_tileset(); RenderingServer *rs = RenderingServer::get_singleton(); // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree(); + bool forced_cleanup = in_destructor || !enabled || !tile_set.is_valid() || !is_visible_in_tree(); // ----------- Layer level processing ----------- - if (forced_cleanup) { - // Cleanup. - if (canvas_item.is_valid()) { - rs->free(canvas_item); - canvas_item = RID(); - } - } else { - // Create/Update the layer's CanvasItem. - if (!canvas_item.is_valid()) { - RID ci = rs->canvas_item_create(); - rs->canvas_item_set_parent(ci, tile_map_node->get_canvas_item()); - canvas_item = ci; - } - RID &ci = canvas_item; - rs->canvas_item_set_draw_index(ci, layer_index_in_tile_map_node - (int64_t)0x80000000); - rs->canvas_item_set_sort_children_by_y(ci, y_sort_enabled); - rs->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid()); - rs->canvas_item_set_z_index(ci, z_index); - rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree())); - rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree())); - rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask()); + if (!forced_cleanup) { + // Update the layer's CanvasItem. + set_use_parent_material(true); + set_light_mask(tile_map_node->get_light_mask()); // Modulate the layer. - Color layer_modulate = modulate; + Color layer_modulate = get_modulate(); int selected_layer = tile_map_node->get_selected_layer(); if (selected_layer >= 0 && layer_index_in_tile_map_node != selected_layer) { int z_selected = tile_map_node->get_layer_z_index(selected_layer); - if (z_index < z_selected || (z_index == z_selected && layer_index_in_tile_map_node < selected_layer)) { + int layer_z_index = get_z_index(); + if (layer_z_index < z_selected || (layer_z_index == z_selected && layer_index_in_tile_map_node < selected_layer)) { layer_modulate = layer_modulate.darkened(0.5); - } else if (z_index > z_selected || (z_index == z_selected && layer_index_in_tile_map_node > selected_layer)) { + } else if (layer_z_index > z_selected || (layer_z_index == z_selected && layer_index_in_tile_map_node > selected_layer)) { layer_modulate = layer_modulate.darkened(0.5); layer_modulate.a *= 0.3; } } - rs->canvas_item_set_modulate(ci, layer_modulate); + rs->canvas_item_set_modulate(get_canvas_item(), layer_modulate); } // ----------- Quadrants processing ----------- @@ -231,7 +228,7 @@ void TileMapLayer::_rendering_update() { // Check if anything changed that might change the quadrant shape. // If so, recreate everything. bool quandrant_shape_changed = dirty.flags[DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE] || - (tile_map_node->is_y_sort_enabled() && y_sort_enabled && (dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] || dirty.flags[DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_TILE_MAP_LOCAL_XFORM] || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET])); + (is_y_sort_enabled() && (dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] || dirty.flags[DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_LOCAL_TRANSFORM] || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET])); // Free all quadrants. if (forced_cleanup || quandrant_shape_changed) { @@ -250,7 +247,7 @@ void TileMapLayer::_rendering_update() { if (!forced_cleanup) { // List all quadrants to update, recreating them if needed. - if (dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || _rendering_was_cleaned_up) { + if (dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE] || _rendering_was_cleaned_up) { // Update all cells. for (KeyValue<Vector2i, CellData> &kv : tile_map) { CellData &cell_data = kv.value; @@ -290,7 +287,7 @@ void TileMapLayer::_rendering_update() { rendering_quadrant->canvas_items.clear(); // Sort the quadrant cells. - if (tile_map_node->is_y_sort_enabled() && is_y_sort_enabled()) { + if (is_y_sort_enabled()) { // For compatibility reasons, we use another comparator for Y-sorted layers. rendering_quadrant->cells.sort_custom<CellDataYSortedComparator>(); } else { @@ -330,8 +327,8 @@ void TileMapLayer::_rendering_update() { if (mat.is_valid()) { rs->canvas_item_set_material(ci, mat->get_rid()); } - rs->canvas_item_set_parent(ci, canvas_item); - rs->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid()); + rs->canvas_item_set_parent(ci, get_canvas_item()); + rs->canvas_item_set_use_parent_material(ci, true); Transform2D xform(0, rendering_quadrant->canvas_items_position); rs->canvas_item_set_transform(ci, xform); @@ -340,8 +337,8 @@ void TileMapLayer::_rendering_update() { rs->canvas_item_set_z_as_relative_to_parent(ci, true); rs->canvas_item_set_z_index(ci, tile_z_index); - rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree())); - rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree())); + rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree())); + rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree())); rendering_quadrant->canvas_items.push_back(ci); @@ -354,7 +351,7 @@ void TileMapLayer::_rendering_update() { ci = prev_ci; } - const Vector2 local_tile_pos = tile_map_node->map_to_local(cell_data.coords); + const Vector2 local_tile_pos = tile_set->map_to_local(cell_data.coords); // Random animation offset. real_t random_animation_offset = 0.0; @@ -366,7 +363,7 @@ void TileMapLayer::_rendering_update() { } // Drawing the tile in the canvas item. - tile_map_node->draw_tile(ci, local_tile_pos - rendering_quadrant->canvas_items_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); + TileMap::draw_tile(ci, local_tile_pos - rendering_quadrant->canvas_items_position, tile_set, cell_data.cell.source_id, cell_data.cell.get_atlas_coords(), cell_data.cell.alternative_tile, -1, get_self_modulate(), tile_data, random_animation_offset); } } else { // Free the quadrant. @@ -393,7 +390,7 @@ void TileMapLayer::_rendering_update() { RBMap<Vector2, Ref<RenderingQuadrant>, RenderingQuadrant::CoordsWorldComparator> local_to_map; for (KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) { Ref<RenderingQuadrant> &rendering_quadrant = kv.value; - local_to_map[tile_map_node->map_to_local(rendering_quadrant->quadrant_coords)] = rendering_quadrant; + local_to_map[tile_set->map_to_local(rendering_quadrant->quadrant_coords)] = rendering_quadrant; } // Sort the quadrants. @@ -409,14 +406,15 @@ void TileMapLayer::_rendering_update() { dirty.flags[DIRTY_FLAGS_TILE_MAP_USE_PARENT_MATERIAL] || dirty.flags[DIRTY_FLAGS_TILE_MAP_MATERIAL] || dirty.flags[DIRTY_FLAGS_TILE_MAP_TEXTURE_FILTER] || - dirty.flags[DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT]) { + dirty.flags[DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT] || + dirty.flags[DIRTY_FLAGS_LAYER_SELF_MODULATE]) { for (KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) { Ref<RenderingQuadrant> &rendering_quadrant = kv.value; for (const RID &ci : rendering_quadrant->canvas_items) { rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask()); - rs->canvas_item_set_use_parent_material(ci, tile_map_node->get_use_parent_material() || tile_map_node->get_material().is_valid()); - rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(tile_map_node->get_texture_filter_in_tree())); - rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(tile_map_node->get_texture_repeat_in_tree())); + rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree())); + rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree())); + rs->canvas_item_set_self_modulate(ci, get_self_modulate()); } } } @@ -441,30 +439,37 @@ void TileMapLayer::_rendering_update() { _rendering_occluders_update_cell(cell_data); } } + } - // Updates on TileMap changes. - if (dirty.flags[DIRTY_FLAGS_TILE_MAP_IN_CANVAS] || dirty.flags[DIRTY_FLAGS_TILE_MAP_VISIBILITY]) { + // ----------- + // Mark the rendering state as up to date. + _rendering_was_cleaned_up = forced_cleanup; +} + +void TileMapLayer::_rendering_notification(int p_what) { + RenderingServer *rs = RenderingServer::get_singleton(); + const Ref<TileSet> &tile_set = _fetch_tileset(); + if (p_what == NOTIFICATION_TRANSFORM_CHANGED || p_what == NOTIFICATION_ENTER_CANVAS || p_what == NOTIFICATION_VISIBILITY_CHANGED) { + if (tile_set.is_valid()) { + Transform2D tilemap_xform = get_global_transform(); for (KeyValue<Vector2i, CellData> &kv : tile_map) { - CellData &cell_data = kv.value; + const CellData &cell_data = kv.value; for (const RID &occluder : cell_data.occluders) { if (occluder.is_null()) { continue; } - Transform2D xform(0, tile_map_node->map_to_local(kv.key)); - rs->canvas_light_occluder_attach_to_canvas(occluder, tile_map_node->get_canvas()); - rs->canvas_light_occluder_set_transform(occluder, tile_map_node->get_global_transform() * xform); + Transform2D xform(0, tile_set->map_to_local(kv.key)); + rs->canvas_light_occluder_attach_to_canvas(occluder, get_canvas()); + rs->canvas_light_occluder_set_transform(occluder, tilemap_xform * xform); } } } } - - // ----------- - // Mark the rendering state as up to date. - _rendering_was_cleaned_up = forced_cleanup; } void TileMapLayer::_rendering_quadrants_update_cell(CellData &r_cell_data, SelfList<RenderingQuadrant>::List &r_dirty_rendering_quadrant_list) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const TileMap *tile_map_node = _fetch_tilemap(); + const Ref<TileSet> &tile_set = _fetch_tileset(); // Check if the cell is valid and retrieve its y_sort_origin. bool is_valid = false; @@ -489,8 +494,8 @@ void TileMapLayer::_rendering_quadrants_update_cell(CellData &r_cell_data, SelfL // Get the quadrant coords. Vector2 canvas_items_position; Vector2i quadrant_coords; - if (tile_map_node->is_y_sort_enabled() && is_y_sort_enabled()) { - canvas_items_position = Vector2(0, tile_map_node->map_to_local(r_cell_data.coords).y + tile_y_sort_origin + y_sort_origin); + if (is_y_sort_enabled()) { + canvas_items_position = Vector2(0, tile_set->map_to_local(r_cell_data.coords).y + tile_y_sort_origin + y_sort_origin); quadrant_coords = canvas_items_position * 100; } else { int quad_size = tile_map_node->get_rendering_quadrant_size(); @@ -500,7 +505,7 @@ void TileMapLayer::_rendering_quadrants_update_cell(CellData &r_cell_data, SelfL quadrant_coords = Vector2i( coords.x > 0 ? coords.x / quad_size : (coords.x - (quad_size - 1)) / quad_size, coords.y > 0 ? coords.y / quad_size : (coords.y - (quad_size - 1)) / quad_size); - canvas_items_position = tile_map_node->map_to_local(quad_size * quadrant_coords); + canvas_items_position = tile_set->map_to_local(quad_size * quadrant_coords); } Ref<RenderingQuadrant> rendering_quadrant; @@ -564,8 +569,7 @@ void TileMapLayer::_rendering_occluders_clear_cell(CellData &r_cell_data) { } void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) { - bool node_visible = tile_map_node->is_visible_in_tree(); - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); RenderingServer *rs = RenderingServer::get_singleton(); // Free unused occluders then resize the occluders array. @@ -606,14 +610,13 @@ void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) { if (occluder_polygon.is_valid()) { // Create or update occluder. Transform2D xform; - xform.set_origin(tile_map_node->map_to_local(r_cell_data.coords)); + xform.set_origin(tile_set->map_to_local(r_cell_data.coords)); if (!occluder.is_valid()) { occluder = rs->canvas_light_occluder_create(); } - rs->canvas_light_occluder_set_enabled(occluder, node_visible); - rs->canvas_light_occluder_set_transform(occluder, tile_map_node->get_global_transform() * xform); + rs->canvas_light_occluder_set_transform(occluder, get_global_transform() * xform); rs->canvas_light_occluder_set_polygon(occluder, tile_data->get_occluder(occlusion_layer_index, flip_h, flip_v, transpose)->get_rid()); - rs->canvas_light_occluder_attach_to_canvas(occluder, tile_map_node->get_canvas()); + rs->canvas_light_occluder_attach_to_canvas(occluder, get_canvas()); rs->canvas_light_occluder_set_light_mask(occluder, tile_set->get_occlusion_layer_light_mask(occlusion_layer_index)); } else { // Clear occluder. @@ -635,7 +638,7 @@ void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) { #ifdef DEBUG_ENABLED void TileMapLayer::_rendering_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); ERR_FAIL_COND(!tile_set.is_valid()); if (!Engine::get_singleton()->is_editor_hint()) { @@ -671,7 +674,7 @@ void TileMapLayer::_rendering_draw_cell_debug(const RID &p_canvas_item, const Ve // Draw a placeholder tile. Transform2D cell_to_quadrant; - cell_to_quadrant.set_origin(tile_map_node->map_to_local(r_cell_data.coords) - p_quadrant_pos); + cell_to_quadrant.set_origin(tile_set->map_to_local(r_cell_data.coords) - p_quadrant_pos); rs->canvas_item_add_set_transform(p_canvas_item, cell_to_quadrant); 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); } @@ -684,17 +687,17 @@ void TileMapLayer::_rendering_draw_cell_debug(const RID &p_canvas_item, const Ve /////////////////////////////// Physics ////////////////////////////////////// void TileMapLayer::_physics_update() { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid(); + bool forced_cleanup = in_destructor || !enabled || !is_inside_tree() || !tile_set.is_valid(); if (forced_cleanup) { // Clean everything. for (KeyValue<Vector2i, CellData> &kv : tile_map) { _physics_clear_cell(kv.value); } } else { - if (_physics_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || dirty.flags[DIRTY_FLAGS_TILE_MAP_COLLISION_ANIMATABLE]) { + if (_physics_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_USE_KINEMATIC_BODIES] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) { // Update all cells. for (KeyValue<Vector2i, CellData> &kv : tile_map) { _physics_update_cell(kv.value); @@ -713,60 +716,43 @@ void TileMapLayer::_physics_update() { _physics_was_cleaned_up = forced_cleanup; } -void TileMapLayer::_physics_notify_tilemap_change(TileMapLayer::DirtyFlags p_what) { - Transform2D gl_transform = tile_map_node->get_global_transform(); +void TileMapLayer::_physics_notification(int p_what) { + const Ref<TileSet> &tile_set = _fetch_tileset(); + Transform2D gl_transform = get_global_transform(); PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); - bool in_editor = false; -#ifdef TOOLS_ENABLED - in_editor = Engine::get_singleton()->is_editor_hint(); -#endif - - if (p_what == DIRTY_FLAGS_TILE_MAP_XFORM) { - if (tile_map_node->is_inside_tree() && (!tile_map_node->is_collision_animatable() || in_editor)) { + switch (p_what) { + case NOTIFICATION_TRANSFORM_CHANGED: // Move the collisison shapes along with the TileMap. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - const CellData &cell_data = kv.value; + if (is_inside_tree() && tile_set.is_valid()) { + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + const CellData &cell_data = kv.value; - for (RID body : cell_data.bodies) { - if (body.is_valid()) { - Transform2D xform(0, tile_map_node->map_to_local(bodies_coords[body])); - xform = gl_transform * xform; - ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform); - } - } - } - } - } else if (p_what == DIRTY_FLAGS_TILE_MAP_LOCAL_XFORM) { - // With collisions animatable, move the collisison shapes along with the TileMap only on local xform change (they are synchornized on physics tick instead). - if (tile_map_node->is_inside_tree() && tile_map_node->is_collision_animatable() && !in_editor) { - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - const CellData &cell_data = kv.value; - - for (RID body : cell_data.bodies) { - if (body.is_valid()) { - Transform2D xform(0, tile_map_node->map_to_local(bodies_coords[body])); - xform = gl_transform * xform; - ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform); + for (RID body : cell_data.bodies) { + if (body.is_valid()) { + Transform2D xform(0, tile_set->map_to_local(kv.key)); + xform = gl_transform * xform; + ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform); + } } } } - } - } else if (p_what == DIRTY_FLAGS_TILE_MAP_IN_TREE) { - // Changes in the tree may cause the space to change (e.g. when reparenting to a SubViewport). - if (tile_map_node->is_inside_tree()) { - RID space = tile_map_node->get_world_2d()->get_space(); + break; + case NOTIFICATION_ENTER_TREE: + // Changes in the tree may cause the space to change (e.g. when reparenting to a SubViewport). + if (is_inside_tree()) { + RID space = get_world_2d()->get_space(); - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - const CellData &cell_data = kv.value; + for (KeyValue<Vector2i, CellData> &kv : tile_map) { + const CellData &cell_data = kv.value; - for (RID body : cell_data.bodies) { - if (body.is_valid()) { - ps->body_set_space(body, space); + for (RID body : cell_data.bodies) { + if (body.is_valid()) { + ps->body_set_space(body, space); + } } } } - } } } @@ -784,9 +770,10 @@ void TileMapLayer::_physics_clear_cell(CellData &r_cell_data) { } void TileMapLayer::_physics_update_cell(CellData &r_cell_data) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); - Transform2D gl_transform = tile_map_node->get_global_transform(); - RID space = tile_map_node->get_world_2d()->get_space(); + const TileMap *tile_map_node = _fetch_tilemap(); + const Ref<TileSet> &tile_set = _fetch_tileset(); + Transform2D gl_transform = get_global_transform(); + RID space = get_world_2d()->get_space(); PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); // Recreate bodies and shapes. @@ -813,10 +800,11 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) { // Free unused bodies then resize the bodies array. for (uint32_t i = tile_set->get_physics_layers_count(); i < r_cell_data.bodies.size(); i++) { - RID body = r_cell_data.bodies[i]; + RID &body = r_cell_data.bodies[i]; if (body.is_valid()) { bodies_coords.erase(body); ps->free(body); + body = RID(); } } r_cell_data.bodies.resize(tile_set->get_physics_layers_count()); @@ -844,7 +832,7 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) { ps->body_set_space(body, space); Transform2D xform; - xform.set_origin(tile_map_node->map_to_local(r_cell_data.coords)); + xform.set_origin(tile_set->map_to_local(r_cell_data.coords)); xform = gl_transform * xform; ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform); @@ -900,17 +888,18 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) { #ifdef DEBUG_ENABLED void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data) { // Draw the debug collision shapes. - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + TileMap *tile_map_node = _fetch_tilemap(); + const Ref<TileSet> &tile_set = _fetch_tileset(); ERR_FAIL_COND(!tile_set.is_valid()); - if (!tile_map_node->get_tree()) { + if (!get_tree()) { return; } bool show_collision = false; switch (tile_map_node->get_collision_visibility_mode()) { case TileMap::VISIBILITY_MODE_DEFAULT: - show_collision = !Engine::get_singleton()->is_editor_hint() && tile_map_node->get_tree()->is_debugging_collisions_hint(); + show_collision = !Engine::get_singleton()->is_editor_hint() && get_tree()->is_debugging_collisions_hint(); break; case TileMap::VISIBILITY_MODE_FORCE_HIDE: show_collision = false; @@ -926,12 +915,12 @@ void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vect RenderingServer *rs = RenderingServer::get_singleton(); PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); - Color debug_collision_color = tile_map_node->get_tree()->get_debug_collisions_color(); + Color debug_collision_color = get_tree()->get_debug_collisions_color(); Vector<Color> color; color.push_back(debug_collision_color); Transform2D quadrant_to_local(0, p_quadrant_pos); - Transform2D global_to_quadrant = (tile_map_node->get_global_transform() * quadrant_to_local).affine_inverse(); + Transform2D global_to_quadrant = (get_global_transform() * quadrant_to_local).affine_inverse(); for (RID body : r_cell_data.bodies) { if (body.is_valid()) { @@ -956,11 +945,11 @@ void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vect void TileMapLayer::_navigation_update() { ERR_FAIL_NULL(NavigationServer2D::get_singleton()); - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); NavigationServer2D *ns = NavigationServer2D::get_singleton(); // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !navigation_enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid(); + bool forced_cleanup = in_destructor || !enabled || !navigation_enabled || !is_inside_tree() || !tile_set.is_valid(); // ----------- Layer level processing ----------- if (forced_cleanup) { @@ -973,7 +962,7 @@ void TileMapLayer::_navigation_update() { if (!navigation_map.is_valid()) { if (layer_index_in_tile_map_node == 0) { // Use the default World2D navigation map for the first layer when empty. - navigation_map = tile_map_node->get_world_2d()->get_navigation_map(); + navigation_map = get_world_2d()->get_navigation_map(); uses_world_navigation_map = true; } else { RID new_layer_map = ns->map_create(); @@ -993,7 +982,7 @@ void TileMapLayer::_navigation_update() { _navigation_clear_cell(kv.value); } } else { - if (_navigation_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) { + if (_navigation_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) { // Update all cells. for (KeyValue<Vector2i, CellData> &kv : tile_map) { _navigation_update_cell(kv.value); @@ -1005,9 +994,18 @@ void TileMapLayer::_navigation_update() { _navigation_update_cell(cell_data); } } + } + + // ----------- + // Mark the navigation state as up to date. + _navigation_was_cleaned_up = forced_cleanup; +} - if (dirty.flags[DIRTY_FLAGS_TILE_MAP_XFORM]) { - Transform2D tilemap_xform = tile_map_node->get_global_transform(); +void TileMapLayer::_navigation_notification(int p_what) { + const Ref<TileSet> &tile_set = _fetch_tileset(); + if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { + if (tile_set.is_valid()) { + Transform2D tilemap_xform = get_global_transform(); for (KeyValue<Vector2i, CellData> &kv : tile_map) { const CellData &cell_data = kv.value; // Update navigation regions transform. @@ -1016,16 +1014,12 @@ void TileMapLayer::_navigation_update() { continue; } Transform2D tile_transform; - tile_transform.set_origin(tile_map_node->map_to_local(kv.key)); + tile_transform.set_origin(tile_set->map_to_local(kv.key)); NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform); } } } } - - // ----------- - // Mark the navigation state as up to date. - _navigation_was_cleaned_up = forced_cleanup; } void TileMapLayer::_navigation_clear_cell(CellData &r_cell_data) { @@ -1042,9 +1036,10 @@ void TileMapLayer::_navigation_clear_cell(CellData &r_cell_data) { } void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const TileMap *tile_map_node = _fetch_tilemap(); + const Ref<TileSet> &tile_set = _fetch_tileset(); NavigationServer2D *ns = NavigationServer2D::get_singleton(); - Transform2D tilemap_xform = tile_map_node->get_global_transform(); + Transform2D gl_xform = get_global_transform(); // Get the navigation polygons and create regions. TileMapCell &c = r_cell_data.cell; @@ -1088,13 +1083,13 @@ void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) { if (navigation_polygon.is_valid() && (navigation_polygon->get_polygon_count() > 0 || navigation_polygon->get_outline_count() > 0)) { // Create or update regions. Transform2D tile_transform; - tile_transform.set_origin(tile_map_node->map_to_local(r_cell_data.coords)); + tile_transform.set_origin(tile_set->map_to_local(r_cell_data.coords)); if (!region.is_valid()) { region = ns->region_create(); } ns->region_set_owner_id(region, tile_map_node->get_instance_id()); ns->region_set_map(region, navigation_map); - ns->region_set_transform(region, tilemap_xform * tile_transform); + ns->region_set_transform(region, gl_xform * tile_transform); ns->region_set_navigation_layers(region, tile_set->get_navigation_layer_layers(navigation_layer_index)); ns->region_set_navigation_polygon(region, navigation_polygon); } else { @@ -1119,10 +1114,11 @@ void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) { #ifdef DEBUG_ENABLED void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data) { // Draw the debug collision shapes. + const TileMap *tile_map_node = _fetch_tilemap(); bool show_navigation = false; switch (tile_map_node->get_navigation_visibility_mode()) { case TileMap::VISIBILITY_MODE_DEFAULT: - show_navigation = !Engine::get_singleton()->is_editor_hint() && tile_map_node->get_tree()->is_debugging_navigation_hint(); + show_navigation = !Engine::get_singleton()->is_editor_hint() && get_tree()->is_debugging_navigation_hint(); break; case TileMap::VISIBILITY_MODE_FORCE_HIDE: show_navigation = false; @@ -1140,7 +1136,7 @@ void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const V return; } - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); RenderingServer *rs = RenderingServer::get_singleton(); const NavigationServer2D *ns2d = NavigationServer2D::get_singleton(); @@ -1170,7 +1166,7 @@ void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const V } Transform2D cell_to_quadrant; - cell_to_quadrant.set_origin(tile_map_node->map_to_local(r_cell_data.coords) - p_quadrant_pos); + cell_to_quadrant.set_origin(tile_set->map_to_local(r_cell_data.coords) - p_quadrant_pos); rs->canvas_item_add_set_transform(p_canvas_item, cell_to_quadrant); for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) { @@ -1226,10 +1222,10 @@ void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const V /////////////////////////////// Scenes ////////////////////////////////////// void TileMapLayer::_scenes_update() { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid(); + bool forced_cleanup = in_destructor || !enabled || !is_inside_tree() || !tile_set.is_valid(); if (forced_cleanup) { // Clean everything. @@ -1237,7 +1233,7 @@ void TileMapLayer::_scenes_update() { _scenes_clear_cell(kv.value); } } else { - if (_scenes_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) { + if (_scenes_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) { // Update all cells. for (KeyValue<Vector2i, CellData> &kv : tile_map) { _scenes_update_cell(kv.value); @@ -1257,6 +1253,11 @@ void TileMapLayer::_scenes_update() { } void TileMapLayer::_scenes_clear_cell(CellData &r_cell_data) { + const TileMap *tile_map_node = _fetch_tilemap(); + if (!tile_map_node) { + return; + } + // Cleanup existing scene. Node *node = tile_map_node->get_node_or_null(r_cell_data.scene); if (node) { @@ -1266,7 +1267,8 @@ void TileMapLayer::_scenes_clear_cell(CellData &r_cell_data) { } void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + TileMap *tile_map_node = _fetch_tilemap(); + const Ref<TileSet> &tile_set = _fetch_tileset(); // Clear the scene in any case. _scenes_clear_cell(r_cell_data); @@ -1287,10 +1289,10 @@ void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) { 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(tile_map_node->map_to_local(r_cell_data.coords) + scene_as_control->get_position()); + scene_as_control->set_position(tile_set->map_to_local(r_cell_data.coords) + scene_as_control->get_position()); } else if (scene_as_node2d) { Transform2D xform; - xform.set_origin(tile_map_node->map_to_local(r_cell_data.coords)); + xform.set_origin(tile_set->map_to_local(r_cell_data.coords)); scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform()); } tile_map_node->add_child(scene); @@ -1303,7 +1305,7 @@ void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) { #ifdef DEBUG_ENABLED void TileMapLayer::_scenes_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); ERR_FAIL_COND(!tile_set.is_valid()); if (!Engine::get_singleton()->is_editor_hint()) { @@ -1341,7 +1343,7 @@ void TileMapLayer::_scenes_draw_cell_debug(const RID &p_canvas_item, const Vecto // Draw a placeholder tile. Transform2D cell_to_quadrant; - cell_to_quadrant.set_origin(tile_map_node->map_to_local(r_cell_data.coords) - p_quadrant_pos); + cell_to_quadrant.set_origin(tile_set->map_to_local(r_cell_data.coords) - p_quadrant_pos); rs->canvas_item_add_set_transform(p_canvas_item, cell_to_quadrant); 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); } @@ -1353,10 +1355,11 @@ void TileMapLayer::_scenes_draw_cell_debug(const RID &p_canvas_item, const Vecto ///////////////////////////////////////////////////////////////////// void TileMapLayer::_build_runtime_update_tile_data() { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const TileMap *tile_map_node = _fetch_tilemap(); + const Ref<TileSet> &tile_set = _fetch_tileset(); // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !tile_map_node->is_inside_tree() || !tile_set.is_valid() || !tile_map_node->is_visible_in_tree(); + bool forced_cleanup = in_destructor || !enabled || !tile_set.is_valid() || !is_visible_in_tree(); if (!forced_cleanup) { if (tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update)) { if (_runtime_update_tile_data_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_MAP_TILE_SET]) { @@ -1382,7 +1385,8 @@ void TileMapLayer::_build_runtime_update_tile_data() { } void TileMapLayer::_build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_auto_add_to_dirty_list) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + TileMap *tile_map_node = _fetch_tilemap(); + const Ref<TileSet> &tile_set = _fetch_tileset(); TileMapCell &c = r_cell_data.cell; TileSetSource *source; @@ -1425,7 +1429,7 @@ void TileMapLayer::_clear_runtime_update_tile_data() { } TileSet::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) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); if (!tile_set.is_valid()) { return TileSet::TerrainsPattern(); } @@ -1437,7 +1441,7 @@ TileSet::TerrainsPattern TileMapLayer::_get_best_terrain_pattern_for_constraints int score = 0; // Check the center bit constraint. - TerrainConstraint terrain_constraint = TerrainConstraint(tile_map_node, p_position, terrain_pattern.get_terrain()); + TerrainConstraint terrain_constraint = TerrainConstraint(tile_set, p_position, terrain_pattern.get_terrain()); const RBSet<TerrainConstraint>::Element *in_set_constraint_element = p_constraints.find(terrain_constraint); if (in_set_constraint_element) { if (in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) { @@ -1453,7 +1457,7 @@ TileSet::TerrainsPattern TileMapLayer::_get_best_terrain_pattern_for_constraints TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { // Check if the bit is compatible with the constraints. - TerrainConstraint terrain_bit_constraint = TerrainConstraint(tile_map_node, p_position, bit, terrain_pattern.get_terrain_peering_bit(bit)); + TerrainConstraint terrain_bit_constraint = TerrainConstraint(tile_set, p_position, bit, terrain_pattern.get_terrain_peering_bit(bit)); in_set_constraint_element = p_constraints.find(terrain_bit_constraint); if (in_set_constraint_element) { if (in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) { @@ -1486,19 +1490,19 @@ TileSet::TerrainsPattern TileMapLayer::_get_best_terrain_pattern_for_constraints } RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); if (!tile_set.is_valid()) { return RBSet<TerrainConstraint>(); } // Compute the constraints needed from the surrounding tiles. RBSet<TerrainConstraint> output; - output.insert(TerrainConstraint(tile_map_node, p_position, p_terrains_pattern.get_terrain())); + output.insert(TerrainConstraint(tile_set, p_position, p_terrains_pattern.get_terrain())); for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { TileSet::CellNeighbor side = TileSet::CellNeighbor(i); if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, side)) { - TerrainConstraint c = TerrainConstraint(tile_map_node, p_position, side, p_terrains_pattern.get_terrain_peering_bit(side)); + TerrainConstraint c = TerrainConstraint(tile_set, p_position, side, p_terrains_pattern.get_terrain_peering_bit(side)); output.insert(c); } } @@ -1507,7 +1511,7 @@ RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_added_patte } RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_painted_cells_list(const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); if (!tile_set.is_valid()) { return RBSet<TerrainConstraint>(); } @@ -1520,7 +1524,7 @@ RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_painted_cel for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over neighbor bits. TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { - dummy_constraints.insert(TerrainConstraint(tile_map_node, E, bit, -1)); + dummy_constraints.insert(TerrainConstraint(tile_set, E, bit, -1)); } } } @@ -1587,27 +1591,89 @@ RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_painted_cel int terrain = (tile_data && tile_data->get_terrain_set() == p_terrain_set) ? tile_data->get_terrain() : -1; if (!p_ignore_empty_terrains || terrain >= 0) { - constraints.insert(TerrainConstraint(tile_map_node, E_coords, terrain)); + constraints.insert(TerrainConstraint(tile_set, E_coords, terrain)); } } return constraints; } -void TileMapLayer::set_tile_map(TileMap *p_tile_map) { - tile_map_node = p_tile_map; +void TileMapLayer::_renamed() { + TileMap *tile_map_node = _fetch_tilemap(); + tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); +} + +void TileMapLayer::_update_notify_local_transform() { + TileMap *tile_map_node = _fetch_tilemap(); + bool notify = tile_map_node->is_collision_animatable() || is_y_sort_enabled(); + if (!notify) { + if (is_y_sort_enabled()) { + notify = true; + } + } + set_notify_local_transform(notify); +} + +void TileMapLayer::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + connect(SNAME("renamed"), callable_mp(this, &TileMapLayer::_renamed)); + break; + } + case NOTIFICATION_ENTER_TREE: { + _update_notify_local_transform(); + dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE] = true; + TileMap *tile_map_node = _fetch_tilemap(); + tile_map_node->queue_internal_update(); + } break; + + case NOTIFICATION_EXIT_TREE: { + dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE] = true; + TileMap *tile_map_node = _fetch_tilemap(); + tile_map_node->queue_internal_update(); + } break; + + case TileMap::NOTIFICATION_ENTER_CANVAS: { + dirty.flags[DIRTY_FLAGS_LAYER_IN_CANVAS] = true; + TileMap *tile_map_node = _fetch_tilemap(); + tile_map_node->queue_internal_update(); + } break; + + case TileMap::NOTIFICATION_EXIT_CANVAS: { + dirty.flags[DIRTY_FLAGS_LAYER_IN_CANVAS] = true; + TileMap *tile_map_node = _fetch_tilemap(); + tile_map_node->queue_internal_update(); + } break; + + case TileMap::NOTIFICATION_VISIBILITY_CHANGED: { + dirty.flags[DIRTY_FLAGS_LAYER_VISIBILITY] = true; + TileMap *tile_map_node = _fetch_tilemap(); + tile_map_node->queue_internal_update(); + } break; + } + + _rendering_notification(p_what); + _physics_notification(p_what); + _navigation_notification(p_what); } void TileMapLayer::set_layer_index_in_tile_map_node(int p_index) { if (p_index == layer_index_in_tile_map_node) { return; } + TileMap *tile_map_node = _fetch_tilemap(); layer_index_in_tile_map_node = p_index; dirty.flags[DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE] = true; tile_map_node->queue_internal_update(); } Rect2 TileMapLayer::get_rect(bool &r_changed) const { + const Ref<TileSet> &tile_set = _fetch_tileset(); + if (tile_set.is_null()) { + r_changed = rect_cache != Rect2(); + return Rect2(); + } + // Compute the displayed area of the tilemap. r_changed = false; #ifdef DEBUG_ENABLED @@ -1617,7 +1683,7 @@ Rect2 TileMapLayer::get_rect(bool &r_changed) const { bool first = true; for (const KeyValue<Vector2i, CellData> &E : tile_map) { Rect2 r; - r.position = tile_map_node->map_to_local(E.key); + r.position = tile_set->map_to_local(E.key); r.size = Size2(); if (first) { r_total = r; @@ -1637,7 +1703,7 @@ Rect2 TileMapLayer::get_rect(bool &r_changed) const { } HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); if (!tile_set.is_valid()) { return HashMap<Vector2i, TileSet::TerrainsPattern>(); } @@ -1686,7 +1752,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_constrain HashMap<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) { HashMap<Vector2i, TileSet::TerrainsPattern> output; - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); ERR_FAIL_COND_V(!tile_set.is_valid(), output); ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); @@ -1704,8 +1770,8 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_connect(c // Find the adequate neighbor. for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); - if (tile_map_node->is_existing_neighbor(bit)) { - Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit); + if (tile_set->is_existing_neighbor(bit)) { + Vector2i neighbor = tile_set->get_neighbor_cell(coords, bit); if (!can_modify_set.has(neighbor)) { can_modify_list.push_back(neighbor); can_modify_set.insert(neighbor); @@ -1746,7 +1812,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_connect(c // Add new constraints from the path drawn. for (Vector2i coords : p_coords_array) { // Constraints on the center bit. - TerrainConstraint c = TerrainConstraint(tile_map_node, coords, p_terrain); + TerrainConstraint c = TerrainConstraint(tile_set, coords, p_terrain); c.set_priority(10); constraints.insert(c); @@ -1754,11 +1820,11 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_connect(c for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { - c = TerrainConstraint(tile_map_node, coords, bit, p_terrain); + c = TerrainConstraint(tile_set, coords, bit, p_terrain); c.set_priority(10); if ((int(bit) % 2) == 0) { // Side peering bits: add the constraint if the center is of the same terrain. - Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit); + Vector2i neighbor = tile_set->get_neighbor_cell(coords, bit); if (cells_with_terrain_center_bit.has(neighbor)) { constraints.insert(c); } @@ -1792,7 +1858,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_connect(c HashMap<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) { HashMap<Vector2i, TileSet::TerrainsPattern> output; - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); ERR_FAIL_COND_V(!tile_set.is_valid(), output); ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); @@ -1803,8 +1869,8 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_path(cons TileSet::CellNeighbor found_bit = TileSet::CELL_NEIGHBOR_MAX; for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); - if (tile_map_node->is_existing_neighbor(bit)) { - if (tile_map_node->get_neighbor_cell(p_coords_array[i], bit) == p_coords_array[i + 1]) { + if (tile_set->is_existing_neighbor(bit)) { + if (tile_set->get_neighbor_cell(p_coords_array[i], bit) == p_coords_array[i + 1]) { found_bit = bit; break; } @@ -1829,7 +1895,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_path(cons for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { - Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit); + Vector2i neighbor = tile_set->get_neighbor_cell(coords, bit); if (!can_modify_set.has(neighbor)) { can_modify_list.push_back(neighbor); can_modify_set.insert(neighbor); @@ -1843,13 +1909,13 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_path(cons // Add new constraints from the path drawn. for (Vector2i coords : p_coords_array) { // Constraints on the center bit. - TerrainConstraint c = TerrainConstraint(tile_map_node, coords, p_terrain); + TerrainConstraint c = TerrainConstraint(tile_set, coords, p_terrain); c.set_priority(10); constraints.insert(c); } for (int i = 0; i < p_coords_array.size() - 1; i++) { // Constraints on the peering bits. - TerrainConstraint c = TerrainConstraint(tile_map_node, p_coords_array[i], neighbor_list[i], p_terrain); + TerrainConstraint c = TerrainConstraint(tile_set, p_coords_array[i], neighbor_list[i], p_terrain); c.set_priority(10); constraints.insert(c); } @@ -1866,7 +1932,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_path(cons HashMap<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) { HashMap<Vector2i, TileSet::TerrainsPattern> output; - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); ERR_FAIL_COND_V(!tile_set.is_valid(), output); ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); @@ -1885,7 +1951,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_pattern(c for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { - Vector2i neighbor = tile_map_node->get_neighbor_cell(coords, bit); + Vector2i neighbor = tile_set->get_neighbor_cell(coords, bit); if (!can_modify_set.has(neighbor)) { can_modify_list.push_back(neighbor); can_modify_set.insert(neighbor); @@ -1922,7 +1988,7 @@ TileMapCell TileMapLayer::get_cell(const Vector2i &p_coords, bool p_use_proxies) return TileMapCell(); } else { TileMapCell c = tile_map.find(p_coords)->value.cell; - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); if (p_use_proxies && tile_set.is_valid()) { Array proxyed = tile_set->map_tile_proxy(c.source_id, c.get_atlas_coords(), c.alternative_tile); c.source_id = proxyed[0]; @@ -1998,7 +2064,7 @@ void TileMapLayer::set_tile_data(TileMapDataFormat p_format, const Vector<int> & coord_y = decode_uint16(&local[10]); } - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); if (tile_set.is_valid()) { Array a = tile_set->compatibility_tilemap_map(v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose); if (a.size() == 3) { @@ -2039,9 +2105,9 @@ Vector<int> TileMapLayer::get_tile_data() const { } void TileMapLayer::notify_tile_map_change(DirtyFlags p_what) { + TileMap *tile_map_node = _fetch_tilemap(); dirty.flags[p_what] = true; tile_map_node->queue_internal_update(); - _physics_notify_tilemap_change(p_what); } void TileMapLayer::internal_update() { @@ -2124,7 +2190,10 @@ void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vec if (!E->value.dirty_list_element.in_list()) { dirty.cell_list.add(&(E->value.dirty_list_element)); } - tile_map_node->queue_internal_update(); + TileMap *tile_map_node = _fetch_tilemap(); + if (tile_map_node) { // Needed to avoid crashes in destructor. + tile_map_node->queue_internal_update(); + } used_rect_cache_dirty = true; } @@ -2141,7 +2210,7 @@ int TileMapLayer::get_cell_source_id(const Vector2i &p_coords, bool p_use_proxie return TileSet::INVALID_SOURCE; } - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); if (p_use_proxies && tile_set.is_valid()) { Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); return proxyed[0]; @@ -2158,7 +2227,7 @@ Vector2i TileMapLayer::get_cell_atlas_coords(const Vector2i &p_coords, bool p_us return TileSetSource::INVALID_ATLAS_COORDS; } - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); if (p_use_proxies && tile_set.is_valid()) { Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); return proxyed[1]; @@ -2175,7 +2244,7 @@ int TileMapLayer::get_cell_alternative_tile(const Vector2i &p_coords, bool p_use return TileSetSource::INVALID_TILE_ALTERNATIVE; } - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); if (p_use_proxies && tile_set.is_valid()) { Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); return proxyed[2]; @@ -2190,7 +2259,7 @@ TileData *TileMapLayer::get_cell_tile_data(const Vector2i &p_coords, bool p_use_ return nullptr; } - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); Ref<TileSetAtlasSource> source = tile_set->get_source(source_id); if (source.is_valid()) { return source->get_tile_data(get_cell_atlas_coords(p_coords, p_use_proxies), get_cell_alternative_tile(p_coords, p_use_proxies)); @@ -2208,7 +2277,7 @@ void TileMapLayer::clear() { } Ref<TileMapPattern> TileMapLayer::get_pattern(TypedArray<Vector2i> p_coords_array) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr); Ref<TileMapPattern> output; @@ -2262,19 +2331,19 @@ Ref<TileMapPattern> TileMapLayer::get_pattern(TypedArray<Vector2i> p_coords_arra } void TileMapLayer::set_pattern(const Vector2i &p_position, const Ref<TileMapPattern> p_pattern) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); ERR_FAIL_COND(tile_set.is_null()); ERR_FAIL_COND(p_pattern.is_null()); TypedArray<Vector2i> used_cells = p_pattern->get_used_cells(); for (int i = 0; i < used_cells.size(); i++) { - Vector2i coords = tile_map_node->map_pattern(p_position, used_cells[i], p_pattern); + Vector2i coords = tile_set->map_pattern(p_position, used_cells[i], p_pattern); 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])); } } void TileMapLayer::set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); ERR_FAIL_COND(!tile_set.is_valid()); ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); @@ -2314,7 +2383,7 @@ void TileMapLayer::set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p } void TileMapLayer::set_cells_terrain_path(TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { - const Ref<TileSet> &tile_set = tile_map_node->get_tileset(); + const Ref<TileSet> &tile_set = _fetch_tileset(); ERR_FAIL_COND(!tile_set.is_valid()); ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); @@ -2415,24 +2484,13 @@ Rect2i TileMapLayer::get_used_rect() const { return used_rect_cache; } -void TileMapLayer::set_name(String p_name) { - if (name == p_name) { - return; - } - name = p_name; - tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); -} - -String TileMapLayer::get_name() const { - return name; -} - void TileMapLayer::set_enabled(bool p_enabled) { if (enabled == p_enabled) { return; } enabled = p_enabled; dirty.flags[DIRTY_FLAGS_LAYER_ENABLED] = true; + TileMap *tile_map_node = _fetch_tilemap(); tile_map_node->queue_internal_update(); tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); @@ -2443,34 +2501,29 @@ bool TileMapLayer::is_enabled() const { return enabled; } -void TileMapLayer::set_modulate(Color p_modulate) { - if (modulate == p_modulate) { +void TileMapLayer::set_self_modulate(const Color &p_self_modulate) { + if (get_self_modulate() == p_self_modulate) { return; } - modulate = p_modulate; - dirty.flags[DIRTY_FLAGS_LAYER_MODULATE] = true; + CanvasItem::set_self_modulate(p_self_modulate); + dirty.flags[DIRTY_FLAGS_LAYER_SELF_MODULATE] = true; + TileMap *tile_map_node = _fetch_tilemap(); tile_map_node->queue_internal_update(); tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); } -Color TileMapLayer::get_modulate() const { - return modulate; -} - void TileMapLayer::set_y_sort_enabled(bool p_y_sort_enabled) { - if (y_sort_enabled == p_y_sort_enabled) { + if (is_y_sort_enabled() == p_y_sort_enabled) { return; } - y_sort_enabled = p_y_sort_enabled; + CanvasItem::set_y_sort_enabled(p_y_sort_enabled); dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] = true; + TileMap *tile_map_node = _fetch_tilemap(); tile_map_node->queue_internal_update(); tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); tile_map_node->update_configuration_warnings(); -} - -bool TileMapLayer::is_y_sort_enabled() const { - return y_sort_enabled; + _update_notify_local_transform(); } void TileMapLayer::set_y_sort_origin(int p_y_sort_origin) { @@ -2479,6 +2532,7 @@ void TileMapLayer::set_y_sort_origin(int p_y_sort_origin) { } y_sort_origin = p_y_sort_origin; dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] = true; + TileMap *tile_map_node = _fetch_tilemap(); tile_map_node->queue_internal_update(); tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); } @@ -2488,19 +2542,28 @@ int TileMapLayer::get_y_sort_origin() const { } void TileMapLayer::set_z_index(int p_z_index) { - if (z_index == p_z_index) { + if (get_z_index() == p_z_index) { return; } - z_index = p_z_index; + CanvasItem::set_z_index(p_z_index); dirty.flags[DIRTY_FLAGS_LAYER_Z_INDEX] = true; + TileMap *tile_map_node = _fetch_tilemap(); tile_map_node->queue_internal_update(); tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); tile_map_node->update_configuration_warnings(); } -int TileMapLayer::get_z_index() const { - return z_index; +void TileMapLayer::set_use_kinematic_bodies(bool p_use_kinematic_bodies) { + use_kinematic_bodies = p_use_kinematic_bodies; + dirty.flags[DIRTY_FLAGS_LAYER_USE_KINEMATIC_BODIES] = p_use_kinematic_bodies; + TileMap *tile_map_node = _fetch_tilemap(); + tile_map_node->queue_internal_update(); + tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); +} + +bool TileMapLayer::is_using_kinematic_bodies() const { + return use_kinematic_bodies; } void TileMapLayer::set_navigation_enabled(bool p_enabled) { @@ -2509,6 +2572,7 @@ void TileMapLayer::set_navigation_enabled(bool p_enabled) { } navigation_enabled = p_enabled; dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_ENABLED] = true; + TileMap *tile_map_node = _fetch_tilemap(); tile_map_node->queue_internal_update(); tile_map_node->emit_signal(CoreStringNames::get_singleton()->changed); } @@ -2518,9 +2582,9 @@ bool TileMapLayer::is_navigation_enabled() const { } void TileMapLayer::set_navigation_map(RID p_map) { - ERR_FAIL_COND_MSG(!tile_map_node->is_inside_tree(), "A TileMap navigation map can only be changed while inside the SceneTree."); + ERR_FAIL_COND_MSG(!is_inside_tree(), "A TileMap navigation map can only be changed while inside the SceneTree."); navigation_map = p_map; - uses_world_navigation_map = p_map == tile_map_node->get_world_2d()->get_navigation_map(); + uses_world_navigation_map = p_map == get_world_2d()->get_navigation_map(); } RID TileMapLayer::get_navigation_map() const { @@ -2531,7 +2595,7 @@ RID TileMapLayer::get_navigation_map() const { } void TileMapLayer::fix_invalid_tiles() { - Ref<TileSet> tileset = tile_map_node->get_tileset(); + Ref<TileSet> tileset = _fetch_tileset(); ERR_FAIL_COND_MSG(tileset.is_null(), "Cannot call fix_invalid_tiles() on a TileMap without a valid TileSet."); RBSet<Vector2i> coords; @@ -2554,12 +2618,11 @@ Vector2i TileMapLayer::get_coords_for_body_rid(RID p_physics_body) const { return bodies_coords[p_physics_body]; } -TileMapLayer::~TileMapLayer() { - if (!tile_map_node) { - // Temporary layer. - return; - } +TileMapLayer::TileMapLayer() { + set_notify_transform(true); +} +TileMapLayer::~TileMapLayer() { in_destructor = true; clear(); internal_update(); @@ -2569,26 +2632,24 @@ HashMap<Vector2i, TileSet::CellNeighbor> TerrainConstraint::get_overlapping_coor HashMap<Vector2i, TileSet::CellNeighbor> output; ERR_FAIL_COND_V(is_center_bit(), output); + ERR_FAIL_COND_V(!tile_set.is_valid(), output); - Ref<TileSet> ts = tile_map->get_tileset(); - ERR_FAIL_COND_V(!ts.is_valid(), output); - - TileSet::TileShape shape = ts->get_tile_shape(); + TileSet::TileShape shape = tile_set->get_tile_shape(); if (shape == TileSet::TILE_SHAPE_SQUARE) { switch (bit) { case 1: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE; break; case 2: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER; break; case 3: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE; break; default: ERR_FAIL_V(output); @@ -2597,47 +2658,47 @@ HashMap<Vector2i, TileSet::CellNeighbor> TerrainConstraint::get_overlapping_coor switch (bit) { case 1: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; break; case 2: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_CORNER; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER; break; case 3: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; break; default: ERR_FAIL_V(output); } } else { // Half offset shapes. - TileSet::TileOffsetAxis offset_axis = ts->get_tile_offset_axis(); + TileSet::TileOffsetAxis offset_axis = tile_set->get_tile_offset_axis(); if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { switch (bit) { case 1: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE; break; case 2: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_CORNER; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_CORNER; break; case 3: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; break; case 4: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER; break; case 5: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; break; default: ERR_FAIL_V(output); @@ -2646,25 +2707,25 @@ HashMap<Vector2i, TileSet::CellNeighbor> TerrainConstraint::get_overlapping_coor switch (bit) { case 1: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; break; case 2: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; break; case 3: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; break; case 4: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE; break; case 5: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; + output[tile_set->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; break; default: ERR_FAIL_V(output); @@ -2674,25 +2735,20 @@ HashMap<Vector2i, TileSet::CellNeighbor> TerrainConstraint::get_overlapping_coor return output; } -TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain) { - tile_map = p_tile_map; - - Ref<TileSet> ts = tile_map->get_tileset(); - ERR_FAIL_COND(!ts.is_valid()); - +TerrainConstraint::TerrainConstraint(Ref<TileSet> p_tile_set, const Vector2i &p_position, int p_terrain) { + ERR_FAIL_COND(!p_tile_set.is_valid()); + tile_set = p_tile_set; bit = 0; base_cell_coords = p_position; terrain = p_terrain; } -TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain) { +TerrainConstraint::TerrainConstraint(Ref<TileSet> p_tile_set, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain) { // The way we build the constraint make it easy to detect conflicting constraints. - tile_map = p_tile_map; - - Ref<TileSet> ts = tile_map->get_tileset(); - ERR_FAIL_COND(!ts.is_valid()); + ERR_FAIL_COND(!p_tile_set.is_valid()); + tile_set = p_tile_set; - TileSet::TileShape shape = ts->get_tile_shape(); + TileSet::TileShape shape = tile_set->get_tile_shape(); if (shape == TileSet::TILE_SHAPE_SQUARE) { switch (p_bit) { case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: @@ -2709,23 +2765,23 @@ TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i & break; case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_LEFT_SIDE: bit = 1; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER); break; case TileSet::CELL_NEIGHBOR_TOP_SIDE: bit = 3; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); break; default: ERR_FAIL(); @@ -2735,7 +2791,7 @@ TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i & switch (p_bit) { case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); break; case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: bit = 1; @@ -2751,19 +2807,19 @@ TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i & break; case TileSet::CELL_NEIGHBOR_LEFT_CORNER: bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: bit = 1; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_CORNER: bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_CORNER); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_CORNER); break; case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: bit = 3; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); break; default: ERR_FAIL(); @@ -2771,7 +2827,7 @@ TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i & } } else { // Half-offset shapes. - TileSet::TileOffsetAxis offset_axis = ts->get_tile_offset_axis(); + TileSet::TileOffsetAxis offset_axis = tile_set->get_tile_offset_axis(); if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { switch (p_bit) { case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: @@ -2796,31 +2852,31 @@ TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i & break; case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_LEFT_SIDE: bit = 1; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: bit = 4; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: bit = 3; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_CORNER: bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: bit = 5; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: bit = 4; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); break; default: ERR_FAIL(); @@ -2846,7 +2902,7 @@ TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i & break; case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: bit = 1; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: bit = 5; @@ -2854,27 +2910,27 @@ TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i & break; case TileSet::CELL_NEIGHBOR_LEFT_CORNER: bit = 3; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: bit = 2; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: bit = 1; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_SIDE: bit = 4; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: bit = 3; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: bit = 5; - base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); + base_cell_coords = tile_set->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); break; default: ERR_FAIL(); diff --git a/scene/2d/tile_map_layer.h b/scene/2d/tile_map_layer.h index f31c5406a4..2cc57f50d1 100644 --- a/scene/2d/tile_map_layer.h +++ b/scene/2d/tile_map_layer.h @@ -38,7 +38,7 @@ class TileSetAtlasSource; class TerrainConstraint { private: - const TileMap *tile_map = nullptr; + Ref<TileSet> tile_set; Vector2i base_cell_coords; int bit = -1; int terrain = -1; @@ -83,8 +83,8 @@ public: return priority; } - TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain); // For the center terrain bit - TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain); // For peering bits + TerrainConstraint(Ref<TileSet> p_tile_set, const Vector2i &p_position, int p_terrain); // For the center terrain bit + TerrainConstraint(Ref<TileSet> p_tile_set, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain); // For peering bits TerrainConstraint(){}; }; @@ -214,23 +214,24 @@ public: } }; -class TileMapLayer : public RefCounted { - GDCLASS(TileMapLayer, RefCounted); +class TileMapLayer : public Node2D { + GDCLASS(TileMapLayer, Node2D); public: enum DirtyFlags { DIRTY_FLAGS_LAYER_ENABLED = 0, - DIRTY_FLAGS_LAYER_MODULATE, + DIRTY_FLAGS_LAYER_IN_TREE, + DIRTY_FLAGS_LAYER_IN_CANVAS, + DIRTY_FLAGS_LAYER_LOCAL_TRANSFORM, + DIRTY_FLAGS_LAYER_VISIBILITY, + DIRTY_FLAGS_LAYER_SELF_MODULATE, DIRTY_FLAGS_LAYER_Y_SORT_ENABLED, DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN, DIRTY_FLAGS_LAYER_Z_INDEX, + DIRTY_FLAGS_LAYER_USE_KINEMATIC_BODIES, DIRTY_FLAGS_LAYER_NAVIGATION_ENABLED, DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE, - DIRTY_FLAGS_TILE_MAP_IN_TREE, - DIRTY_FLAGS_TILE_MAP_IN_CANVAS, - DIRTY_FLAGS_TILE_MAP_VISIBILITY, - DIRTY_FLAGS_TILE_MAP_XFORM, - DIRTY_FLAGS_TILE_MAP_LOCAL_XFORM, + DIRTY_FLAGS_TILE_MAP_SELECTED_LAYER, DIRTY_FLAGS_TILE_MAP_LIGHT_MASK, DIRTY_FLAGS_TILE_MAP_MATERIAL, @@ -239,7 +240,6 @@ public: DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT, DIRTY_FLAGS_TILE_MAP_TILE_SET, DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE, - DIRTY_FLAGS_TILE_MAP_COLLISION_ANIMATABLE, DIRTY_FLAGS_TILE_MAP_COLLISION_VISIBILITY_MODE, DIRTY_FLAGS_TILE_MAP_NAVIGATION_VISIBILITY_MODE, DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED, @@ -249,20 +249,15 @@ public: private: // Exposed properties. - String name; bool enabled = true; - Color modulate = Color(1, 1, 1, 1); - bool y_sort_enabled = false; int y_sort_origin = 0; - int z_index = 0; + bool use_kinematic_bodies = false; bool navigation_enabled = true; RID navigation_map; bool uses_world_navigation_map = false; // Internal. - TileMap *tile_map_node = nullptr; int layer_index_in_tile_map_node = -1; - RID canvas_item; HashMap<Vector2i, CellData> tile_map; // Dirty flag. Allows knowing what was modified since the last update. @@ -278,6 +273,10 @@ private: mutable Rect2i used_rect_cache; mutable bool used_rect_cache_dirty = true; + // Method to fetch the TileSet to use + TileMap *_fetch_tilemap() const; + Ref<TileSet> _fetch_tileset() const; + // Runtime tile data. bool _runtime_update_tile_data_was_cleaned_up = false; void _build_runtime_update_tile_data(); @@ -296,6 +295,7 @@ private: HashMap<Vector2i, Ref<RenderingQuadrant>> rendering_quadrant_map; bool _rendering_was_cleaned_up = false; void _rendering_update(); + void _rendering_notification(int p_what); void _rendering_quadrants_update_cell(CellData &r_cell_data, SelfList<RenderingQuadrant>::List &r_dirty_rendering_quadrant_list); void _rendering_occluders_clear_cell(CellData &r_cell_data); void _rendering_occluders_update_cell(CellData &r_cell_data); @@ -306,7 +306,7 @@ private: HashMap<RID, Vector2i> bodies_coords; // Mapping for RID to coords. bool _physics_was_cleaned_up = false; void _physics_update(); - void _physics_notify_tilemap_change(DirtyFlags p_what); + void _physics_notification(int p_what); void _physics_clear_cell(CellData &r_cell_data); void _physics_update_cell(CellData &r_cell_data); #ifdef DEBUG_ENABLED @@ -315,6 +315,7 @@ private: bool _navigation_was_cleaned_up = false; void _navigation_update(); + void _navigation_notification(int p_what); void _navigation_clear_cell(CellData &r_cell_data); void _navigation_update_cell(CellData &r_cell_data); #ifdef DEBUG_ENABLED @@ -334,9 +335,14 @@ private: RBSet<TerrainConstraint> _get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const; RBSet<TerrainConstraint> _get_terrain_constraints_from_painted_cells_list(const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const; + void _renamed(); + void _update_notify_local_transform(); + +protected: + void _notification(int p_what); + public: // TileMap node. - void set_tile_map(TileMap *p_tile_map); void set_layer_index_in_tile_map_node(int p_index); // Rect caching. @@ -383,18 +389,15 @@ public: Rect2i get_used_rect() const; // Layer properties. - void set_name(String p_name); - String get_name() const; void set_enabled(bool p_enabled); bool is_enabled() const; - void set_modulate(Color p_modulate); - Color get_modulate() const; - void set_y_sort_enabled(bool p_y_sort_enabled); - bool is_y_sort_enabled() const; + virtual void set_self_modulate(const Color &p_self_modulate) override; + virtual void set_y_sort_enabled(bool p_y_sort_enabled) override; void set_y_sort_origin(int p_y_sort_origin); int get_y_sort_origin() const; - void set_z_index(int p_z_index); - int get_z_index() const; + virtual void set_z_index(int p_z_index) override; + void set_use_kinematic_bodies(bool p_use_kinematic_bodies); + bool is_using_kinematic_bodies() const; void set_navigation_enabled(bool p_enabled); bool is_navigation_enabled() const; void set_navigation_map(RID p_map); @@ -407,6 +410,7 @@ public: bool has_body_rid(RID p_physics_body) const; Vector2i get_coords_for_body_rid(RID p_physics_body) const; // For finding tiles from collision. + TileMapLayer(); ~TileMapLayer(); }; diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index a35ee17868..0dbbbf7fd6 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -277,6 +277,8 @@ void CanvasItem::_notification(int p_what) { ERR_MAIN_THREAD_GUARD; ERR_FAIL_COND(!is_inside_tree()); + _set_global_invalid(true); + Node *parent = get_parent(); if (parent) { CanvasItem *ci = Object::cast_to<CanvasItem>(parent); diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 36f0e17924..ce1dbce6c3 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -237,7 +237,7 @@ public: Color get_modulate() const; Color get_modulate_in_tree() const; - void set_self_modulate(const Color &p_self_modulate); + virtual void set_self_modulate(const Color &p_self_modulate); Color get_self_modulate() const; void set_visibility_layer(uint32_t p_visibility_layer); @@ -248,7 +248,7 @@ public: /* ORDERING */ - void set_z_index(int p_z); + virtual void set_z_index(int p_z); int get_z_index() const; int get_effective_z_index() const; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index a99102e847..66e1b7bcf9 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -1563,6 +1563,632 @@ void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform } } +Vector2 TileSet::map_to_local(const Vector2i &p_pos) const { + // SHOULD RETURN THE CENTER OF THE CELL. + Vector2 ret = p_pos; + + if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { + // Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap. + // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap. + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + switch (tile_layout) { + case TileSet::TILE_LAYOUT_STACKED: + ret = Vector2(ret.x + (Math::posmod(ret.y, 2) == 0 ? 0.0 : 0.5), ret.y); + break; + case TileSet::TILE_LAYOUT_STACKED_OFFSET: + ret = Vector2(ret.x + (Math::posmod(ret.y, 2) == 1 ? 0.0 : 0.5), ret.y); + break; + case TileSet::TILE_LAYOUT_STAIRS_RIGHT: + ret = Vector2(ret.x + ret.y / 2, ret.y); + break; + case TileSet::TILE_LAYOUT_STAIRS_DOWN: + ret = Vector2(ret.x / 2, ret.y * 2 + ret.x); + break; + case TileSet::TILE_LAYOUT_DIAMOND_RIGHT: + ret = Vector2((ret.x + ret.y) / 2, ret.y - ret.x); + break; + case TileSet::TILE_LAYOUT_DIAMOND_DOWN: + ret = Vector2((ret.x - ret.y) / 2, ret.y + ret.x); + break; + } + } else { // TILE_OFFSET_AXIS_VERTICAL. + switch (tile_layout) { + case TileSet::TILE_LAYOUT_STACKED: + ret = Vector2(ret.x, ret.y + (Math::posmod(ret.x, 2) == 0 ? 0.0 : 0.5)); + break; + case TileSet::TILE_LAYOUT_STACKED_OFFSET: + ret = Vector2(ret.x, ret.y + (Math::posmod(ret.x, 2) == 1 ? 0.0 : 0.5)); + break; + case TileSet::TILE_LAYOUT_STAIRS_RIGHT: + ret = Vector2(ret.x * 2 + ret.y, ret.y / 2); + break; + case TileSet::TILE_LAYOUT_STAIRS_DOWN: + ret = Vector2(ret.x, ret.y + ret.x / 2); + break; + case TileSet::TILE_LAYOUT_DIAMOND_RIGHT: + ret = Vector2(ret.x + ret.y, (ret.y - ret.x) / 2); + break; + case TileSet::TILE_LAYOUT_DIAMOND_DOWN: + ret = Vector2(ret.x - ret.y, (ret.y + ret.x) / 2); + break; + } + } + } + + // Multiply by the overlapping ratio. + double overlapping_ratio = 1.0; + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { + overlapping_ratio = 0.5; + } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) { + overlapping_ratio = 0.75; + } + ret.y *= overlapping_ratio; + } else { // TILE_OFFSET_AXIS_VERTICAL. + if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { + overlapping_ratio = 0.5; + } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) { + overlapping_ratio = 0.75; + } + ret.x *= overlapping_ratio; + } + + return (ret + Vector2(0.5, 0.5)) * tile_size; +} + +Vector2i TileSet::local_to_map(const Vector2 &p_local_position) const { + Vector2 ret = p_local_position; + ret /= tile_size; + + // Divide by the overlapping ratio. + double overlapping_ratio = 1.0; + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { + overlapping_ratio = 0.5; + } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) { + overlapping_ratio = 0.75; + } + ret.y /= overlapping_ratio; + } else { // TILE_OFFSET_AXIS_VERTICAL. + if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { + overlapping_ratio = 0.5; + } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) { + overlapping_ratio = 0.75; + } + ret.x /= overlapping_ratio; + } + + // For each half-offset shape, we check if we are in the corner of the tile, and thus should correct the local position accordingly. + if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { + // Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap. + // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap. + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + // Smart floor of the position + Vector2 raw_pos = ret; + if (Math::posmod(Math::floor(ret.y), 2) ^ (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET)) { + ret = Vector2(Math::floor(ret.x + 0.5) - 0.5, Math::floor(ret.y)); + } else { + ret = ret.floor(); + } + + // Compute the tile offset, and if we might the output for a neighbor top tile. + Vector2 in_tile_pos = raw_pos - ret; + bool in_top_left_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(-0.5, 1.0 / overlapping_ratio - 1)) <= 0; + bool in_top_right_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(0.5, 1.0 / overlapping_ratio - 1)) > 0; + + switch (tile_layout) { + case TileSet::TILE_LAYOUT_STACKED: + ret = ret.floor(); + if (in_top_left_triangle) { + ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 0 : -1, -1); + } else if (in_top_right_triangle) { + ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 1 : 0, -1); + } + break; + case TileSet::TILE_LAYOUT_STACKED_OFFSET: + ret = ret.floor(); + if (in_top_left_triangle) { + ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? -1 : 0, -1); + } else if (in_top_right_triangle) { + ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 0 : 1, -1); + } + break; + case TileSet::TILE_LAYOUT_STAIRS_RIGHT: + ret = Vector2(ret.x - ret.y / 2, ret.y).floor(); + if (in_top_left_triangle) { + ret += Vector2i(0, -1); + } else if (in_top_right_triangle) { + ret += Vector2i(1, -1); + } + break; + case TileSet::TILE_LAYOUT_STAIRS_DOWN: + ret = Vector2(ret.x * 2, ret.y / 2 - ret.x).floor(); + if (in_top_left_triangle) { + ret += Vector2i(-1, 0); + } else if (in_top_right_triangle) { + ret += Vector2i(1, -1); + } + break; + case TileSet::TILE_LAYOUT_DIAMOND_RIGHT: + ret = Vector2(ret.x - ret.y / 2, ret.y / 2 + ret.x).floor(); + if (in_top_left_triangle) { + ret += Vector2i(0, -1); + } else if (in_top_right_triangle) { + ret += Vector2i(1, 0); + } + break; + case TileSet::TILE_LAYOUT_DIAMOND_DOWN: + ret = Vector2(ret.x + ret.y / 2, ret.y / 2 - ret.x).floor(); + if (in_top_left_triangle) { + ret += Vector2i(-1, 0); + } else if (in_top_right_triangle) { + ret += Vector2i(0, -1); + } + break; + } + } else { // TILE_OFFSET_AXIS_VERTICAL. + // Smart floor of the position. + Vector2 raw_pos = ret; + if (Math::posmod(Math::floor(ret.x), 2) ^ (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET)) { + ret = Vector2(Math::floor(ret.x), Math::floor(ret.y + 0.5) - 0.5); + } else { + ret = ret.floor(); + } + + // Compute the tile offset, and if we might the output for a neighbor top tile. + Vector2 in_tile_pos = raw_pos - ret; + bool in_top_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, -0.5)) > 0; + bool in_bottom_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, 0.5)) <= 0; + + switch (tile_layout) { + case TileSet::TILE_LAYOUT_STACKED: + ret = ret.floor(); + if (in_top_left_triangle) { + ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 0 : -1); + } else if (in_bottom_left_triangle) { + ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 1 : 0); + } + break; + case TileSet::TILE_LAYOUT_STACKED_OFFSET: + ret = ret.floor(); + if (in_top_left_triangle) { + ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? -1 : 0); + } else if (in_bottom_left_triangle) { + ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 0 : 1); + } + break; + case TileSet::TILE_LAYOUT_STAIRS_RIGHT: + ret = Vector2(ret.x / 2 - ret.y, ret.y * 2).floor(); + if (in_top_left_triangle) { + ret += Vector2i(0, -1); + } else if (in_bottom_left_triangle) { + ret += Vector2i(-1, 1); + } + break; + case TileSet::TILE_LAYOUT_STAIRS_DOWN: + ret = Vector2(ret.x, ret.y - ret.x / 2).floor(); + if (in_top_left_triangle) { + ret += Vector2i(-1, 0); + } else if (in_bottom_left_triangle) { + ret += Vector2i(-1, 1); + } + break; + case TileSet::TILE_LAYOUT_DIAMOND_RIGHT: + ret = Vector2(ret.x / 2 - ret.y, ret.y + ret.x / 2).floor(); + if (in_top_left_triangle) { + ret += Vector2i(0, -1); + } else if (in_bottom_left_triangle) { + ret += Vector2i(-1, 0); + } + break; + case TileSet::TILE_LAYOUT_DIAMOND_DOWN: + ret = Vector2(ret.x / 2 + ret.y, ret.y - ret.x / 2).floor(); + if (in_top_left_triangle) { + ret += Vector2i(-1, 0); + } else if (in_bottom_left_triangle) { + ret += Vector2i(0, 1); + } + break; + } + } + } else { + ret = (ret + Vector2(0.00005, 0.00005)).floor(); + } + return Vector2i(ret); +} + +bool TileSet::is_existing_neighbor(TileSet::CellNeighbor p_cell_neighbor) const { + if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { + return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER; + + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { + return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; + } else { + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; + } else { + return p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE || + p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; + } + } +} + +Vector2i TileSet::get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const { + if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { + switch (p_cell_neighbor) { + case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: + return p_coords + Vector2i(1, 0); + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + return p_coords + Vector2i(1, 1); + case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: + return p_coords + Vector2i(0, 1); + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + return p_coords + Vector2i(-1, 1); + case TileSet::CELL_NEIGHBOR_LEFT_SIDE: + return p_coords + Vector2i(-1, 0); + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + return p_coords + Vector2i(-1, -1); + case TileSet::CELL_NEIGHBOR_TOP_SIDE: + return p_coords + Vector2i(0, -1); + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + return p_coords + Vector2i(1, -1); + default: + ERR_FAIL_V(p_coords); + } + } else { // Half-offset shapes (square and hexagon). + switch (tile_layout) { + case TileSet::TILE_LAYOUT_STACKED: { + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + bool is_offset = p_coords.y % 2; + if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { + return p_coords + Vector2i(1, 0); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { + return p_coords + Vector2i(is_offset ? 1 : 0, 1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) { + return p_coords + Vector2i(0, 2); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { + return p_coords + Vector2i(is_offset ? 0 : -1, 1); + } else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { + return p_coords + Vector2i(-1, 0); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { + return p_coords + Vector2i(is_offset ? 0 : -1, -1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) { + return p_coords + Vector2i(0, -2); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { + return p_coords + Vector2i(is_offset ? 1 : 0, -1); + } else { + ERR_FAIL_V(p_coords); + } + } else { + bool is_offset = p_coords.x % 2; + + if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { + return p_coords + Vector2i(0, 1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { + return p_coords + Vector2i(1, is_offset ? 1 : 0); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) { + return p_coords + Vector2i(2, 0); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { + return p_coords + Vector2i(1, is_offset ? 0 : -1); + } else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) { + return p_coords + Vector2i(0, -1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { + return p_coords + Vector2i(-1, is_offset ? 0 : -1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) { + return p_coords + Vector2i(-2, 0); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { + return p_coords + Vector2i(-1, is_offset ? 1 : 0); + } else { + ERR_FAIL_V(p_coords); + } + } + } break; + case TileSet::TILE_LAYOUT_STACKED_OFFSET: { + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + bool is_offset = p_coords.y % 2; + + if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { + return p_coords + Vector2i(1, 0); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { + return p_coords + Vector2i(is_offset ? 0 : 1, 1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) { + return p_coords + Vector2i(0, 2); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { + return p_coords + Vector2i(is_offset ? -1 : 0, 1); + } else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { + return p_coords + Vector2i(-1, 0); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { + return p_coords + Vector2i(is_offset ? -1 : 0, -1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) { + return p_coords + Vector2i(0, -2); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { + return p_coords + Vector2i(is_offset ? 0 : 1, -1); + } else { + ERR_FAIL_V(p_coords); + } + } else { + bool is_offset = p_coords.x % 2; + + if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { + return p_coords + Vector2i(0, 1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { + return p_coords + Vector2i(1, is_offset ? 0 : 1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) { + return p_coords + Vector2i(2, 0); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { + return p_coords + Vector2i(1, is_offset ? -1 : 0); + } else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) { + return p_coords + Vector2i(0, -1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { + return p_coords + Vector2i(-1, is_offset ? -1 : 0); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) { + return p_coords + Vector2i(-2, 0); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { + return p_coords + Vector2i(-1, is_offset ? 0 : 1); + } else { + ERR_FAIL_V(p_coords); + } + } + } break; + case TileSet::TILE_LAYOUT_STAIRS_RIGHT: + case TileSet::TILE_LAYOUT_STAIRS_DOWN: { + if ((tile_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) { + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { + return p_coords + Vector2i(1, 0); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { + return p_coords + Vector2i(0, 1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) { + return p_coords + Vector2i(-1, 2); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { + return p_coords + Vector2i(-1, 1); + } else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { + return p_coords + Vector2i(-1, 0); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { + return p_coords + Vector2i(0, -1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) { + return p_coords + Vector2i(1, -2); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { + return p_coords + Vector2i(1, -1); + } else { + ERR_FAIL_V(p_coords); + } + + } else { + if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { + return p_coords + Vector2i(0, 1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { + return p_coords + Vector2i(1, 0); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) { + return p_coords + Vector2i(2, -1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { + return p_coords + Vector2i(1, -1); + } else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) { + return p_coords + Vector2i(0, -1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { + return p_coords + Vector2i(-1, 0); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) { + return p_coords + Vector2i(-2, 1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { + return p_coords + Vector2i(-1, 1); + } else { + ERR_FAIL_V(p_coords); + } + } + } else { + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { + return p_coords + Vector2i(2, -1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { + return p_coords + Vector2i(1, 0); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) { + return p_coords + Vector2i(0, 1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { + return p_coords + Vector2i(-1, 1); + } else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { + return p_coords + Vector2i(-2, 1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { + return p_coords + Vector2i(-1, 0); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) { + return p_coords + Vector2i(0, -1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { + return p_coords + Vector2i(1, -1); + } else { + ERR_FAIL_V(p_coords); + } + + } else { + if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { + return p_coords + Vector2i(-1, 2); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { + return p_coords + Vector2i(0, 1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) { + return p_coords + Vector2i(1, 0); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { + return p_coords + Vector2i(1, -1); + } else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) { + return p_coords + Vector2i(1, -2); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { + return p_coords + Vector2i(0, -1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) { + return p_coords + Vector2i(-1, 0); + + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { + return p_coords + Vector2i(-1, 1); + } else { + ERR_FAIL_V(p_coords); + } + } + } + } break; + case TileSet::TILE_LAYOUT_DIAMOND_RIGHT: + case TileSet::TILE_LAYOUT_DIAMOND_DOWN: { + if ((tile_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) { + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { + return p_coords + Vector2i(1, 1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { + return p_coords + Vector2i(0, 1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) { + return p_coords + Vector2i(-1, 1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { + return p_coords + Vector2i(-1, 0); + } else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { + return p_coords + Vector2i(-1, -1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { + return p_coords + Vector2i(0, -1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) { + return p_coords + Vector2i(1, -1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { + return p_coords + Vector2i(1, 0); + } else { + ERR_FAIL_V(p_coords); + } + + } else { + if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { + return p_coords + Vector2i(1, 1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { + return p_coords + Vector2i(1, 0); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) { + return p_coords + Vector2i(1, -1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { + return p_coords + Vector2i(0, -1); + } else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) { + return p_coords + Vector2i(-1, -1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { + return p_coords + Vector2i(-1, 0); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) { + return p_coords + Vector2i(-1, 1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { + return p_coords + Vector2i(0, 1); + } else { + ERR_FAIL_V(p_coords); + } + } + } else { + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { + return p_coords + Vector2i(1, -1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { + return p_coords + Vector2i(1, 0); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) { + return p_coords + Vector2i(1, 1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { + return p_coords + Vector2i(0, 1); + } else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { + return p_coords + Vector2i(-1, 1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { + return p_coords + Vector2i(-1, 0); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) { + return p_coords + Vector2i(-1, -1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { + return p_coords + Vector2i(0, -1); + } else { + ERR_FAIL_V(p_coords); + } + + } else { + if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { + return p_coords + Vector2i(-1, 1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) { + return p_coords + Vector2i(0, 1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) { + return p_coords + Vector2i(1, 1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) { + return p_coords + Vector2i(1, 0); + } else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) || + (tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) { + return p_coords + Vector2i(1, -1); + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) { + return p_coords + Vector2i(0, -1); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) { + return p_coords + Vector2i(-1, -1); + + } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) { + return p_coords + Vector2i(-1, 0); + } else { + ERR_FAIL_V(p_coords); + } + } + } + } break; + default: + ERR_FAIL_V(p_coords); + } + } +} + +Vector2i TileSet::map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern) { + ERR_FAIL_COND_V(p_pattern.is_null(), Vector2i()); + ERR_FAIL_COND_V(!p_pattern->has_cell(p_coords_in_pattern), Vector2i()); + + Vector2i output = p_position_in_tilemap + p_coords_in_pattern; + if (tile_shape != TileSet::TILE_SHAPE_SQUARE) { + if (tile_layout == TileSet::TILE_LAYOUT_STACKED) { + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(p_position_in_tilemap.y % 2) && bool(p_coords_in_pattern.y % 2)) { + output.x += 1; + } else if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(p_position_in_tilemap.x % 2) && bool(p_coords_in_pattern.x % 2)) { + output.y += 1; + } + } else if (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET) { + if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(p_position_in_tilemap.y % 2) && bool(p_coords_in_pattern.y % 2)) { + output.x -= 1; + } else if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(p_position_in_tilemap.x % 2) && bool(p_coords_in_pattern.x % 2)) { + output.y -= 1; + } + } + } + + return output; +} + Vector<Point2> TileSet::get_terrain_polygon(int p_terrain_set) { if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { return _get_square_terrain_polygon(tile_size); diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index a71982cd56..0a6d879047 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -530,6 +530,13 @@ public: Vector<Vector2> get_tile_shape_polygon(); void draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>()); + // Used by TileMap/TileMapLayer + Vector2 map_to_local(const Vector2i &p_pos) const; + Vector2i local_to_map(const Vector2 &p_pos) const; + bool is_existing_neighbor(TileSet::CellNeighbor p_cell_neighbor) const; + Vector2i get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const; + Vector2i map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern); + Vector<Point2> get_terrain_polygon(int p_terrain_set); Vector<Point2> get_terrain_peering_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit); void draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, const TileData *p_tile_data); |