Expose TileMapLayer

This commit is contained in:
Gilles Roudière 2024-03-05 13:55:23 +01:00
parent 7d151c8381
commit 3cd4b2859c
21 changed files with 1626 additions and 996 deletions

View file

@ -448,6 +448,9 @@
The color to use for the TileMap editor's grid.
[b]Note:[/b] Only effective if [member editors/tiles_editor/display_grid] is [code]true[/code].
</member>
<member name="editors/tiles_editor/highlight_selected_layer" type="bool" setter="" getter="">
Highlight the currently selected TileMapLayer by dimming the other ones in the scene.
</member>
<member name="editors/visual_editors/category_colors/color_color" type="Color" setter="" getter="">
The color of a graph node's header when it belongs to the "Color" category.
</member>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="TileMap" inherits="TileMapLayerGroup" keywords="gridmap" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<class name="TileMap" inherits="Node2D" deprecated="Use multiple [TileMapLayer] nodes instead." keywords="gridmap" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Node for 2D tile-based maps.
</brief_description>
@ -89,7 +89,8 @@
<param index="1" name="coords" type="Vector2i" />
<param index="2" name="use_proxies" type="bool" default="false" />
<description>
Returns the tile alternative ID of the cell on layer [param layer] at [param coords]. If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
Returns the tile alternative ID of the cell on layer [param layer] at [param coords].
If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
@ -100,7 +101,7 @@
<param index="2" name="use_proxies" type="bool" default="false" />
<description>
Returns the tile atlas coordinates ID of the cell on layer [param layer] at coordinates [param coords]. Returns [code]Vector2i(-1, -1)[/code] if the cell does not exist.
If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw atlas coordinate identifier. See [method TileSet.map_tile_proxy].
If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
@ -111,7 +112,7 @@
<param index="2" name="use_proxies" type="bool" default="false" />
<description>
Returns the tile source ID of the cell on layer [param layer] at coordinates [param coords]. Returns [code]-1[/code] if the cell does not exist.
If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw source identifier. See [method TileSet.map_tile_proxy].
If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
@ -123,7 +124,6 @@
<description>
Returns the [TileData] object associated with the given cell, or [code]null[/code] if the cell does not exist or is not a [TileSetAtlasSource].
If [param layer] is negative, the layers are accessed from the last one.
If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
[codeblock]
func get_clicked_tile_power():
var clicked_cell = tile_map.local_to_map(tile_map.get_local_mouse_position())
@ -133,6 +133,7 @@
else:
return 0
[/codeblock]
If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies. See [method TileSet.map_tile_proxy].
</description>
</method>
<method name="get_coords_for_body_rid">
@ -489,6 +490,9 @@
The quadrant size does not apply on Y-sorted layers, as tiles are be grouped by Y position instead in that case.
[b]Note:[/b] As quadrants are created according to the map's coordinate system, the quadrant's "square shape" might not look like square in the TileMap's local coordinate system.
</member>
<member name="tile_set" type="TileSet" setter="set_tileset" getter="get_tileset">
The [TileSet] used by this [TileMap]. The textures, collisions, and additional behavior of all available tiles are stored here.
</member>
</members>
<signals>
<signal name="changed">

View file

@ -0,0 +1,303 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="TileMapLayer" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Node for 2D tile-based maps.
</brief_description>
<description>
Node for 2D tile-based maps. A [TileMapLayer] uses a [TileSet] which contain a list of tiles which are used to create grid-based maps. Unlike the [TileMap] node, which is deprecated, [TileMapLayer] has only one layer of tiles. You can use several [TileMapLayer] to achieve the same result as a [TileMap] node.
For performance reasons, all TileMap updates are batched at the end of a frame. Notably, this means that scene tiles from a [TileSetScenesCollectionSource] may be initialized after their parent. This is only queued when inside the scene tree.
To force an update earlier on, call [method update_internals].
</description>
<tutorials>
</tutorials>
<methods>
<method name="_tile_data_runtime_update" qualifiers="virtual">
<return type="void" />
<param index="0" name="coords" type="Vector2i" />
<param index="1" name="tile_data" type="TileData" />
<description>
Called with a [TileData] object about to be used internally by the [TileMapLayer], allowing its modification at runtime.
This method is only called if [method _use_tile_data_runtime_update] is implemented and returns [code]true[/code] for the given tile [param coords].
[b]Warning:[/b] The [param tile_data] object's sub-resources are the same as the one in the TileSet. Modifying them might impact the whole TileSet. Instead, make sure to duplicate those resources.
[b]Note:[/b] If the properties of [param tile_data] object should change over time, use [method notify_runtime_tile_data_update] to notify the [TileMapLayer] it needs an update.
</description>
</method>
<method name="_use_tile_data_runtime_update" qualifiers="virtual">
<return type="bool" />
<param index="0" name="coords" type="Vector2i" />
<description>
Should return [code]true[/code] if the tile at coordinates [param coords] requires a runtime update.
[b]Warning:[/b] Make sure this function only returns [code]true[/code] when needed. Any tile processed at runtime without a need for it will imply a significant performance penalty.
[b]Note:[/b] If the result of this function should change, use [method notify_runtime_tile_data_update] to notify the [TileMapLayer] it needs an update.
</description>
</method>
<method name="clear">
<return type="void" />
<description>
Clears all cells.
</description>
</method>
<method name="erase_cell">
<return type="void" />
<param index="0" name="coords" type="Vector2i" />
<description>
Erases the cell at coordinates [param coords].
</description>
</method>
<method name="fix_invalid_tiles">
<return type="void" />
<description>
Clears cells containing tiles that do not exist in the [member tile_set].
</description>
</method>
<method name="get_cell_alternative_tile" qualifiers="const">
<return type="int" />
<param index="0" name="coords" type="Vector2i" />
<description>
Returns the tile alternative ID of the cell at coordinates [param coords].
</description>
</method>
<method name="get_cell_atlas_coords" qualifiers="const">
<return type="Vector2i" />
<param index="0" name="coords" type="Vector2i" />
<description>
Returns the tile atlas coordinates ID of the cell at coordinates [param coords]. Returns [code]Vector2i(-1, -1)[/code] if the cell does not exist.
</description>
</method>
<method name="get_cell_source_id" qualifiers="const">
<return type="int" />
<param index="0" name="coords" type="Vector2i" />
<description>
Returns the tile source ID of the cell at coordinates [param coords]. Returns [code]-1[/code] if the cell does not exist.
</description>
</method>
<method name="get_cell_tile_data" qualifiers="const">
<return type="TileData" />
<param index="0" name="coords" type="Vector2i" />
<description>
Returns the [TileData] object associated with the given cell, or [code]null[/code] if the cell does not exist or is not a [TileSetAtlasSource].
[codeblock]
func get_clicked_tile_power():
var clicked_cell = tile_map_layer.local_to_map(tile_map_layer.get_local_mouse_position())
var data = tile_map_layer.get_cell_tile_data(clicked_cell)
if data:
return data.get_custom_data("power")
else:
return 0
[/codeblock]
</description>
</method>
<method name="get_coords_for_body_rid" qualifiers="const">
<return type="Vector2i" />
<param index="0" name="body" type="RID" />
<description>
Returns the coordinates of the tile for given physics body [RID]. Such an [RID] can be retrieved from [method KinematicCollision2D.get_collider_rid], when colliding with a tile.
</description>
</method>
<method name="get_navigation_map" qualifiers="const">
<return type="RID" />
<description>
Returns the [RID] of the [NavigationServer2D] navigation used by this [TileMapLayer].
By default this returns the default [World2D] navigation map, unless a custom map was provided using [method set_navigation_map].
</description>
</method>
<method name="get_neighbor_cell" qualifiers="const">
<return type="Vector2i" />
<param index="0" name="coords" type="Vector2i" />
<param index="1" name="neighbor" type="int" enum="TileSet.CellNeighbor" />
<description>
Returns the neighboring cell to the one at coordinates [param coords], identified by the [param neighbor] direction. This method takes into account the different layouts a TileMap can take.
</description>
</method>
<method name="get_pattern">
<return type="TileMapPattern" />
<param index="0" name="coords_array" type="Vector2i[]" />
<description>
Creates and returns a new [TileMapPattern] from the given array of cells. See also [method set_pattern].
</description>
</method>
<method name="get_surrounding_cells">
<return type="Vector2i[]" />
<param index="0" name="coords" type="Vector2i" />
<description>
Returns the list of all neighboring cells to the one at [param coords].
</description>
</method>
<method name="get_used_cells" qualifiers="const">
<return type="Vector2i[]" />
<description>
Returns a [Vector2i] array with the positions of all cells containing a tile. A cell is considered empty if its source identifier equals [code]-1[/code], its atlas coordinate identifier is [code]Vector2(-1, -1)[/code] and its alternative identifier is [code]-1[/code].
</description>
</method>
<method name="get_used_cells_by_id" qualifiers="const">
<return type="Vector2i[]" />
<param index="0" name="source_id" type="int" default="-1" />
<param index="1" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" />
<param index="2" name="alternative_tile" type="int" default="-1" />
<description>
Returns a [Vector2i] array with the positions of all cells containing a tile. Tiles may be filtered according to their source ([param source_id]), their atlas coordinates ([param atlas_coords]), or alternative id ([param alternative_tile]).
If a parameter has its value set to the default one, this parameter is not used to filter a cell. Thus, if all parameters have their respective default values, this method returns the same result as [method get_used_cells].
A cell is considered empty if its source identifier equals [code]-1[/code], its atlas coordinate identifier is [code]Vector2(-1, -1)[/code] and its alternative identifier is [code]-1[/code].
</description>
</method>
<method name="get_used_rect" qualifiers="const">
<return type="Rect2i" />
<description>
Returns a rectangle enclosing the used (non-empty) tiles of the map.
</description>
</method>
<method name="has_body_rid" qualifiers="const">
<return type="bool" />
<param index="0" name="body" type="RID" />
<description>
Returns whether the provided [param body] [RID] belongs to one of this [TileMapLayer]'s cells.
</description>
</method>
<method name="local_to_map" qualifiers="const">
<return type="Vector2i" />
<param index="0" name="local_position" type="Vector2" />
<description>
Returns the map coordinates of the cell containing the given [param local_position]. If [param local_position] is in global coordinates, consider using [method Node2D.to_local] before passing it to this method. See also [method map_to_local].
</description>
</method>
<method name="map_pattern">
<return type="Vector2i" />
<param index="0" name="position_in_tilemap" type="Vector2i" />
<param index="1" name="coords_in_pattern" type="Vector2i" />
<param index="2" name="pattern" type="TileMapPattern" />
<description>
Returns for the given coordinates [param coords_in_pattern] in a [TileMapPattern] the corresponding cell coordinates if the pattern was pasted at the [param position_in_tilemap] coordinates (see [method set_pattern]). This mapping is required as in half-offset tile shapes, the mapping might not work by calculating [code]position_in_tile_map + coords_in_pattern[/code].
</description>
</method>
<method name="map_to_local" qualifiers="const">
<return type="Vector2" />
<param index="0" name="map_position" type="Vector2i" />
<description>
Returns the centered position of a cell in the [TileMapLayer]'s local coordinate space. To convert the returned value into global coordinates, use [method Node2D.to_global]. See also [method local_to_map].
[b]Note:[/b] This may not correspond to the visual position of the tile, i.e. it ignores the [member TileData.texture_origin] property of individual tiles.
</description>
</method>
<method name="notify_runtime_tile_data_update">
<return type="void" />
<description>
Notifies the [TileMapLayer] node that calls to [method _use_tile_data_runtime_update] or [method _tile_data_runtime_update] will lead to different results. This will thus trigger a [TileMapLayer] update.
[b]Warning:[/b] Updating the [TileMapLayer] is computationally expensive and may impact performance. Try to limit the number of calls to this function to avoid unnecessary update.
[b]Note:[/b] This does not trigger a direct update of the [TileMapLayer], the update will be done at the end of the frame as usual (unless you call [method update_internals]).
</description>
</method>
<method name="set_cell">
<return type="void" />
<param index="0" name="coords" type="Vector2i" />
<param index="1" name="source_id" type="int" default="-1" />
<param index="2" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" />
<param index="3" name="alternative_tile" type="int" default="0" />
<description>
Sets the tile identifiers for the cell at coordinates [param coords]. Each tile of the [TileSet] is identified using three parts:
- The source identifier [param source_id] identifies a [TileSetSource] identifier. See [method TileSet.set_source_id],
- The atlas coordinate identifier [param atlas_coords] identifies a tile coordinates in the atlas (if the source is a [TileSetAtlasSource]). For [TileSetScenesCollectionSource] it should always be [code]Vector2i(0, 0)[/code],
- The alternative tile identifier [param alternative_tile] identifies a tile alternative in the atlas (if the source is a [TileSetAtlasSource]), and the scene for a [TileSetScenesCollectionSource].
If [param source_id] is set to [code]-1[/code], [param atlas_coords] to [code]Vector2i(-1, -1)[/code], or [param alternative_tile] to [code]-1[/code], the cell will be erased. An erased cell gets [b]all[/b] its identifiers automatically set to their respective invalid values, namely [code]-1[/code], [code]Vector2i(-1, -1)[/code] and [code]-1[/code].
</description>
</method>
<method name="set_cells_terrain_connect">
<return type="void" />
<param index="0" name="cells" type="Vector2i[]" />
<param index="1" name="terrain_set" type="int" />
<param index="2" name="terrain" type="int" />
<param index="3" name="ignore_empty_terrains" type="bool" default="true" />
<description>
Update all the cells in the [param cells] coordinates array so that they use the given [param terrain] for the given [param terrain_set]. If an updated cell has the same terrain as one of its neighboring cells, this function tries to join the two. This function might update neighboring tiles if needed to create correct terrain transitions.
If [param ignore_empty_terrains] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints.
[b]Note:[/b] To work correctly, this method requires the [TileMapLayer]'s TileSet to have terrains set up with all required terrain combinations. Otherwise, it may produce unexpected results.
</description>
</method>
<method name="set_cells_terrain_path">
<return type="void" />
<param index="0" name="path" type="Vector2i[]" />
<param index="1" name="terrain_set" type="int" />
<param index="2" name="terrain" type="int" />
<param index="3" name="ignore_empty_terrains" type="bool" default="true" />
<description>
Update all the cells in the [param path] coordinates array so that they use the given [param terrain] for the given [param terrain_set]. The function will also connect two successive cell in the path with the same terrain. This function might update neighboring tiles if needed to create correct terrain transitions.
If [param ignore_empty_terrains] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints.
[b]Note:[/b] To work correctly, this method requires the [TileMapLayer]'s TileSet to have terrains set up with all required terrain combinations. Otherwise, it may produce unexpected results.
</description>
</method>
<method name="set_navigation_map">
<return type="void" />
<param index="0" name="map" type="RID" />
<description>
Sets a custom [param map] as a [NavigationServer2D] navigation map. If not set, uses the default [World2D] navigation map instead.
</description>
</method>
<method name="set_pattern">
<return type="void" />
<param index="0" name="position" type="Vector2i" />
<param index="1" name="pattern" type="TileMapPattern" />
<description>
Pastes the [TileMapPattern] at the given [param position] in the tile map. See also [method get_pattern].
</description>
</method>
<method name="update_internals">
<return type="void" />
<description>
Triggers a direct update of the [TileMapLayer]. Usually, calling this function is not needed, as [TileMapLayer] node updates automatically when one of its properties or cells is modified.
However, for performance reasons, those updates are batched and delayed to the end of the frame. Calling this function will force the [TileMapLayer] to update right away instead.
[b]Warning:[/b] Updating the [TileMapLayer] is computationally expensive and may impact performance. Try to limit the number of updates and how many tiles they impact.
</description>
</method>
</methods>
<members>
<member name="collision_enabled" type="bool" setter="set_collision_enabled" getter="is_collision_enabled" default="true">
Enable or disable collisions.
</member>
<member name="collision_visibility_mode" type="int" setter="set_collision_visibility_mode" getter="get_collision_visibility_mode" enum="TileMapLayer.DebugVisibilityMode" default="0">
Show or hide the [TileMapLayer]'s collision shapes. If set to [constant DEBUG_VISIBILITY_MODE_DEFAULT], this depends on the show collision debug settings.
</member>
<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
If [code]false[/code], disables this [TileMapLayer] completely (rendering, collision, navigation, scene tiles, etc.)
</member>
<member name="navigation_enabled" type="bool" setter="set_navigation_enabled" getter="is_navigation_enabled" default="true">
If [code]true[/code], navigation regions are enabled.
</member>
<member name="navigation_visibility_mode" type="int" setter="set_navigation_visibility_mode" getter="get_navigation_visibility_mode" enum="TileMapLayer.DebugVisibilityMode" default="0">
Show or hide the [TileMapLayer]'s navigation meshes. If set to [constant DEBUG_VISIBILITY_MODE_DEFAULT], this depends on the show navigation debug settings.
</member>
<member name="rendering_quadrant_size" type="int" setter="set_rendering_quadrant_size" getter="get_rendering_quadrant_size" default="16">
The [TileMapLayer]'s quadrant size. A quadrant is a group of tiles to be drawn together on a single canvas item, for optimization purposes. [member rendering_quadrant_size] defines the length of a square's side, in the map's coordinate system, that forms the quadrant. Thus, the default quandrant size groups together [code]16 * 16 = 256[/code] tiles.
The quadrant size does not apply on a Y-sorted [TileMapLayer], as tiles are be grouped by Y position instead in that case.
[b]Note:[/b] As quadrants are created according to the map's coordinate system, the quadrant's "square shape" might not look like square in the [TileMapLayer]'s local coordinate system.
</member>
<member name="tile_map_data" type="PackedByteArray" setter="set_tile_map_data_from_array" getter="get_tile_map_data_as_array" default="PackedByteArray(0, 0)">
The raw tile map data as a byte array.
</member>
<member name="tile_set" type="TileSet" setter="set_tile_set" getter="get_tile_set">
The [TileSet] used by this layer. The textures, collisions, and additional behavior of all available tiles are stored here.
</member>
<member name="use_kinematic_bodies" type="bool" setter="set_use_kinematic_bodies" getter="is_using_kinematic_bodies" default="false">
If [code]true[/code], this [TileMapLayer] collision shapes will be instantiated as kinematic bodies. This can be needed for moving [TileMapLayer] nodes (i.e. moving platforms).
</member>
<member name="y_sort_origin" type="int" setter="set_y_sort_origin" getter="get_y_sort_origin" default="0">
This Y-sort origin value is added to each tile's Y-sort origin value. This allows, for example, to fake a different height level. This can be useful for top-down view games.
</member>
</members>
<signals>
<signal name="changed">
<description>
Emitted when this [TileMapLayer]'s properties changes. This includes modified cells, properties, or changes made to its assigned [TileSet].
[b]Note:[/b] This signal may be emitted very often when batch-modifying a [TileMapLayer]. Avoid executing complex processing in a connected function, and consider delaying it to the end of the frame instead (i.e. calling [method Object.call_deferred]).
</description>
</signal>
</signals>
<constants>
<constant name="DEBUG_VISIBILITY_MODE_DEFAULT" value="0" enum="DebugVisibilityMode">
Hide the collisions or navigation debug shapes in the editor, and use the debug settings to determine their visibility in game (i.e. [member SceneTree.debug_collisions_hint] or [member SceneTree.debug_navigation_hint]).
</constant>
<constant name="DEBUG_VISIBILITY_MODE_FORCE_HIDE" value="2" enum="DebugVisibilityMode">
Always hide the collisions or navigation debug shapes.
</constant>
<constant name="DEBUG_VISIBILITY_MODE_FORCE_SHOW" value="1" enum="DebugVisibilityMode">
Always show the collisions or navigation debug shapes.
</constant>
</constants>
</class>

View file

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="TileMapLayerGroup" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Groups a set of tile map layers together, allowing them to share a provided [TileSet].
</brief_description>
<description>
Groups together tile map layers as part or the same map, replacing the [TileMap] node. Child layers will use this node's [member tile_set].
The editor also uses [TileMapLayerGroup] as a way to store which layers are selected in a given group. This allows highlighting the currently selected layers.
</description>
<tutorials>
</tutorials>
<members>
<member name="tile_set" type="TileSet" setter="set_tileset" getter="get_tileset">
The assigned [TileSet]. This TileSet will be applied to all child layers.
</member>
</members>
</class>

View file

@ -2506,8 +2506,8 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update
editable_info,
info_is_warning);
Object *editor_owner = is_node ? (Object *)SceneTreeDock::get_singleton() : is_resource ? (Object *)InspectorDock::get_inspector_singleton()
: (Object *)this;
Object *editor_owner = (is_node || current_obj->is_class("MultiNodeEdit")) ? (Object *)SceneTreeDock::get_singleton() : is_resource ? (Object *)InspectorDock::get_inspector_singleton()
: (Object *)this;
// Take care of the main editor plugin.

View file

@ -755,6 +755,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Tiles editor
_initial_set("editors/tiles_editor/display_grid", true);
_initial_set("editors/tiles_editor/highlight_selected_layer", true);
_initial_set("editors/tiles_editor/grid_color", Color(1.0, 0.5, 0.2, 0.5));
// Polygon editor

View file

@ -1 +1 @@
<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 7v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2z" fill="#8da5f3"/></svg>
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M8 2 6.25 3.375 8 4.75l1.75-1.375zm2.624 2.062-1.75 1.375 1.75 1.375 1.75-1.375Zm2.626 2.063L11.5 7.5l1.75 1.375L15 7.5ZM5.376 4.062l-1.75 1.375 1.75 1.375 1.75-1.375zM8 6.124 6.25 7.499 8 8.874l1.75-1.375zm2.626 2.063-1.75 1.375 1.75 1.375 1.75-1.375ZM2.75 6.125 1 7.5l1.75 1.375L4.5 7.5Zm2.624 2.062-1.75 1.375 1.75 1.375 1.75-1.375ZM8 10.25l-1.75 1.375L8 13l1.75-1.375z" fill="#8da5f3"/></svg>

Before

Width:  |  Height:  |  Size: 176 B

After

Width:  |  Height:  |  Size: 488 B

View file

@ -36,9 +36,9 @@
#include "editor/editor_resource_preview.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/multi_node_edit.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "editor/themes/editor_scale.h"
#include "scene/2d/camera_2d.h"
#include "scene/2d/tile_map_layer.h"
#include "scene/gui/center_container.h"
@ -107,7 +107,7 @@ void TileMapLayerEditorTilesPlugin::_update_transform_buttons() {
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null() || selection_pattern.is_null()) {
return;
}
@ -171,7 +171,7 @@ void TileMapLayerEditorTilesPlugin::_update_tile_set_sources_list() {
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -256,7 +256,7 @@ void TileMapLayerEditorTilesPlugin::_update_source_display() {
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -302,7 +302,7 @@ void TileMapLayerEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<Inpu
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -348,7 +348,7 @@ void TileMapLayerEditorTilesPlugin::_update_patterns_list() {
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -380,7 +380,7 @@ void TileMapLayerEditorTilesPlugin::_update_atlas_view() {
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -401,7 +401,7 @@ void TileMapLayerEditorTilesPlugin::_update_scenes_collection_view() {
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -459,7 +459,7 @@ void TileMapLayerEditorTilesPlugin::_scenes_list_multi_selected(int p_index, boo
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -538,7 +538,7 @@ bool TileMapLayerEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEven
return false;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return false;
}
@ -784,7 +784,7 @@ void TileMapLayerEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -1021,7 +1021,7 @@ TileMapCell TileMapLayerEditorTilesPlugin::_pick_random_tile(Ref<TileMapPattern>
return TileMapCell();
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return TileMapCell();
}
@ -1073,7 +1073,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTilesPlugin::_draw_line(Vector2
return HashMap<Vector2i, TileMapCell>();
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return HashMap<Vector2i, TileMapCell>();
}
@ -1122,7 +1122,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTilesPlugin::_draw_rect(Vector2
return HashMap<Vector2i, TileMapCell>();
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return HashMap<Vector2i, TileMapCell>();
}
@ -1181,7 +1181,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTilesPlugin::_draw_bucket_fill(
return HashMap<Vector2i, TileMapCell>();
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return HashMap<Vector2i, TileMapCell>();
}
@ -1293,7 +1293,7 @@ void TileMapLayerEditorTilesPlugin::_stop_dragging() {
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -1601,7 +1601,7 @@ void TileMapLayerEditorTilesPlugin::_update_fix_selected_and_hovered() {
selection_pattern.instantiate();
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
hovered_tile.source_id = TileSet::INVALID_SOURCE;
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
@ -1688,7 +1688,7 @@ void TileMapLayerEditorTilesPlugin::_update_selection_pattern_from_tilemap_selec
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -1709,7 +1709,7 @@ void TileMapLayerEditorTilesPlugin::_update_selection_pattern_from_tileset_tiles
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -1783,7 +1783,7 @@ void TileMapLayerEditorTilesPlugin::_update_selection_pattern_from_tileset_patte
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -1822,7 +1822,7 @@ void TileMapLayerEditorTilesPlugin::_tile_atlas_control_draw() {
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -1901,7 +1901,7 @@ void TileMapLayerEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<Inpu
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -2007,7 +2007,7 @@ void TileMapLayerEditorTilesPlugin::_tile_alternatives_control_draw() {
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -2059,7 +2059,7 @@ void TileMapLayerEditorTilesPlugin::_tile_alternatives_control_gui_input(const R
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -2157,16 +2157,21 @@ void TileMapLayerEditorTilesPlugin::edit(ObjectID p_tile_map_layer_id) {
// Disable sort button if the tileset is read-only
TileMapLayer *edited_layer = _get_edited_layer();
Ref<TileSet> tile_set;
if (edited_layer) {
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
tile_set = edited_layer->get_tile_set();
if (tile_set.is_valid()) {
source_sort_button->set_disabled(EditorNode::get_singleton()->is_resource_read_only(tile_set));
}
}
if (edited_tile_map_layer_id != p_tile_map_layer_id) {
edited_tile_map_layer_id = p_tile_map_layer_id;
TileMapLayer *new_tile_map_layer = Object::cast_to<TileMapLayer>(ObjectDB::get_instance(edited_tile_map_layer_id));
Ref<TileSet> new_tile_set;
if (new_tile_map_layer) {
new_tile_set = new_tile_map_layer->get_tile_set();
}
if (tile_set.is_valid() && tile_set != new_tile_set) {
// Clear the selection.
tile_set_selection.clear();
patterns_item_list->deselect_all();
@ -2531,7 +2536,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_terrain_p
return HashMap<Vector2i, TileMapCell>();
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return HashMap<Vector2i, TileMapCell>();
}
@ -2583,7 +2588,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_terrain_p
return HashMap<Vector2i, TileMapCell>();
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return HashMap<Vector2i, TileMapCell>();
}
@ -2630,7 +2635,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_line(Vect
return HashMap<Vector2i, TileMapCell>();
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return HashMap<Vector2i, TileMapCell>();
}
@ -2654,7 +2659,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_rect(Vect
return HashMap<Vector2i, TileMapCell>();
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return HashMap<Vector2i, TileMapCell>();
}
@ -2688,7 +2693,7 @@ RBSet<Vector2i> TileMapLayerEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vec
return RBSet<Vector2i>();
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return RBSet<Vector2i>();
}
@ -2799,7 +2804,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_bucket_fi
return HashMap<Vector2i, TileMapCell>();
}
const Ref<TileSet> &tile_set = edited_layer->get_effective_tile_set();
const Ref<TileSet> &tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return HashMap<Vector2i, TileMapCell>();
}
@ -2827,7 +2832,7 @@ void TileMapLayerEditorTerrainsPlugin::_stop_dragging() {
return;
}
const Ref<TileSet> &tile_set = edited_layer->get_effective_tile_set();
const Ref<TileSet> &tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -2961,7 +2966,7 @@ void TileMapLayerEditorTerrainsPlugin::_update_selection() {
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -3013,7 +3018,7 @@ bool TileMapLayerEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputE
return false;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return false;
}
@ -3150,7 +3155,7 @@ void TileMapLayerEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -3275,7 +3280,7 @@ void TileMapLayerEditorTerrainsPlugin::_update_terrains_cache() {
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -3342,7 +3347,7 @@ void TileMapLayerEditorTerrainsPlugin::_update_terrains_tree() {
const TileMapLayer *edited_layer = _get_edited_layer();
ERR_FAIL_NULL(edited_layer);
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -3389,7 +3394,7 @@ void TileMapLayerEditorTerrainsPlugin::_update_tiles_list() {
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -3627,57 +3632,258 @@ TileMapLayer *TileMapLayerEditor::_get_edited_layer() const {
return Object::cast_to<TileMapLayer>(ObjectDB::get_instance(edited_tile_map_layer_id));
}
void TileMapLayerEditor::_find_tile_map_layers_in_scene(Node *p_current, const Node *p_owner, Vector<TileMapLayer *> &r_list) const {
ERR_FAIL_COND(!p_current || !p_owner);
if (p_current != p_owner && p_current->get_owner() != p_owner) {
return;
}
TileMapLayer *layer = Object::cast_to<TileMapLayer>(p_current);
if (layer) {
r_list.append(layer);
}
for (int i = 0; i < p_current->get_child_count(); i++) {
Node *child = p_current->get_child(i);
_find_tile_map_layers_in_scene(child, p_owner, r_list);
}
}
void TileMapLayerEditor::_update_tile_map_layers_in_scene_list_cache() {
if (!layers_in_scene_list_cache_needs_update) {
return;
}
EditorNode *en = EditorNode::get_singleton();
Node *edited_scene_root = en->get_edited_scene();
if (!edited_scene_root) {
return;
}
tile_map_layers_in_scene_cache.clear();
_find_tile_map_layers_in_scene(edited_scene_root, edited_scene_root, tile_map_layers_in_scene_cache);
layers_in_scene_list_cache_needs_update = false;
}
void TileMapLayerEditor::_node_change(Node *p_node) {
if (!layers_in_scene_list_cache_needs_update && p_node->is_part_of_edited_scene() && Object::cast_to<TileMapLayer>(p_node)) {
layers_in_scene_list_cache_needs_update = true;
}
}
void TileMapLayerEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
get_tree()->connect("node_added", callable_mp(this, &TileMapLayerEditor::_node_change));
get_tree()->connect("node_removed", callable_mp(this, &TileMapLayerEditor::_node_change));
} break;
case NOTIFICATION_THEME_CHANGED: {
missing_tile_texture = get_editor_theme_icon(SNAME("StatusWarning"));
warning_pattern_texture = get_editor_theme_icon(SNAME("WarningPattern"));
advanced_menu_button->set_icon(get_editor_theme_icon(SNAME("Tools")));
select_previous_layer->set_icon(get_editor_theme_icon(SNAME("MoveUp")));
select_next_layer->set_icon(get_editor_theme_icon(SNAME("MoveDown")));
select_all_layers->set_icon(get_editor_theme_icon(SNAME("FileList")));
toggle_grid_button->set_icon(get_editor_theme_icon(SNAME("Grid")));
toggle_grid_button->set_pressed(EDITOR_GET("editors/tiles_editor/display_grid"));
toggle_highlight_selected_layer_button->set_icon(get_editor_theme_icon(SNAME("TileMapHighlightSelected")));
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
if (is_visible_in_tree() && tileset_changed_needs_update) {
if (is_visible_in_tree() && tile_map_layer_changed_needs_update) {
_update_bottom_panel();
update_layers_selector();
_update_highlighting_toggle();
_update_layers_selector();
tabs_plugins[tabs_bar->get_current_tab()]->tile_set_changed();
CanvasItemEditor::get_singleton()->update_viewport();
tileset_changed_needs_update = false;
tile_map_layer_changed_needs_update = false;
}
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
if (EditorSettings::get_singleton()->check_changed_settings_in_group("editors/tiles_editor")) {
toggle_grid_button->set_pressed_no_signal(EDITOR_GET("editors/tiles_editor/display_grid"));
toggle_highlight_selected_layer_button->set_pressed_no_signal(EDITOR_GET("editors/tiles_editor/highlight_selected_layer"));
}
} break;
}
}
void TileMapLayerEditor::_bind_methods() {
ADD_SIGNAL(MethodInfo("change_selected_layer_request", PropertyInfo(Variant::STRING_NAME, "layer_name")));
}
void TileMapLayerEditor::_on_grid_toggled(bool p_pressed) {
EditorSettings::get_singleton()->set("editors/tiles_editor/display_grid", p_pressed);
CanvasItemEditor::get_singleton()->update_viewport();
}
void TileMapLayerEditor::_select_previous_layer_pressed() {
_layers_select_next_or_previous(false);
}
void TileMapLayerEditor::_select_next_layer_pressed() {
_layers_select_next_or_previous(true);
}
void TileMapLayerEditor::_select_all_layers_pressed() {
EditorNode *en = EditorNode::get_singleton();
Node *edited_scene_root = en->get_edited_scene();
ERR_FAIL_NULL(edited_scene_root);
en->get_editor_selection()->clear();
if (tile_map_layers_in_scene_cache.size() == 1) {
en->edit_node(tile_map_layers_in_scene_cache[0]);
en->get_editor_selection()->add_node(tile_map_layers_in_scene_cache[0]);
} else {
_update_tile_map_layers_in_scene_list_cache();
Ref<MultiNodeEdit> multi_node_edit = memnew(MultiNodeEdit);
for (TileMapLayer *layer : tile_map_layers_in_scene_cache) {
multi_node_edit->add_node(edited_scene_root->get_path_to(layer));
en->get_editor_selection()->add_node(layer);
}
en->push_item(multi_node_edit.ptr());
}
}
void TileMapLayerEditor::_layers_selection_item_selected(int p_index) {
emit_signal("change_selected_layer_request", layers_selection_button->get_item_metadata(p_index));
TileMapLayer *edited_layer = _get_edited_layer();
ERR_FAIL_NULL(edited_layer);
TileMap *tile_map = Object::cast_to<TileMap>(edited_layer->get_parent());
ERR_FAIL_NULL(tile_map);
TileMapLayer *new_edited = Object::cast_to<TileMapLayer>(tile_map->get_child(p_index));
edit(new_edited);
}
void TileMapLayerEditor::_update_layers_selector() {
const TileMapLayer *edited_layer = _get_edited_layer();
// Update the selector.
layers_selection_button->clear();
layers_selection_button->hide();
select_all_layers->show();
select_next_layer->set_disabled(false);
select_previous_layer->set_disabled(false);
advanced_menu_button->get_popup()->set_item_disabled(ADVANCED_MENU_EXTRACT_TILE_MAP_LAYERS, true);
if (edited_layer) {
TileMap *tile_map = Object::cast_to<TileMap>(edited_layer->get_parent());
if (tile_map && edited_layer->get_index_in_tile_map() >= 0) {
// Build the list of layers.
for (int i = 0; i < tile_map->get_layers_count(); i++) {
const TileMapLayer *layer = Object::cast_to<TileMapLayer>(tile_map->get_child(i));
if (layer) {
int index = layers_selection_button->get_item_count();
layers_selection_button->add_item(layer->get_name());
layers_selection_button->set_item_metadata(index, layer->get_name());
if (edited_layer == layer) {
layers_selection_button->select(index);
}
}
}
// Disable selector if there's no layer to select.
layers_selection_button->set_disabled(false);
if (layers_selection_button->get_item_count() == 0) {
layers_selection_button->set_disabled(true);
layers_selection_button->set_text(TTR("No Layers"));
}
// Disable next/previous if there's one or less layers.
if (layers_selection_button->get_item_count() <= 1) {
select_next_layer->set_disabled(true);
select_previous_layer->set_disabled(true);
}
layers_selection_button->show();
select_all_layers->hide();
// Enable the "extract as TileMapLayer" option only if we are editing a TleMap.
advanced_menu_button->get_popup()->set_item_disabled(ADVANCED_MENU_EXTRACT_TILE_MAP_LAYERS, false);
}
} else {
select_all_layers->hide();
select_next_layer->set_disabled(true);
select_previous_layer->set_disabled(true);
}
}
void TileMapLayerEditor::_clear_all_layers_highlighting() {
// Note: This function might be removed if we remove the TileMap node at some point.
// All processing could be done in _update_all_layers_highlighting otherwise.
TileMapLayer *edited_layer = _get_edited_layer();
// Use default mode.
if (edited_layer && edited_layer->get_index_in_tile_map() >= 0) {
// For the TileMap node.
TileMap *tile_map = Object::cast_to<TileMap>(edited_layer->get_parent());
if (tile_map) {
for (int i = 0; i < tile_map->get_layers_count(); i++) {
TileMapLayer *layer = Object::cast_to<TileMapLayer>(tile_map->get_child(i));
layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_DEFAULT);
}
}
} else {
// For other TileMapLayer nodes.
_update_tile_map_layers_in_scene_list_cache();
for (TileMapLayer *layer : tile_map_layers_in_scene_cache) {
layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_DEFAULT);
}
}
}
void TileMapLayerEditor::_update_all_layers_highlighting() {
EditorNode *en = EditorNode::get_singleton();
Node *edited_scene_root = en->get_edited_scene();
if (!edited_scene_root) {
return;
}
// Get selected layer.
TileMapLayer *edited_layer = _get_edited_layer();
bool highlight_selected_layer = EDITOR_GET("editors/tiles_editor/highlight_selected_layer");
if (edited_layer && highlight_selected_layer) {
int edited_z_index = edited_layer->get_z_index();
if (edited_layer->get_index_in_tile_map() >= 0) {
// For the TileMap node.
TileMap *tile_map = Object::cast_to<TileMap>(edited_layer->get_parent());
ERR_FAIL_NULL(tile_map);
bool passed = false;
for (int i = 0; i < tile_map->get_layers_count(); i++) {
TileMapLayer *layer = Object::cast_to<TileMapLayer>(tile_map->get_child(i));
if (layer == edited_layer) {
passed = true;
layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_DEFAULT);
} else {
if (passed || layer->get_z_index() > edited_z_index) {
layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_ABOVE);
} else {
layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_BELOW);
}
}
}
} else {
// Update highlight mode for independent layers.
_update_tile_map_layers_in_scene_list_cache();
bool passed = false;
for (TileMapLayer *layer : tile_map_layers_in_scene_cache) {
if (layer == edited_layer) {
passed = true;
layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_DEFAULT);
} else {
if (passed || layer->get_z_index() > edited_z_index) {
layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_ABOVE);
} else {
layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_BELOW);
}
}
}
}
}
}
void TileMapLayerEditor::_highlight_selected_layer_button_toggled(bool p_pressed) {
TileMapLayer *edited_layer = _get_edited_layer();
ERR_FAIL_NULL(edited_layer);
if (!edited_layer) {
return;
}
TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent());
ERR_FAIL_NULL(tile_map_layer_group);
tile_map_layer_group->set_highlight_selected_layer(p_pressed);
EditorSettings::get_singleton()->set("editors/tiles_editor/highlight_selected_layer", p_pressed);
_update_all_layers_highlighting();
}
void TileMapLayerEditor::_advanced_menu_button_id_pressed(int p_id) {
@ -3686,12 +3892,12 @@ void TileMapLayerEditor::_advanced_menu_button_id_pressed(int p_id) {
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
if (p_id == 0) { // Replace Tile Proxies
if (p_id == ADVANCED_MENU_REPLACE_WITH_PROXIES) { // Replace Tile Proxies
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Replace Tiles with Proxies"));
TypedArray<Vector2i> used_cells = edited_layer->get_used_cells();
@ -3709,32 +3915,75 @@ void TileMapLayerEditor::_advanced_menu_button_id_pressed(int p_id) {
}
}
undo_redo->commit_action();
} else if (p_id == ADVANCED_MENU_EXTRACT_TILE_MAP_LAYERS) { // Transform internal TileMap layers into TileMapLayers.
ERR_FAIL_COND(edited_layer->get_index_in_tile_map() < 0);
EditorNode *en = EditorNode::get_singleton();
Node *edited_scene_root = en->get_edited_scene();
ERR_FAIL_NULL(edited_scene_root);
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Extract TileMap layers as individual TileMapLayer nodes"));
TileMap *tile_map = Object::cast_to<TileMap>(edited_layer->get_parent());
for (int i = 0; i < tile_map->get_layers_count(); i++) {
undo_redo->add_do_method(tile_map, "remove_layer", 0);
}
for (int i = 0; i < tile_map->get_layers_count(); i++) {
TileMapLayer *new_layer = tile_map->duplicate_layer_from_internal(i);
undo_redo->add_do_method(tile_map, "add_child", new_layer);
undo_redo->add_do_method(new_layer, "set_owner", edited_scene_root);
undo_redo->add_do_property(new_layer, "tile_set", tile_map->get_tileset()); // Workaround for a bug: #89947.
undo_redo->add_undo_method(tile_map, "remove_child", new_layer);
undo_redo->add_do_reference(new_layer);
}
List<PropertyInfo> prop_list;
tile_map->get_property_list(&prop_list);
for (PropertyInfo &prop : prop_list) {
undo_redo->add_undo_property(tile_map, prop.name, tile_map->get(prop.name));
}
undo_redo->commit_action();
}
}
void TileMapLayerEditor::_update_bottom_panel() {
const TileMapLayer *edited_layer = _get_edited_layer();
if (!edited_layer) {
return;
Ref<TileSet> tile_set;
if (edited_layer) {
tile_set = edited_layer->get_tile_set();
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
// Update state labels.
if (is_multi_node_edit) {
cant_edit_label->set_text(TTR("Can't edit multiple layers at once."));
cant_edit_label->show();
} else if (!edited_layer) {
cant_edit_label->set_text(TTR("The selected TileMap has no layer to edit."));
cant_edit_label->show();
} else if (!edited_layer->is_enabled() || !edited_layer->is_visible_in_tree()) {
cant_edit_label->set_text(TTR("The edited layer is disabled or invisible"));
cant_edit_label->show();
} else if (tile_set.is_null()) {
cant_edit_label->set_text(TTR("The edited TileMap or TileMapLayer node has no TileSet resource.\nCreate or load a TileSet resource in the Tile Set property in the inspector."));
cant_edit_label->show();
} else {
cant_edit_label->hide();
}
// Update the visibility of controls.
missing_tileset_label->set_visible(tile_set.is_null());
// Update tabs visibility.
for (TileMapLayerSubEditorPlugin::TabData &tab_data : tabs_data) {
tab_data.panel->hide();
}
if (tile_set.is_valid()) {
tabs_data[tabs_bar->get_current_tab()].panel->show();
}
tabs_data[tabs_bar->get_current_tab()].panel->set_visible(!cant_edit_label->is_visible());
}
Vector<Vector2i> TileMapLayerEditor::get_line(const TileMapLayer *p_tile_map_layer, Vector2i p_from_cell, Vector2i p_to_cell) {
ERR_FAIL_NULL_V(p_tile_map_layer, Vector<Vector2i>());
Ref<TileSet> tile_set = p_tile_map_layer->get_effective_tile_set();
Ref<TileSet> tile_set = p_tile_map_layer->get_tile_set();
ERR_FAIL_COND_V(tile_set.is_null(), Vector<Vector2i>());
if (tile_set->get_tile_shape() == TileSet::TILE_SHAPE_SQUARE) {
@ -3805,7 +4054,7 @@ Vector<Vector2i> TileMapLayerEditor::get_line(const TileMapLayer *p_tile_map_lay
}
void TileMapLayerEditor::_tile_map_layer_changed() {
tileset_changed_needs_update = true;
tile_map_layer_changed_needs_update = true;
}
void TileMapLayerEditor::_tab_changed(int p_tab_id) {
@ -3825,7 +4074,7 @@ void TileMapLayerEditor::_tab_changed(int p_tab_id) {
TileMapLayer *tile_map_layer = _get_edited_layer();
if (tile_map_layer) {
if (tile_map_layer->get_effective_tile_set().is_valid()) {
if (tile_map_layer->get_tile_set().is_valid()) {
tabs_data[tabs_bar->get_current_tab()].panel->show();
}
}
@ -3841,36 +4090,38 @@ void TileMapLayerEditor::_layers_select_next_or_previous(bool p_next) {
return;
}
TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent());
if (!tile_map_layer_group) {
return;
}
EditorNode *en = EditorNode::get_singleton();
Node *edited_scene_root = en->get_edited_scene();
ERR_FAIL_NULL(edited_scene_root);
TileMapLayer *new_selected_layer = nullptr;
int inc = p_next ? 1 : -1;
int index = Math::posmod(edited_layer->get_index() + inc, tile_map_layer_group->get_child_count());
const TileMapLayer *new_selected_layer = Object::cast_to<TileMapLayer>(tile_map_layer_group->get_child(index));
while (new_selected_layer != edited_layer) {
if (new_selected_layer && new_selected_layer->is_enabled()) {
break;
if (edited_layer->get_index_in_tile_map() >= 0) {
// Part of a TileMap.
TileMap *tile_map = Object::cast_to<TileMap>(edited_layer->get_parent());
new_selected_layer = Object::cast_to<TileMapLayer>(tile_map->get_child(Math::posmod(edited_layer->get_index_in_tile_map() + inc, tile_map->get_layers_count())));
} else {
// Individual layer.
_update_tile_map_layers_in_scene_list_cache();
int edited_index = -1;
for (int i = 0; i < tile_map_layers_in_scene_cache.size(); i++) {
if (tile_map_layers_in_scene_cache[i] == edited_layer) {
edited_index = i;
break;
}
}
index = Math::posmod((index + inc), tile_map_layer_group->get_child_count());
new_selected_layer = Object::cast_to<TileMapLayer>(tile_map_layer_group->get_child(index));
new_selected_layer = tile_map_layers_in_scene_cache[Math::posmod(edited_index + inc, tile_map_layers_in_scene_cache.size())];
}
if (new_selected_layer != edited_layer) {
emit_signal("change_selected_layer_request", new_selected_layer->get_name());
}
}
ERR_FAIL_NULL(new_selected_layer);
void TileMapLayerEditor::_update_highlighting_toggle() {
const TileMapLayer *edited_layer = _get_edited_layer();
if (!edited_layer) {
return;
}
TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent());
if (tile_map_layer_group) {
toggle_highlight_selected_layer_button->set_pressed(tile_map_layer_group->is_highlighting_selected_layer());
if (edited_layer->get_index_in_tile_map() < 0) {
// Only if not part of a TileMap.
en->edit_node(new_selected_layer);
en->get_editor_selection()->clear();
en->get_editor_selection()->add_node(new_selected_layer);
} else {
edit(new_selected_layer);
}
}
@ -3966,7 +4217,7 @@ void TileMapLayerEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
return;
}
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_null()) {
return;
}
@ -3994,29 +4245,25 @@ void TileMapLayerEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
}
if (!source || !source->has_tile(tile_atlas_coords) || !source->has_alternative_tile(tile_atlas_coords, tile_alternative_tile)) {
// Generate a random color from the hashed values of the tiles.
Array a = tile_set->map_tile_proxy(tile_source_id, tile_atlas_coords, tile_alternative_tile);
if (int(a[0]) == tile_source_id && Vector2i(a[1]) == tile_atlas_coords && int(a[2]) == tile_alternative_tile) {
// Only display the pattern if we have no proxy tile.
Array to_hash;
to_hash.push_back(tile_source_id);
to_hash.push_back(tile_atlas_coords);
to_hash.push_back(tile_alternative_tile);
uint32_t hash = RandomPCG(to_hash.hash()).rand();
// Generate a random color from the hashed identifier of the tiles.
Array to_hash;
to_hash.push_back(tile_source_id);
to_hash.push_back(tile_atlas_coords);
to_hash.push_back(tile_alternative_tile);
uint32_t hash = RandomPCG(to_hash.hash()).rand();
Color color;
color = color.from_hsv(
(float)((hash >> 24) & 0xFF) / 256.0,
Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0),
Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0),
0.8);
Color color;
color = color.from_hsv(
(float)((hash >> 24) & 0xFF) / 256.0,
Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0),
Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0),
0.8);
// Draw the scaled tile.
Transform2D tile_xform;
tile_xform.set_origin(tile_set->map_to_local(coords));
tile_xform.set_scale(tile_shape_size);
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, true, warning_pattern_texture);
}
// Display the warning pattern.
Transform2D tile_xform;
tile_xform.set_origin(tile_set->map_to_local(coords));
tile_xform.set_scale(tile_shape_size);
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, true, warning_pattern_texture);
// Draw the warning icon.
Vector2::Axis min_axis = missing_tile_texture->get_size().min_axis_index();
@ -4092,75 +4339,50 @@ void TileMapLayerEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
tabs_plugins[tabs_bar->get_current_tab()]->forward_canvas_draw_over_viewport(p_overlay);
}
void TileMapLayerEditor::edit(TileMapLayer *p_tile_map_layer) {
if (p_tile_map_layer && p_tile_map_layer->get_instance_id() == edited_tile_map_layer_id) {
void TileMapLayerEditor::edit(Object *p_edited) {
if (p_edited && p_edited->get_instance_id() == edited_tile_map_layer_id) {
return;
}
_clear_all_layers_highlighting();
// Disconnect to changes.
TileMapLayer *tile_map_layer = _get_edited_layer();
if (tile_map_layer) {
tile_map_layer->disconnect("changed", callable_mp(this, &TileMapLayerEditor::_tile_map_layer_changed));
tile_map_layer->disconnect("visibility_changed", callable_mp(this, &TileMapLayerEditor::_tile_map_layer_changed));
}
// Update the edited layer.
if (p_tile_map_layer) {
TileMapLayer *new_layer = Object::cast_to<TileMapLayer>(p_edited);
if (new_layer) {
// Change the edited object.
edited_tile_map_layer_id = p_tile_map_layer->get_instance_id();
edited_tile_map_layer_id = new_layer->get_instance_id();
tile_map_layer = _get_edited_layer();
// Connect to changes.
if (!tile_map_layer->is_connected("changed", callable_mp(this, &TileMapLayerEditor::_tile_map_layer_changed))) {
tile_map_layer->connect("changed", callable_mp(this, &TileMapLayerEditor::_tile_map_layer_changed));
tile_map_layer->connect("visibility_changed", callable_mp(this, &TileMapLayerEditor::_tile_map_layer_changed));
}
} else {
edited_tile_map_layer_id = ObjectID();
}
update_layers_selector();
_update_highlighting_toggle();
// Check if we are trying to use a MultiNodeEdit.
is_multi_node_edit = Object::cast_to<MultiNodeEdit>(p_edited);
// Call the plugins.
// Call the plugins and update everything.
tabs_plugins[tabs_bar->get_current_tab()]->edit(edited_tile_map_layer_id);
_update_layers_selector();
_update_all_layers_highlighting();
_tile_map_layer_changed();
}
void TileMapLayerEditor::update_layers_selector() {
const TileMapLayer *edited_layer = _get_edited_layer();
if (!edited_layer) {
return;
}
TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent());
if (tile_map_layer_group) {
// Update the selector
layers_selection_button->show();
layers_selection_button->clear();
// Build the list of layers.
for (int i = 0; i < tile_map_layer_group->get_child_count(); i++) {
const TileMapLayer *layer = Object::cast_to<TileMapLayer>(tile_map_layer_group->get_child(i));
if (layer) {
int index = layers_selection_button->get_item_count();
layers_selection_button->add_item(layer->get_name());
layers_selection_button->set_item_disabled(index, !layer->is_enabled());
layers_selection_button->set_item_metadata(index, layer->get_name());
if (edited_layer == layer) {
layers_selection_button->select(index);
}
}
}
// Disable the button if there's no layer to select.
layers_selection_button->set_disabled(false);
if (layers_selection_button->get_item_count() == 0) {
layers_selection_button->set_disabled(true);
layers_selection_button->set_text(TTR("No Layers"));
}
} else {
layers_selection_button->hide();
}
void TileMapLayerEditor::set_show_layer_selector(bool p_show_layer_selector) {
show_layers_selector = p_show_layer_selector;
_update_layers_selector();
}
TileMapLayerEditor::TileMapLayerEditor() {
@ -4210,13 +4432,36 @@ TileMapLayerEditor::TileMapLayerEditor() {
tile_map_toolbar->add_child(c);
// Layer selector.
layer_selection_hbox = memnew(HBoxContainer);
tile_map_toolbar->add_child(layer_selection_hbox);
layers_selection_button = memnew(OptionButton);
layers_selection_button->set_custom_minimum_size(Size2(200, 0));
layers_selection_button->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
layers_selection_button->set_tooltip_text(TTR("TileMap Layers"));
layers_selection_button->connect("item_selected", callable_mp(this, &TileMapLayerEditor::_layers_selection_item_selected));
tile_map_toolbar->add_child(layers_selection_button);
layer_selection_hbox->add_child(layers_selection_button);
select_previous_layer = memnew(Button);
select_previous_layer->set_theme_type_variation("FlatButton");
select_previous_layer->set_tooltip_text(TTR("Select previous layer"));
select_previous_layer->connect("pressed", callable_mp(this, &TileMapLayerEditor::_select_previous_layer_pressed));
layer_selection_hbox->add_child(select_previous_layer);
select_next_layer = memnew(Button);
select_next_layer->set_theme_type_variation("FlatButton");
select_next_layer->set_tooltip_text(TTR("Select next layer"));
select_next_layer->connect("pressed", callable_mp(this, &TileMapLayerEditor::_select_next_layer_pressed));
layer_selection_hbox->add_child(select_next_layer);
select_all_layers = memnew(Button);
select_all_layers->set_theme_type_variation("FlatButton");
select_all_layers->set_text(TTR("Select all layers"));
select_all_layers->connect("pressed", callable_mp(this, &TileMapLayerEditor::_select_all_layers_pressed));
select_all_layers->set_tooltip_text(TTR("Select all TileMapLayers in scene"));
layer_selection_hbox->add_child(select_all_layers);
// Highlighting selected layer.
toggle_highlight_selected_layer_button = memnew(Button);
toggle_highlight_selected_layer_button->set_theme_type_variation("FlatButton");
toggle_highlight_selected_layer_button->set_toggle_mode(true);
@ -4239,18 +4484,19 @@ TileMapLayerEditor::TileMapLayerEditor() {
advanced_menu_button = memnew(MenuButton);
advanced_menu_button->set_flat(false);
advanced_menu_button->set_theme_type_variation("FlatButton");
advanced_menu_button->get_popup()->add_item(TTR("Automatically Replace Tiles with Proxies"));
advanced_menu_button->get_popup()->add_item(TTR("Automatically Replace Tiles with Proxies"), ADVANCED_MENU_REPLACE_WITH_PROXIES);
advanced_menu_button->get_popup()->add_item(TTR("Extract TileMap layers as individual TileMapLayer nodes"), ADVANCED_MENU_EXTRACT_TILE_MAP_LAYERS);
advanced_menu_button->get_popup()->connect("id_pressed", callable_mp(this, &TileMapLayerEditor::_advanced_menu_button_id_pressed));
tile_map_toolbar->add_child(advanced_menu_button);
missing_tileset_label = memnew(Label);
missing_tileset_label->set_text(TTR("The edited TileMap node has no TileSet resource.\nCreate or load a TileSet resource in the Tile Set property in the inspector."));
missing_tileset_label->set_h_size_flags(SIZE_EXPAND_FILL);
missing_tileset_label->set_v_size_flags(SIZE_EXPAND_FILL);
missing_tileset_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
missing_tileset_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
missing_tileset_label->hide();
add_child(missing_tileset_label);
// A label for editing errors.
cant_edit_label = memnew(Label);
cant_edit_label->set_h_size_flags(SIZE_EXPAND_FILL);
cant_edit_label->set_v_size_flags(SIZE_EXPAND_FILL);
cant_edit_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
cant_edit_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
cant_edit_label->hide();
add_child(cant_edit_label);
for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) {
add_child(tabs_data[tab_index].panel);

View file

@ -339,10 +339,16 @@ class TileMapLayerEditor : public VBoxContainer {
GDCLASS(TileMapLayerEditor, VBoxContainer);
private:
bool tileset_changed_needs_update = false;
bool tile_map_layer_changed_needs_update = false;
ObjectID edited_tile_map_layer_id;
bool is_multi_node_edit = false;
Vector<TileMapLayer *> tile_map_layers_in_scene_cache;
bool layers_in_scene_list_cache_needs_update = false;
TileMapLayer *_get_edited_layer() const;
void _find_tile_map_layers_in_scene(Node *p_current, const Node *p_owner, Vector<TileMapLayer *> &r_list) const;
void _update_tile_map_layers_in_scene_list_cache();
void _node_change(Node *p_node);
// Vector to keep plugins.
Vector<TileMapLayerSubEditorPlugin *> tile_map_editor_plugins;
@ -350,20 +356,36 @@ private:
// Toolbar.
HFlowContainer *tile_map_toolbar = nullptr;
bool show_layers_selector = false;
HBoxContainer *layer_selection_hbox = nullptr;
Button *select_previous_layer = nullptr;
void _select_previous_layer_pressed();
Button *select_next_layer = nullptr;
void _select_next_layer_pressed();
Button *select_all_layers = nullptr;
void _select_all_layers_pressed();
OptionButton *layers_selection_button = nullptr;
void _layers_selection_item_selected(int p_index);
void _update_layers_selector();
Button *toggle_highlight_selected_layer_button = nullptr;
void _clear_all_layers_highlighting();
void _update_all_layers_highlighting();
void _highlight_selected_layer_button_toggled(bool p_pressed);
Button *toggle_grid_button = nullptr;
void _on_grid_toggled(bool p_pressed);
enum {
ADVANCED_MENU_REPLACE_WITH_PROXIES,
ADVANCED_MENU_EXTRACT_TILE_MAP_LAYERS,
};
MenuButton *advanced_menu_button = nullptr;
void _advanced_menu_button_id_pressed(int p_id);
// Bottom panel.
Label *missing_tileset_label = nullptr;
Label *cant_edit_label = nullptr;
TabBar *tabs_bar = nullptr;
LocalVector<TileMapLayerSubEditorPlugin::TabData> tabs_data;
LocalVector<TileMapLayerSubEditorPlugin *> tabs_plugins;
@ -379,22 +401,20 @@ private:
// Updates.
void _layers_select_next_or_previous(bool p_next);
void _update_highlighting_toggle();
// Inspector undo/redo callback.
void _move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, const String &p_array_prefix, int p_from_index, int p_to_pos);
protected:
void _notification(int p_what);
static void _bind_methods();
void _draw_shape(Control *p_control, Rect2 p_region, TileSet::TileShape p_shape, TileSet::TileOffsetAxis p_offset_axis, Color p_color);
public:
bool forward_canvas_gui_input(const Ref<InputEvent> &p_event);
void forward_canvas_draw_over_viewport(Control *p_overlay);
void edit(TileMapLayer *p_tile_map_layer);
void update_layers_selector();
void edit(Object *p_tile_map_layer);
void set_show_layer_selector(bool p_show_layer_selector);
TileMapLayerEditor();
~TileMapLayerEditor();

View file

@ -40,6 +40,7 @@
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"
#include "editor/gui/editor_bottom_panel.h"
#include "editor/multi_node_edit.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "editor/themes/editor_scale.h"
#include "scene/2d/tile_map.h"
@ -336,7 +337,7 @@ void TileMapEditorPlugin::_tile_map_layer_removed() {
void TileMapEditorPlugin::_update_tile_map() {
TileMapLayer *edited_layer = Object::cast_to<TileMapLayer>(ObjectDB::get_instance(tile_map_layer_id));
if (edited_layer) {
Ref<TileSet> tile_set = edited_layer->get_effective_tile_set();
Ref<TileSet> tile_set = edited_layer->get_tile_set();
if (tile_set.is_valid() && tile_set_id != tile_set->get_instance_id()) {
tile_set_plugin_singleton->edit(tile_set.ptr());
tile_set_plugin_singleton->make_visible(true);
@ -355,38 +356,25 @@ void TileMapEditorPlugin::_select_layer(const StringName &p_name) {
ERR_FAIL_NULL(edited_layer);
Node *parent = edited_layer->get_parent();
ERR_FAIL_NULL(parent);
TileMapLayer *new_layer = Object::cast_to<TileMapLayer>(parent->get_node_or_null(String(p_name)));
edit(new_layer);
if (parent) {
TileMapLayer *new_layer = Object::cast_to<TileMapLayer>(parent->get_node_or_null(String(p_name)));
edit(new_layer);
}
}
void TileMapEditorPlugin::_edit_tile_map_layer(TileMapLayer *p_tile_map_layer) {
void TileMapEditorPlugin::_edit_tile_map_layer(TileMapLayer *p_tile_map_layer, bool p_show_layer_selector) {
ERR_FAIL_NULL(p_tile_map_layer);
editor->edit(p_tile_map_layer);
// Update the selected layers in the TileMapLayerGroup parent node.
TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(p_tile_map_layer->get_parent());
if (tile_map_layer_group) {
Vector<StringName> selected;
selected.push_back(p_tile_map_layer->get_name());
tile_map_layer_group->set_selected_layers(selected);
}
editor->set_show_layer_selector(p_show_layer_selector);
// Update the object IDs.
tile_map_layer_id = p_tile_map_layer->get_instance_id();
p_tile_map_layer->connect("changed", callable_mp(this, &TileMapEditorPlugin::_tile_map_layer_changed));
p_tile_map_layer->connect("tree_exited", callable_mp(this, &TileMapEditorPlugin::_tile_map_layer_removed));
if (tile_map_layer_group) {
tile_map_group_id = tile_map_layer_group->get_instance_id();
tile_map_layer_group->connect("child_entered_tree", callable_mp(editor, &TileMapLayerEditor::update_layers_selector).unbind(1));
tile_map_layer_group->connect("child_exiting_tree", callable_mp(editor, &TileMapLayerEditor::update_layers_selector).unbind(1));
tile_map_layer_group->connect("child_order_changed", callable_mp(editor, &TileMapLayerEditor::update_layers_selector));
}
// Update the edited tileset.
Ref<TileSet> tile_set = p_tile_map_layer->get_effective_tile_set();
Ref<TileSet> tile_set = p_tile_map_layer->get_tile_set();
if (tile_set.is_valid()) {
tile_set_plugin_singleton->edit(tile_set.ptr());
tile_set_plugin_singleton->make_visible(true);
@ -397,30 +385,15 @@ void TileMapEditorPlugin::_edit_tile_map_layer(TileMapLayer *p_tile_map_layer) {
}
}
void TileMapEditorPlugin::_edit_tile_map_layer_group(TileMapLayerGroup *p_tile_map_layer_group) {
ERR_FAIL_NULL(p_tile_map_layer_group);
void TileMapEditorPlugin::_edit_tile_map(TileMap *p_tile_map) {
ERR_FAIL_NULL(p_tile_map);
Vector<StringName> selected_layers = p_tile_map_layer_group->get_selected_layers();
TileMapLayer *selected_layer = nullptr;
if (selected_layers.size() > 0) {
// Edit the selected layer.
selected_layer = Object::cast_to<TileMapLayer>(p_tile_map_layer_group->get_node_or_null(String(selected_layers[0])));
}
if (!selected_layer) {
// Edit the first layer found.
for (int i = 0; i < p_tile_map_layer_group->get_child_count(); i++) {
selected_layer = Object::cast_to<TileMapLayer>(p_tile_map_layer_group->get_child(i));
if (selected_layer) {
break;
}
}
}
if (selected_layer) {
_edit_tile_map_layer(selected_layer);
if (p_tile_map->get_layers_count() > 0) {
TileMapLayer *selected_layer = Object::cast_to<TileMapLayer>(p_tile_map->get_child(0));
_edit_tile_map_layer(selected_layer, true);
} else {
editor->edit(nullptr);
editor->set_show_layer_selector(false);
}
}
@ -437,36 +410,38 @@ void TileMapEditorPlugin::edit(Object *p_object) {
edited_layer->disconnect("tree_exited", callable_mp(this, &TileMapEditorPlugin::_tile_map_layer_removed));
}
TileMapLayerGroup *tile_map_group = Object::cast_to<TileMapLayerGroup>(ObjectDB::get_instance(tile_map_group_id));
if (tile_map_group) {
tile_map_group->disconnect("child_entered_tree", callable_mp(editor, &TileMapLayerEditor::update_layers_selector).unbind(1));
tile_map_group->disconnect("child_exiting_tree", callable_mp(editor, &TileMapLayerEditor::update_layers_selector).unbind(1));
tile_map_group->disconnect("child_order_changed", callable_mp(editor, &TileMapLayerEditor::update_layers_selector));
}
tile_map_group_id = ObjectID();
tile_map_layer_id = ObjectID();
tile_set_id = ObjectID();
TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMap>(p_object);
TileMap *tile_map = Object::cast_to<TileMap>(p_object);
TileMapLayer *tile_map_layer = Object::cast_to<TileMapLayer>(p_object);
if (tile_map_layer_group) {
_edit_tile_map_layer_group(tile_map_layer_group);
MultiNodeEdit *multi_node_edit = Object::cast_to<MultiNodeEdit>(p_object);
if (tile_map) {
_edit_tile_map(tile_map);
} else if (tile_map_layer) {
_edit_tile_map_layer(tile_map_layer);
_edit_tile_map_layer(tile_map_layer, false);
} else if (multi_node_edit) {
editor->edit(multi_node_edit);
} else {
// Deselect the layer in the group.
if (edited_layer) {
tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent());
if (tile_map_layer_group) {
tile_map_layer_group->set_selected_layers(Vector<StringName>());
}
}
editor->edit(nullptr);
}
}
bool TileMapEditorPlugin::handles(Object *p_object) const {
return Object::cast_to<TileMapLayer>(p_object) != nullptr || Object::cast_to<TileMapLayerGroup>(p_object) != nullptr;
MultiNodeEdit *multi_node_edit = Object::cast_to<MultiNodeEdit>(p_object);
Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
if (multi_node_edit && edited_scene) {
bool only_tile_map_layers = true;
for (int i = 0; i < multi_node_edit->get_node_count(); i++) {
if (!Object::cast_to<TileMapLayer>(edited_scene->get_node(multi_node_edit->get_node(i)))) {
only_tile_map_layers = false;
break;
}
}
return only_tile_map_layers;
}
return Object::cast_to<TileMapLayer>(p_object) != nullptr || Object::cast_to<TileMap>(p_object) != nullptr;
}
void TileMapEditorPlugin::make_visible(bool p_visible) {
@ -509,7 +484,6 @@ TileMapEditorPlugin::TileMapEditorPlugin() {
editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
editor->connect("change_selected_layer_request", callable_mp(this, &TileMapEditorPlugin::_select_layer));
editor->hide();
button = EditorNode::get_bottom_panel()->add_item(TTR("TileMap"), editor, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_tile_map_bottom_panel", TTR("Toggle TileMap Bottom Panel")));

View file

@ -126,8 +126,8 @@ class TileMapEditorPlugin : public EditorPlugin {
void _update_tile_map();
void _select_layer(const StringName &p_name);
void _edit_tile_map_layer(TileMapLayer *p_tile_map_layer);
void _edit_tile_map_layer_group(TileMapLayerGroup *p_tile_map_layer_group);
void _edit_tile_map_layer(TileMapLayer *p_tile_map_layer, bool p_show_layer_selector);
void _edit_tile_map(TileMap *p_tile_map);
protected:
void _notification(int p_notification);

View file

@ -99,15 +99,6 @@ Validate extension JSON: Error: Field 'classes/GLTFBufferView/methods/get_indice
Change AudioStreamPlayer* is_autoplay_enabled and GLTFBufferView getters to be const.
GH-87379
--------
Validate extension JSON: API was removed: classes/TileMap/methods/get_tileset
Validate extension JSON: API was removed: classes/TileMap/methods/set_tileset
Validate extension JSON: API was removed: classes/TileMap/properties/tile_set
Moved to the parent TileMapLayerGroup class. No change should be necessary.
GH-87340
--------
Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/RenderingDevice/methods/screen_get_framebuffer_format': arguments

View file

@ -32,7 +32,7 @@
#include "tile_map.compat.inc"
#include "core/core_string_names.h"
#include "scene/2d/tile_map_layer.h"
#include "core/io/marshalls.h"
#include "scene/gui/control.h"
#define TILEMAP_CALL_FOR_LAYER(layer, function, ...) \
@ -49,10 +49,118 @@
ERR_FAIL_INDEX_V(layer, (int)layers.size(), err_value); \
return layers[layer]->function(__VA_ARGS__);
void TileMap::_tile_set_changed() {
update_configuration_warnings();
}
void TileMap::_emit_changed() {
emit_signal(CoreStringNames::get_singleton()->changed);
}
void TileMap::_set_tile_map_data_using_compatibility_format(int p_layer, TileMapDataFormat p_format, const Vector<int> &p_data) {
ERR_FAIL_INDEX(p_layer, (int)layers.size());
ERR_FAIL_COND(p_format >= TileMapDataFormat::TILE_MAP_DATA_FORMAT_MAX);
#ifndef DISABLE_DEPRECATED
ERR_FAIL_COND_MSG(p_format != (TileMapDataFormat)(TILE_MAP_DATA_FORMAT_MAX - 1), "Old TileMap data format detected despite DISABLE_DEPRECATED being set compilation time.");
#endif // DISABLE_DEPRECATED
// Set data for a given tile from raw data.
int c = p_data.size();
const int *r = p_data.ptr();
int offset = (p_format >= TileMapDataFormat::TILE_MAP_DATA_FORMAT_2) ? 3 : 2;
ERR_FAIL_COND_MSG(c % offset != 0, vformat("Corrupted tile data. Got size: %d. Expected modulo: %d", c, offset));
layers[p_layer]->clear();
for (int i = 0; i < c; i += offset) {
const uint8_t *ptr = (const uint8_t *)&r[i];
uint8_t local[12];
for (int j = 0; j < ((p_format >= TileMapDataFormat::TILE_MAP_DATA_FORMAT_2) ? 12 : 8); j++) {
local[j] = ptr[j];
}
#ifdef BIG_ENDIAN_ENABLED
SWAP(local[0], local[3]);
SWAP(local[1], local[2]);
SWAP(local[4], local[7]);
SWAP(local[5], local[6]);
//TODO: ask someone to check this...
if (FORMAT >= FORMAT_2) {
SWAP(local[8], local[11]);
SWAP(local[9], local[10]);
}
#endif
// Extracts position in TileMap.
int16_t x = decode_uint16(&local[0]);
int16_t y = decode_uint16(&local[2]);
if (p_format == TileMapDataFormat::TILE_MAP_DATA_FORMAT_3) {
uint16_t source_id = decode_uint16(&local[4]);
uint16_t atlas_coords_x = decode_uint16(&local[6]);
uint16_t atlas_coords_y = decode_uint16(&local[8]);
uint16_t alternative_tile = decode_uint16(&local[10]);
layers[p_layer]->set_cell(Vector2i(x, y), source_id, Vector2i(atlas_coords_x, atlas_coords_y), alternative_tile);
} else {
#ifndef DISABLE_DEPRECATED
// Previous decated format.
uint32_t v = decode_uint32(&local[4]);
// Extract the transform flags that used to be in the tilemap.
bool flip_h = v & (1UL << 29);
bool flip_v = v & (1UL << 30);
bool transpose = v & (1UL << 31);
v &= (1UL << 29) - 1;
// Extract autotile/atlas coords.
int16_t coord_x = 0;
int16_t coord_y = 0;
if (p_format == TileMapDataFormat::TILE_MAP_DATA_FORMAT_2) {
coord_x = decode_uint16(&local[8]);
coord_y = decode_uint16(&local[10]);
}
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) {
layers[p_layer]->set_cell(Vector2i(x, y), a[0], a[1], a[2]);
} else {
ERR_PRINT(vformat("No valid tile in Tileset for: tile:%s coords:%s flip_h:%s flip_v:%s transpose:%s", v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose));
}
} else {
int compatibility_alternative_tile = ((int)flip_h) + ((int)flip_v << 1) + ((int)transpose << 2);
layers[p_layer]->set_cell(Vector2i(x, y), v, Vector2i(coord_x, coord_y), compatibility_alternative_tile);
}
#endif // DISABLE_DEPRECATED
}
}
}
Vector<int> TileMap::_get_tile_map_data_using_compatibility_format(int p_layer) const {
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), Vector<int>());
// Export tile data to raw format.
const HashMap<Vector2i, CellData> tile_map_layer_data = layers[p_layer]->get_tile_map_layer_data();
Vector<int> tile_data;
tile_data.resize(tile_map_layer_data.size() * 3);
int *w = tile_data.ptrw();
// Save in highest format.
int idx = 0;
for (const KeyValue<Vector2i, CellData> &E : tile_map_layer_data) {
uint8_t *ptr = (uint8_t *)&w[idx];
encode_uint16((int16_t)(E.key.x), &ptr[0]);
encode_uint16((int16_t)(E.key.y), &ptr[2]);
encode_uint16(E.value.cell.source_id, &ptr[4]);
encode_uint16(E.value.cell.coord_x, &ptr[6]);
encode_uint16(E.value.cell.coord_y, &ptr[8]);
encode_uint16(E.value.cell.alternative_tile, &ptr[10]);
idx += 3;
}
return tile_data;
}
void TileMap::_notification(int p_what) {
switch (p_what) {
case TileMap::NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
@ -199,6 +307,34 @@ void TileMap::draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<
}
}
void TileMap::set_tileset(const Ref<TileSet> &p_tileset) {
if (p_tileset == tile_set) {
return;
}
// Set the tileset, registering to its changes.
if (tile_set.is_valid()) {
tile_set->disconnect_changed(callable_mp(this, &TileMap::_tile_set_changed));
}
tile_set = p_tileset;
if (tile_set.is_valid()) {
tile_set->connect_changed(callable_mp(this, &TileMap::_tile_set_changed));
}
for (int i = 0; i < get_child_count(); i++) {
TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i));
if (layer) {
layer->set_tile_set(tile_set);
}
}
}
Ref<TileSet> TileMap::get_tileset() const {
return tile_set;
}
int TileMap::get_layers_count() const {
return layers.size();
}
@ -215,6 +351,7 @@ void TileMap::add_layer(int p_to_pos) {
layers.insert(p_to_pos, new_layer);
add_child(new_layer, false, INTERNAL_MODE_FRONT);
new_layer->set_name(vformat("Layer%d", p_to_pos));
new_layer->set_tile_set(tile_set);
move_child(new_layer, p_to_pos);
for (uint32_t i = 0; i < layers.size(); i++) {
layers[i]->set_as_tile_map_internal_node(i);
@ -251,8 +388,11 @@ 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();
TileMapLayer *removed = layers[p_layer];
layers.remove_at(p_layer);
remove_child(removed);
removed->queue_free();
for (uint32_t i = 0; i < layers.size(); i++) {
layers[i]->set_as_tile_map_internal_node(i);
}
@ -349,7 +489,7 @@ void TileMap::set_collision_visibility_mode(TileMap::VisibilityMode p_show_colli
}
collision_visibility_mode = p_show_collision;
for (TileMapLayer *layer : layers) {
layer->set_collision_visibility_mode(TileMapLayer::VisibilityMode(p_show_collision));
layer->set_collision_visibility_mode(TileMapLayer::DebugVisibilityMode(p_show_collision));
}
_emit_changed();
}
@ -364,7 +504,7 @@ void TileMap::set_navigation_visibility_mode(TileMap::VisibilityMode p_show_navi
}
navigation_visibility_mode = p_show_navigation;
for (TileMapLayer *layer : layers) {
layer->set_navigation_visibility_mode(TileMapLayer::VisibilityMode(p_show_navigation));
layer->set_navigation_visibility_mode(TileMapLayer::DebugVisibilityMode(p_show_navigation));
}
_emit_changed();
}
@ -394,19 +534,85 @@ void TileMap::erase_cell(int p_layer, const Vector2i &p_coords) {
}
int TileMap::get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSet::INVALID_SOURCE, get_cell_source_id, p_coords, p_use_proxies);
if (p_use_proxies && tile_set.is_valid()) {
if (p_layer < 0) {
p_layer = layers.size() + p_layer;
}
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSet::INVALID_SOURCE);
int source_id = layers[p_layer]->get_cell_source_id(p_coords);
Vector2i atlas_coords = layers[p_layer]->get_cell_atlas_coords(p_coords);
int alternative_id = layers[p_layer]->get_cell_alternative_tile(p_coords);
Array arr = tile_set->map_tile_proxy(source_id, atlas_coords, alternative_id);
ERR_FAIL_COND_V(arr.size() != 3, TileSet::INVALID_SOURCE);
return arr[0];
} else {
TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSet::INVALID_SOURCE, get_cell_source_id, p_coords);
}
}
Vector2i TileMap::get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSetSource::INVALID_ATLAS_COORDS, get_cell_atlas_coords, p_coords, p_use_proxies);
if (p_use_proxies && tile_set.is_valid()) {
if (p_layer < 0) {
p_layer = layers.size() + p_layer;
}
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSetAtlasSource::INVALID_ATLAS_COORDS);
int source_id = layers[p_layer]->get_cell_source_id(p_coords);
Vector2i atlas_coords = layers[p_layer]->get_cell_atlas_coords(p_coords);
int alternative_id = layers[p_layer]->get_cell_alternative_tile(p_coords);
Array arr = tile_set->map_tile_proxy(source_id, atlas_coords, alternative_id);
ERR_FAIL_COND_V(arr.size() != 3, TileSetSource::INVALID_ATLAS_COORDS);
return arr[1];
} else {
TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSetSource::INVALID_ATLAS_COORDS, get_cell_atlas_coords, p_coords);
}
}
int TileMap::get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSetSource::INVALID_TILE_ALTERNATIVE, get_cell_alternative_tile, p_coords, p_use_proxies);
if (p_use_proxies && tile_set.is_valid()) {
if (p_layer < 0) {
p_layer = layers.size() + p_layer;
}
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSetSource::INVALID_TILE_ALTERNATIVE);
int source_id = layers[p_layer]->get_cell_source_id(p_coords);
Vector2i atlas_coords = layers[p_layer]->get_cell_atlas_coords(p_coords);
int alternative_id = layers[p_layer]->get_cell_alternative_tile(p_coords);
Array arr = tile_set->map_tile_proxy(source_id, atlas_coords, alternative_id);
ERR_FAIL_COND_V(arr.size() != 3, TileSetSource::INVALID_TILE_ALTERNATIVE);
return arr[2];
} else {
TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSetSource::INVALID_TILE_ALTERNATIVE, get_cell_alternative_tile, p_coords);
}
}
TileData *TileMap::get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
TILEMAP_CALL_FOR_LAYER_V(p_layer, nullptr, get_cell_tile_data, p_coords, p_use_proxies);
if (p_use_proxies && tile_set.is_valid()) {
if (p_layer < 0) {
p_layer = layers.size() + p_layer;
}
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr);
int source_id = layers[p_layer]->get_cell_source_id(p_coords);
Vector2i atlas_coords = layers[p_layer]->get_cell_atlas_coords(p_coords);
int alternative_id = layers[p_layer]->get_cell_alternative_tile(p_coords);
Array arr = tile_set->map_tile_proxy(source_id, atlas_coords, alternative_id);
ERR_FAIL_COND_V(arr.size() != 3, nullptr);
Ref<TileSetAtlasSource> atlas_source = tile_set->get_source(arr[0]);
if (atlas_source.is_valid()) {
return atlas_source->get_tile_data(arr[1], arr[2]);
} else {
return nullptr;
}
} else {
TILEMAP_CALL_FOR_LAYER_V(p_layer, nullptr, get_cell_tile_data, p_coords);
}
}
Ref<TileMapPattern> TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array) {
@ -451,7 +657,10 @@ void TileMap::set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, i
}
TileMapCell TileMap::get_cell(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
TILEMAP_CALL_FOR_LAYER_V(p_layer, TileMapCell(), get_cell, p_coords, p_use_proxies);
if (p_use_proxies) {
WARN_DEPRECATED_MSG("use_proxies is deprecated.");
}
TILEMAP_CALL_FOR_LAYER_V(p_layer, TileMapCell(), get_cell, p_coords);
}
Vector2i TileMap::get_coords_for_body_rid(RID p_physics_body) {
@ -478,6 +687,13 @@ void TileMap::fix_invalid_tiles() {
}
}
#ifdef TOOLS_ENABLED
TileMapLayer *TileMap::duplicate_layer_from_internal(int p_layer) {
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr);
return Object::cast_to<TileMapLayer>(layers[p_layer]->duplicate(DUPLICATE_USE_INSTANTIATION | DUPLICATE_FROM_EDITOR));
}
#endif // TOOLS_ENABLED
void TileMap::clear_layer(int p_layer) {
TILEMAP_CALL_FOR_LAYER(p_layer, clear)
}
@ -540,10 +756,11 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
add_child(new_layer, false, INTERNAL_MODE_FRONT);
new_layer->set_as_tile_map_internal_node(0);
new_layer->set_name("Layer0");
new_layer->set_tile_set(tile_set);
new_layer->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileMap::_emit_changed));
layers.push_back(new_layer);
}
layers[0]->set_tile_data(format, p_value);
_set_tile_map_data_using_compatibility_format(0, format, p_value);
_emit_changed();
return true;
}
@ -565,6 +782,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
add_child(new_layer, false, INTERNAL_MODE_FRONT);
new_layer->set_as_tile_map_internal_node(index);
new_layer->set_name(vformat("Layer%d", index));
new_layer->set_tile_set(tile_set);
new_layer->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileMap::_emit_changed));
layers.push_back(new_layer);
}
@ -596,7 +814,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
set_layer_navigation_enabled(index, p_value);
return true;
} else if (components[1] == "tile_data") {
layers[index]->set_tile_data(format, p_value);
_set_tile_map_data_using_compatibility_format(index, format, p_value);
_emit_changed();
return true;
} else {
@ -609,7 +827,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
bool TileMap::_get(const StringName &p_name, Variant &r_ret) const {
Vector<String> components = String(p_name).split("/", true, 2);
if (p_name == "format") {
r_ret = TileMapDataFormat::FORMAT_MAX - 1; // When saving, always save highest format.
r_ret = TileMapDataFormat::TILE_MAP_DATA_FORMAT_MAX - 1; // When saving, always save highest format.
return true;
}
#ifndef DISABLE_DEPRECATED
@ -646,7 +864,7 @@ bool TileMap::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = is_layer_navigation_enabled(index);
return true;
} else if (components[1] == "tile_data") {
r_ret = layers[index]->get_tile_data();
r_ret = _get_tile_map_data_using_compatibility_format(index);
return true;
} else {
return false;
@ -899,6 +1117,9 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("force_update", "layer"), &TileMap::force_update, DEFVAL(-1));
#endif // DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_tileset", "tileset"), &TileMap::set_tileset);
ClassDB::bind_method(D_METHOD("get_tileset"), &TileMap::get_tileset);
ClassDB::bind_method(D_METHOD("set_rendering_quadrant_size", "size"), &TileMap::set_rendering_quadrant_size);
ClassDB::bind_method(D_METHOD("get_rendering_quadrant_size"), &TileMap::get_rendering_quadrant_size);
@ -969,6 +1190,7 @@ void TileMap::_bind_methods() {
GDVIRTUAL_BIND(_use_tile_data_runtime_update, "layer", "coords");
GDVIRTUAL_BIND(_tile_data_runtime_update, "layer", "coords", "tile_data");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_set", PROPERTY_HINT_RESOURCE_TYPE, "TileSet"), "set_tileset", "get_tileset");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rendering_quadrant_size", PROPERTY_HINT_RANGE, "1,128,1"), "set_rendering_quadrant_size", "get_rendering_quadrant_size");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_animatable"), "set_collision_animatable", "is_collision_animatable");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_visibility_mode", PROPERTY_HINT_ENUM, "Default,Force Show,Force Hide"), "set_collision_visibility_mode", "get_collision_visibility_mode");
@ -976,7 +1198,7 @@ void TileMap::_bind_methods() {
ADD_ARRAY("layers", "layer_");
ADD_PROPERTY_DEFAULT("format", TileMapDataFormat::FORMAT_1);
ADD_PROPERTY_DEFAULT("format", TileMapDataFormat::TILE_MAP_DATA_FORMAT_1);
ADD_SIGNAL(MethodInfo(CoreStringNames::get_singleton()->changed));
@ -990,6 +1212,7 @@ TileMap::TileMap() {
add_child(new_layer, false, INTERNAL_MODE_FRONT);
new_layer->set_as_tile_map_internal_node(0);
new_layer->set_name("Layer0");
new_layer->set_tile_set(tile_set);
new_layer->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileMap::_emit_changed));
layers.push_back(new_layer);
default_layer = memnew(TileMapLayer);

View file

@ -31,7 +31,7 @@
#ifndef TILE_MAP_H
#define TILE_MAP_H
#include "scene/2d/tile_map_layer_group.h"
#include "scene/2d/tile_map_layer.h"
#include "scene/resources/2d/tile_set.h"
class Control;
@ -39,14 +39,14 @@ class TileMapLayer;
class TerrainConstraint;
enum TileMapDataFormat {
FORMAT_1 = 0,
FORMAT_2,
FORMAT_3,
FORMAT_MAX,
TILE_MAP_DATA_FORMAT_1 = 0,
TILE_MAP_DATA_FORMAT_2,
TILE_MAP_DATA_FORMAT_3,
TILE_MAP_DATA_FORMAT_MAX,
};
class TileMap : public TileMapLayerGroup {
GDCLASS(TileMap, TileMapLayerGroup)
class TileMap : public Node2D {
GDCLASS(TileMap, Node2D)
public:
// Kept for compatibility, but should use TileMapLayer::VisibilityMode instead.
@ -60,11 +60,12 @@ private:
friend class TileSetPlugin;
// A compatibility enum to specify how is the data if formatted.
mutable TileMapDataFormat format = TileMapDataFormat::FORMAT_3;
mutable TileMapDataFormat format = TileMapDataFormat::TILE_MAP_DATA_FORMAT_3;
static constexpr float FP_ADJUST = 0.00001;
// Properties.
Ref<TileSet> tile_set;
int rendering_quadrant_size = 16;
bool collision_animatable = false;
VisibilityMode collision_visibility_mode = VISIBILITY_MODE_DEFAULT;
@ -78,8 +79,14 @@ private:
Transform2D last_valid_transform;
Transform2D new_transform;
void _tile_set_changed();
void _emit_changed();
// Kept for compatibility with TileMap. With TileMapLayers as individual nodes, the format is stored directly in the array.
void _set_tile_map_data_using_compatibility_format(int p_layer, TileMapDataFormat p_format, const Vector<int> &p_data);
Vector<int> _get_tile_map_data_using_compatibility_format(int p_layer) const;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@ -114,6 +121,10 @@ public:
static void draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame = -1, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0), const TileData *p_tile_data_override = nullptr, real_t p_normalized_animation_offset = 0.0);
// Accessors.
void set_tileset(const Ref<TileSet> &p_tileset);
Ref<TileSet> get_tileset() const;
// Layers management.
int get_layers_count() const;
void add_layer(int p_to_pos);
@ -200,6 +211,11 @@ public:
// Fixing and clearing methods.
void fix_invalid_tiles();
#ifdef TOOLS_ENABLED
// Moving layers outside of TileMap.
TileMapLayer *duplicate_layer_from_internal(int p_layer);
#endif // TOOLS_ENABLED
// Clears tiles from a given layer.
void clear_layer(int p_layer);
void clear();

File diff suppressed because it is too large Load diff

View file

@ -31,10 +31,15 @@
#ifndef TILE_MAP_LAYER_H
#define TILE_MAP_LAYER_H
#include "scene/2d/tile_map.h"
#include "scene/resources/2d/tile_set.h"
class TileSetAtlasSource;
class TileMap;
enum TileMapLayerDataFormat {
TILE_MAP_LAYER_DATA_FORMAT_0 = 0,
TILE_MAP_LAYER_DATA_FORMAT_MAX,
};
class TerrainConstraint {
private:
@ -218,14 +223,21 @@ class TileMapLayer : public Node2D {
GDCLASS(TileMapLayer, Node2D);
public:
enum VisibilityMode {
VISIBILITY_MODE_DEFAULT,
VISIBILITY_MODE_FORCE_SHOW,
VISIBILITY_MODE_FORCE_HIDE,
enum HighlightMode {
HIGHLIGHT_MODE_DEFAULT,
HIGHLIGHT_MODE_ABOVE,
HIGHLIGHT_MODE_BELOW,
};
enum DebugVisibilityMode {
DEBUG_VISIBILITY_MODE_DEFAULT,
DEBUG_VISIBILITY_MODE_FORCE_SHOW,
DEBUG_VISIBILITY_MODE_FORCE_HIDE,
};
enum DirtyFlags {
DIRTY_FLAGS_LAYER_ENABLED = 0,
DIRTY_FLAGS_LAYER_IN_TREE,
DIRTY_FLAGS_LAYER_IN_CANVAS,
DIRTY_FLAGS_LAYER_LOCAL_TRANSFORM,
@ -238,6 +250,7 @@ public:
DIRTY_FLAGS_LAYER_TEXTURE_FILTER,
DIRTY_FLAGS_LAYER_TEXTURE_REPEAT,
DIRTY_FLAGS_LAYER_RENDERING_QUADRANT_SIZE,
DIRTY_FLAGS_LAYER_COLLISION_ENABLED,
DIRTY_FLAGS_LAYER_USE_KINEMATIC_BODIES,
DIRTY_FLAGS_LAYER_COLLISION_VISIBILITY_MODE,
DIRTY_FLAGS_LAYER_NAVIGATION_ENABLED,
@ -249,26 +262,33 @@ public:
DIRTY_FLAGS_LAYER_GROUP_SELECTED_LAYERS,
DIRTY_FLAGS_LAYER_GROUP_HIGHLIGHT_SELECTED,
DIRTY_FLAGS_LAYER_GROUP_TILE_SET,
DIRTY_FLAGS_TILE_SET,
DIRTY_FLAGS_MAX,
};
private:
// Exposed properties.
// Properties.
HashMap<Vector2i, CellData> tile_map_layer_data;
bool enabled = true;
Ref<TileSet> tile_set;
HighlightMode highlight_mode = HIGHLIGHT_MODE_DEFAULT;
int y_sort_origin = 0;
int rendering_quadrant_size = 16;
bool collision_enabled = true;
bool use_kinematic_bodies = false;
VisibilityMode collision_visibility_mode = VISIBILITY_MODE_DEFAULT;
DebugVisibilityMode collision_visibility_mode = DEBUG_VISIBILITY_MODE_DEFAULT;
bool navigation_enabled = true;
RID navigation_map_override;
VisibilityMode navigation_visibility_mode = VISIBILITY_MODE_DEFAULT;
DebugVisibilityMode navigation_visibility_mode = DEBUG_VISIBILITY_MODE_DEFAULT;
// Internal.
HashMap<Vector2i, CellData> tile_map;
bool pending_update = false;
// For keeping compatibility with TileMap.
@ -348,6 +368,8 @@ 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 _tile_set_changed();
void _renamed();
void _update_notify_local_transform();
@ -358,11 +380,21 @@ private:
protected:
void _notification(int p_what);
static void _bind_methods();
virtual void _update_self_texture_filter(RS::CanvasItemTextureFilter p_texture_filter) override;
virtual void _update_self_texture_repeat(RS::CanvasItemTextureRepeat p_texture_repeat) override;
public:
// TileMap node.
void set_as_tile_map_internal_node(int p_index);
int get_index_in_tile_map() const {
return layer_index_in_tile_map_node;
}
const HashMap<Vector2i, CellData> &get_tile_map_layer_data() const {
return tile_map_layer_data;
}
// Rect caching.
Rect2 get_rect(bool &r_changed) const;
@ -374,27 +406,26 @@ public:
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true) const; // Not exposed.
// Not exposed to users.
TileMapCell get_cell(const Vector2i &p_coords, bool p_use_proxies = false) const;
TileMapCell get_cell(const Vector2i &p_coords) const;
// For TileMap node's use.
void set_tile_data(TileMapDataFormat p_format, const Vector<int> &p_data);
Vector<int> get_tile_data() const;
void notify_tile_map_layer_group_change(DirtyFlags p_what);
////////////// Exposed functions //////////////
void update_internals();
void notify_runtime_tile_data_update();
// --- Exposed in TileMap ---
// Cells manipulation.
void set_cell(const Vector2i &p_coords, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0);
// --- Cells manipulation ---
// Generic cells manipulations and data access.
void set_cell(const Vector2i &p_coords, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i &p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0);
void erase_cell(const Vector2i &p_coords);
int get_cell_source_id(const Vector2i &p_coords, bool p_use_proxies = false) const;
Vector2i get_cell_atlas_coords(const Vector2i &p_coords, bool p_use_proxies = false) const;
int get_cell_alternative_tile(const Vector2i &p_coords, bool p_use_proxies = false) const;
TileData *get_cell_tile_data(const Vector2i &p_coords, bool p_use_proxies = false) const; // Helper method to make accessing the data easier.
void fix_invalid_tiles();
void clear();
int get_cell_source_id(const Vector2i &p_coords) const;
Vector2i get_cell_atlas_coords(const Vector2i &p_coords) const;
int get_cell_alternative_tile(const Vector2i &p_coords) const;
TileData *get_cell_tile_data(const Vector2i &p_coords) const; // Helper method to make accessing the data easier.
TypedArray<Vector2i> get_used_cells() const;
TypedArray<Vector2i> get_used_cells_by_id(int p_source_id = TileSet::INVALID_SOURCE, const Vector2i &p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) const;
Rect2i get_used_rect() const;
// Patterns.
Ref<TileMapPattern> get_pattern(TypedArray<Vector2i> p_coords_array);
void set_pattern(const Vector2i &p_position, const Ref<TileMapPattern> p_pattern);
@ -403,54 +434,62 @@ public:
void set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true);
void set_cells_terrain_path(TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true);
// Cells usage.
TypedArray<Vector2i> get_used_cells() const;
TypedArray<Vector2i> get_used_cells_by_id(int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) const;
Rect2i get_used_rect() const;
// --- Physics helpers ---
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.
// --- Runtime ---
void update_internals();
void notify_runtime_tile_data_update();
GDVIRTUAL1R(bool, _use_tile_data_runtime_update, Vector2i);
GDVIRTUAL2(_tile_data_runtime_update, Vector2i, TileData *);
// --- Shortcuts to methods defined in TileSet ---
Vector2i map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern);
TypedArray<Vector2i> get_surrounding_cells(const Vector2i &p_coords);
Vector2i get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const;
Vector2 map_to_local(const Vector2i &p_pos) const;
Vector2i local_to_map(const Vector2 &p_pos) const;
// --- Accessors ---
void set_tile_map_data_from_array(const Vector<uint8_t> &p_data);
Vector<uint8_t> get_tile_map_data_as_array() const;
// Layer properties.
void set_enabled(bool p_enabled);
bool is_enabled() const;
void set_tile_set(const Ref<TileSet> &p_tile_set);
Ref<TileSet> get_tile_set() const;
void set_highlight_mode(HighlightMode p_highlight_mode);
HighlightMode get_highlight_mode() 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;
virtual void set_z_index(int p_z_index) override;
virtual void set_light_mask(int p_light_mask) override;
virtual void set_texture_filter(CanvasItem::TextureFilter p_texture_filter) override;
virtual void set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) override;
void set_rendering_quadrant_size(int p_size);
int get_rendering_quadrant_size() const;
void set_collision_enabled(bool p_enabled);
bool is_collision_enabled() const;
void set_use_kinematic_bodies(bool p_use_kinematic_bodies);
bool is_using_kinematic_bodies() const;
void set_collision_visibility_mode(VisibilityMode p_show_collision);
VisibilityMode get_collision_visibility_mode() const;
void set_collision_visibility_mode(DebugVisibilityMode p_show_collision);
DebugVisibilityMode get_collision_visibility_mode() const;
void set_navigation_enabled(bool p_enabled);
bool is_navigation_enabled() const;
void set_navigation_map(RID p_map);
RID get_navigation_map() const;
void set_navigation_visibility_mode(VisibilityMode p_show_navigation);
VisibilityMode get_navigation_visibility_mode() const;
// Fixing and clearing methods.
void fix_invalid_tiles();
// Find coords for body.
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.
// Helper.
Ref<TileSet> get_effective_tile_set() const;
// Virtual function to modify the TileData at runtime.
GDVIRTUAL1R(bool, _use_tile_data_runtime_update, Vector2i);
GDVIRTUAL2(_tile_data_runtime_update, Vector2i, TileData *);
// ---
void set_navigation_visibility_mode(DebugVisibilityMode p_show_navigation);
DebugVisibilityMode get_navigation_visibility_mode() const;
TileMapLayer();
~TileMapLayer();
};
VARIANT_ENUM_CAST(TileMapLayer::DebugVisibilityMode);
#endif // TILE_MAP_LAYER_H

View file

@ -1,148 +0,0 @@
/**************************************************************************/
/* tile_map_layer_group.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "tile_map_layer_group.h"
#include "core/core_string_names.h"
#include "scene/2d/tile_map_layer.h"
#include "scene/resources/2d/tile_set.h"
#ifdef TOOLS_ENABLED
void TileMapLayerGroup::_cleanup_selected_layers() {
for (int i = 0; i < selected_layers.size(); i++) {
const String name = selected_layers[i];
TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_node_or_null(name));
if (!layer) {
selected_layers.remove_at(i);
i--;
}
}
}
#endif // TOOLS_ENABLED
void TileMapLayerGroup::_tile_set_changed() {
for (int i = 0; i < get_child_count(); i++) {
TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i));
if (layer) {
layer->notify_tile_map_layer_group_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_TILE_SET);
}
}
update_configuration_warnings();
}
#ifdef TOOLS_ENABLED
void TileMapLayerGroup::set_selected_layers(Vector<StringName> p_layer_names) {
selected_layers = p_layer_names;
_cleanup_selected_layers();
// Update the layers modulation.
for (int i = 0; i < get_child_count(); i++) {
TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i));
if (layer) {
layer->notify_tile_map_layer_group_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_SELECTED_LAYERS);
}
}
}
Vector<StringName> TileMapLayerGroup::get_selected_layers() const {
return selected_layers;
}
void TileMapLayerGroup::set_highlight_selected_layer(bool p_highlight_selected_layer) {
if (highlight_selected_layer == p_highlight_selected_layer) {
return;
}
highlight_selected_layer = p_highlight_selected_layer;
for (int i = 0; i < get_child_count(); i++) {
TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i));
if (layer) {
layer->notify_tile_map_layer_group_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_HIGHLIGHT_SELECTED);
}
}
}
bool TileMapLayerGroup::is_highlighting_selected_layer() const {
return highlight_selected_layer;
}
#endif // TOOLS_ENABLED
void TileMapLayerGroup::remove_child_notify(Node *p_child) {
#ifdef TOOLS_ENABLED
_cleanup_selected_layers();
#endif // TOOLS_ENABLED
}
void TileMapLayerGroup::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_tileset", "tileset"), &TileMapLayerGroup::set_tileset);
ClassDB::bind_method(D_METHOD("get_tileset"), &TileMapLayerGroup::get_tileset);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_set", PROPERTY_HINT_RESOURCE_TYPE, "TileSet"), "set_tileset", "get_tileset");
}
void TileMapLayerGroup::set_tileset(const Ref<TileSet> &p_tileset) {
if (p_tileset == tile_set) {
return;
}
// Set the tileset, registering to its changes.
if (tile_set.is_valid()) {
tile_set->disconnect_changed(callable_mp(this, &TileMapLayerGroup::_tile_set_changed));
}
tile_set = p_tileset;
if (tile_set.is_valid()) {
tile_set->connect_changed(callable_mp(this, &TileMapLayerGroup::_tile_set_changed));
}
for (int i = 0; i < get_child_count(); i++) {
TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i));
if (layer) {
layer->notify_tile_map_layer_group_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_TILE_SET);
}
}
}
Ref<TileSet> TileMapLayerGroup::get_tileset() const {
return tile_set;
}
TileMapLayerGroup::~TileMapLayerGroup() {
if (tile_set.is_valid()) {
tile_set->disconnect_changed(callable_mp(this, &TileMapLayerGroup::_tile_set_changed));
}
}

View file

@ -1,73 +0,0 @@
/**************************************************************************/
/* tile_map_layer_group.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef TILE_MAP_LAYER_GROUP_H
#define TILE_MAP_LAYER_GROUP_H
#include "scene/2d/node_2d.h"
class TileSet;
class TileMapLayerGroup : public Node2D {
GDCLASS(TileMapLayerGroup, Node2D);
private:
mutable Vector<StringName> selected_layers;
bool highlight_selected_layer = true;
#ifdef TOOLS_ENABLED
void _cleanup_selected_layers();
#endif
void _tile_set_changed();
protected:
Ref<TileSet> tile_set;
virtual void remove_child_notify(Node *p_child) override;
static void _bind_methods();
public:
#ifdef TOOLS_ENABLED
// For editor use.
void set_selected_layers(Vector<StringName> p_layer_names);
Vector<StringName> get_selected_layers() const;
void set_highlight_selected_layer(bool p_highlight_selected_layer);
bool is_highlighting_selected_layer() const;
#endif
// Accessors.
void set_tileset(const Ref<TileSet> &p_tileset);
Ref<TileSet> get_tileset() const;
~TileMapLayerGroup();
};
#endif // TILE_MAP_LAYER_GROUP_H

View file

@ -1401,14 +1401,17 @@ void CanvasItem::_refresh_texture_filter_cache() const {
}
}
void CanvasItem::_update_self_texture_filter(RS::CanvasItemTextureFilter p_texture_filter) {
RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), p_texture_filter);
queue_redraw();
}
void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
if (!is_inside_tree()) {
return;
}
_refresh_texture_filter_cache();
RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache);
queue_redraw();
_update_self_texture_filter(texture_filter_cache);
if (p_propagate) {
for (CanvasItem *E : children_items) {
@ -1452,14 +1455,18 @@ void CanvasItem::_refresh_texture_repeat_cache() const {
}
}
void CanvasItem::_update_self_texture_repeat(RS::CanvasItemTextureRepeat p_texture_repeat) {
RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), p_texture_repeat);
queue_redraw();
}
void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
if (!is_inside_tree()) {
return;
}
_refresh_texture_repeat_cache();
_update_self_texture_repeat(texture_repeat_cache);
RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache);
queue_redraw();
if (p_propagate) {
for (CanvasItem *E : children_items) {
if (!E->top_level && E->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {

View file

@ -152,6 +152,9 @@ private:
void _notify_transform_deferred();
protected:
virtual void _update_self_texture_repeat(RS::CanvasItemTextureRepeat p_texture_repeat);
virtual void _update_self_texture_filter(RS::CanvasItemTextureFilter p_texture_filter);
_FORCE_INLINE_ void _notify_transform() {
_notify_transform(this);
if (is_inside_tree() && !block_transform_notify && notify_local_transform) {

View file

@ -77,6 +77,7 @@
#include "scene/2d/skeleton_2d.h"
#include "scene/2d/sprite_2d.h"
#include "scene/2d/tile_map.h"
#include "scene/2d/tile_map_layer.h"
#include "scene/2d/touch_screen_button.h"
#include "scene/2d/visible_on_screen_notifier_2d.h"
#include "scene/animation/animation_blend_space_1d.h"
@ -813,7 +814,7 @@ void register_scene_types() {
GDREGISTER_CLASS(TileMapPattern);
GDREGISTER_CLASS(TileData);
GDREGISTER_CLASS(TileMap);
GDREGISTER_ABSTRACT_CLASS(TileMapLayerGroup);
GDREGISTER_CLASS(TileMapLayer);
GDREGISTER_CLASS(Parallax2D);
GDREGISTER_CLASS(ParallaxBackground);
GDREGISTER_CLASS(ParallaxLayer);