|
|
|
|
@ -40,10 +40,6 @@
|
|
|
|
|
#include "servers/navigation_server_3d.h"
|
|
|
|
|
#endif // DEBUG_ENABLED
|
|
|
|
|
|
|
|
|
|
TileMap *TileMapLayer::_fetch_tilemap() const {
|
|
|
|
|
return TileMap::cast_to<TileMap>(get_parent());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_ENABLED
|
|
|
|
|
/////////////////////////////// Debug //////////////////////////////////////////
|
|
|
|
|
constexpr int TILE_MAP_DEBUG_QUADRANT_SIZE = 16;
|
|
|
|
|
@ -183,7 +179,6 @@ void TileMapLayer::_debug_quadrants_update_cell(CellData &r_cell_data, SelfList<
|
|
|
|
|
|
|
|
|
|
/////////////////////////////// Rendering //////////////////////////////////////
|
|
|
|
|
void TileMapLayer::_rendering_update() {
|
|
|
|
|
const TileMap *tile_map_node = _fetch_tilemap();
|
|
|
|
|
const Ref<TileSet> &tile_set = get_effective_tile_set();
|
|
|
|
|
RenderingServer *rs = RenderingServer::get_singleton();
|
|
|
|
|
|
|
|
|
|
@ -192,24 +187,23 @@ void TileMapLayer::_rendering_update() {
|
|
|
|
|
|
|
|
|
|
// ----------- Layer level processing -----------
|
|
|
|
|
if (!forced_cleanup) {
|
|
|
|
|
// Update the layer's CanvasItem.
|
|
|
|
|
set_use_parent_material(true);
|
|
|
|
|
set_light_mask(tile_map_node->get_light_mask());
|
|
|
|
|
|
|
|
|
|
// Modulate the layer.
|
|
|
|
|
Color layer_modulate = get_modulate();
|
|
|
|
|
#ifdef TOOLS_ENABLED
|
|
|
|
|
const Vector<StringName> selected_layers = tile_map_node->get_selected_layers();
|
|
|
|
|
if (tile_map_node->is_highlighting_selected_layer() && selected_layers.size() == 1 && get_name() != selected_layers[0]) {
|
|
|
|
|
TileMapLayer *selected_layer = Object::cast_to<TileMapLayer>(tile_map_node->get_node_or_null(String(selected_layers[0])));
|
|
|
|
|
if (selected_layer) {
|
|
|
|
|
int z_selected = selected_layer->get_z_index();
|
|
|
|
|
int layer_z_index = get_z_index();
|
|
|
|
|
if (layer_z_index < z_selected || (layer_z_index == z_selected && get_index() < selected_layer->get_index())) {
|
|
|
|
|
layer_modulate = layer_modulate.darkened(0.5);
|
|
|
|
|
} else if (layer_z_index > z_selected || (layer_z_index == z_selected && get_index() > selected_layer->get_index())) {
|
|
|
|
|
layer_modulate = layer_modulate.darkened(0.5);
|
|
|
|
|
layer_modulate.a *= 0.3;
|
|
|
|
|
const TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(get_parent());
|
|
|
|
|
if (tile_map_layer_group) {
|
|
|
|
|
const Vector<StringName> selected_layers = tile_map_layer_group->get_selected_layers();
|
|
|
|
|
if (tile_map_layer_group->is_highlighting_selected_layer() && selected_layers.size() == 1 && get_name() != selected_layers[0]) {
|
|
|
|
|
TileMapLayer *selected_layer = Object::cast_to<TileMapLayer>(tile_map_layer_group->get_node_or_null(String(selected_layers[0])));
|
|
|
|
|
if (selected_layer) {
|
|
|
|
|
int z_selected = selected_layer->get_z_index();
|
|
|
|
|
int layer_z_index = get_z_index();
|
|
|
|
|
if (layer_z_index < z_selected || (layer_z_index == z_selected && get_index() < selected_layer->get_index())) {
|
|
|
|
|
layer_modulate = layer_modulate.darkened(0.5);
|
|
|
|
|
} else if (layer_z_index > z_selected || (layer_z_index == z_selected && get_index() > selected_layer->get_index())) {
|
|
|
|
|
layer_modulate = layer_modulate.darkened(0.5);
|
|
|
|
|
layer_modulate.a *= 0.3;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -224,8 +218,8 @@ void TileMapLayer::_rendering_update() {
|
|
|
|
|
|
|
|
|
|
// Check if anything changed that might change the quadrant shape.
|
|
|
|
|
// If so, recreate everything.
|
|
|
|
|
bool quandrant_shape_changed = dirty.flags[DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE] ||
|
|
|
|
|
(is_y_sort_enabled() && (dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] || dirty.flags[DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_LOCAL_TRANSFORM] || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET]));
|
|
|
|
|
bool quandrant_shape_changed = dirty.flags[DIRTY_FLAGS_LAYER_RENDERING_QUADRANT_SIZE] ||
|
|
|
|
|
(is_y_sort_enabled() && (dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] || dirty.flags[DIRTY_FLAGS_LAYER_LOCAL_TRANSFORM] || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET]));
|
|
|
|
|
|
|
|
|
|
// Free all quadrants.
|
|
|
|
|
if (forced_cleanup || quandrant_shape_changed) {
|
|
|
|
|
@ -330,7 +324,7 @@ void TileMapLayer::_rendering_update() {
|
|
|
|
|
Transform2D xform(0, rendering_quadrant->canvas_items_position);
|
|
|
|
|
rs->canvas_item_set_transform(ci, xform);
|
|
|
|
|
|
|
|
|
|
rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask());
|
|
|
|
|
rs->canvas_item_set_light_mask(ci, get_light_mask());
|
|
|
|
|
rs->canvas_item_set_z_as_relative_to_parent(ci, true);
|
|
|
|
|
rs->canvas_item_set_z_index(ci, tile_z_index);
|
|
|
|
|
|
|
|
|
|
@ -398,17 +392,15 @@ void TileMapLayer::_rendering_update() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Updates on TileMap changes.
|
|
|
|
|
if (dirty.flags[DIRTY_FLAGS_TILE_MAP_LIGHT_MASK] ||
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_TILE_MAP_USE_PARENT_MATERIAL] ||
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_TILE_MAP_MATERIAL] ||
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_TILE_MAP_TEXTURE_FILTER] ||
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT] ||
|
|
|
|
|
// Updates on rendering changes.
|
|
|
|
|
if (dirty.flags[DIRTY_FLAGS_LAYER_LIGHT_MASK] ||
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_LAYER_TEXTURE_FILTER] ||
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_LAYER_TEXTURE_REPEAT] ||
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_LAYER_SELF_MODULATE]) {
|
|
|
|
|
for (KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) {
|
|
|
|
|
Ref<RenderingQuadrant> &rendering_quadrant = kv.value;
|
|
|
|
|
for (const RID &ci : rendering_quadrant->canvas_items) {
|
|
|
|
|
rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask());
|
|
|
|
|
rs->canvas_item_set_light_mask(ci, get_light_mask());
|
|
|
|
|
rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree()));
|
|
|
|
|
rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree()));
|
|
|
|
|
rs->canvas_item_set_self_modulate(ci, get_self_modulate());
|
|
|
|
|
@ -465,7 +457,6 @@ void TileMapLayer::_rendering_notification(int p_what) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::_rendering_quadrants_update_cell(CellData &r_cell_data, SelfList<RenderingQuadrant>::List &r_dirty_rendering_quadrant_list) {
|
|
|
|
|
const TileMap *tile_map_node = _fetch_tilemap();
|
|
|
|
|
const Ref<TileSet> &tile_set = get_effective_tile_set();
|
|
|
|
|
|
|
|
|
|
// Check if the cell is valid and retrieve its y_sort_origin.
|
|
|
|
|
@ -495,14 +486,13 @@ void TileMapLayer::_rendering_quadrants_update_cell(CellData &r_cell_data, SelfL
|
|
|
|
|
canvas_items_position = Vector2(0, tile_set->map_to_local(r_cell_data.coords).y + tile_y_sort_origin + y_sort_origin);
|
|
|
|
|
quadrant_coords = canvas_items_position * 100;
|
|
|
|
|
} else {
|
|
|
|
|
int quad_size = tile_map_node->get_rendering_quadrant_size();
|
|
|
|
|
const Vector2i &coords = r_cell_data.coords;
|
|
|
|
|
|
|
|
|
|
// Rounding down, instead of simply rounding towards zero (truncating).
|
|
|
|
|
quadrant_coords = Vector2i(
|
|
|
|
|
coords.x > 0 ? coords.x / quad_size : (coords.x - (quad_size - 1)) / quad_size,
|
|
|
|
|
coords.y > 0 ? coords.y / quad_size : (coords.y - (quad_size - 1)) / quad_size);
|
|
|
|
|
canvas_items_position = tile_set->map_to_local(quad_size * quadrant_coords);
|
|
|
|
|
coords.x > 0 ? coords.x / rendering_quadrant_size : (coords.x - (rendering_quadrant_size - 1)) / rendering_quadrant_size,
|
|
|
|
|
coords.y > 0 ? coords.y / rendering_quadrant_size : (coords.y - (rendering_quadrant_size - 1)) / rendering_quadrant_size);
|
|
|
|
|
canvas_items_position = tile_set->map_to_local(rendering_quadrant_size * quadrant_coords);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ref<RenderingQuadrant> rendering_quadrant;
|
|
|
|
|
@ -767,7 +757,6 @@ void TileMapLayer::_physics_clear_cell(CellData &r_cell_data) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::_physics_update_cell(CellData &r_cell_data) {
|
|
|
|
|
const TileMap *tile_map_node = _fetch_tilemap();
|
|
|
|
|
const Ref<TileSet> &tile_set = get_effective_tile_set();
|
|
|
|
|
Transform2D gl_transform = get_global_transform();
|
|
|
|
|
RID space = get_world_2d()->get_space();
|
|
|
|
|
@ -825,7 +814,7 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) {
|
|
|
|
|
body = ps->body_create();
|
|
|
|
|
}
|
|
|
|
|
bodies_coords[body] = r_cell_data.coords;
|
|
|
|
|
ps->body_set_mode(body, tile_map_node->is_collision_animatable() ? PhysicsServer2D::BODY_MODE_KINEMATIC : PhysicsServer2D::BODY_MODE_STATIC);
|
|
|
|
|
ps->body_set_mode(body, use_kinematic_bodies ? PhysicsServer2D::BODY_MODE_KINEMATIC : PhysicsServer2D::BODY_MODE_STATIC);
|
|
|
|
|
ps->body_set_space(body, space);
|
|
|
|
|
|
|
|
|
|
Transform2D xform;
|
|
|
|
|
@ -833,7 +822,7 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) {
|
|
|
|
|
xform = gl_transform * xform;
|
|
|
|
|
ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
|
|
|
|
|
|
|
|
|
|
ps->body_attach_object_instance_id(body, tile_map_node->get_instance_id());
|
|
|
|
|
ps->body_attach_object_instance_id(body, tile_map_node ? tile_map_node->get_instance_id() : get_instance_id());
|
|
|
|
|
ps->body_set_collision_layer(body, physics_layer);
|
|
|
|
|
ps->body_set_collision_mask(body, physics_mask);
|
|
|
|
|
ps->body_set_pickable(body, false);
|
|
|
|
|
@ -885,7 +874,6 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) {
|
|
|
|
|
#ifdef DEBUG_ENABLED
|
|
|
|
|
void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data) {
|
|
|
|
|
// Draw the debug collision shapes.
|
|
|
|
|
TileMap *tile_map_node = _fetch_tilemap();
|
|
|
|
|
const Ref<TileSet> &tile_set = get_effective_tile_set();
|
|
|
|
|
ERR_FAIL_COND(!tile_set.is_valid());
|
|
|
|
|
|
|
|
|
|
@ -894,14 +882,14 @@ void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vect
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool show_collision = false;
|
|
|
|
|
switch (tile_map_node->get_collision_visibility_mode()) {
|
|
|
|
|
case TileMap::VISIBILITY_MODE_DEFAULT:
|
|
|
|
|
switch (collision_visibility_mode) {
|
|
|
|
|
case TileMapLayer::VISIBILITY_MODE_DEFAULT:
|
|
|
|
|
show_collision = !Engine::get_singleton()->is_editor_hint() && get_tree()->is_debugging_collisions_hint();
|
|
|
|
|
break;
|
|
|
|
|
case TileMap::VISIBILITY_MODE_FORCE_HIDE:
|
|
|
|
|
case TileMapLayer::VISIBILITY_MODE_FORCE_HIDE:
|
|
|
|
|
show_collision = false;
|
|
|
|
|
break;
|
|
|
|
|
case TileMap::VISIBILITY_MODE_FORCE_SHOW:
|
|
|
|
|
case TileMapLayer::VISIBILITY_MODE_FORCE_SHOW:
|
|
|
|
|
show_collision = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@ -942,32 +930,32 @@ void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vect
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::_navigation_update() {
|
|
|
|
|
ERR_FAIL_NULL(NavigationServer2D::get_singleton());
|
|
|
|
|
const Ref<TileSet> &tile_set = get_effective_tile_set();
|
|
|
|
|
NavigationServer2D *ns = NavigationServer2D::get_singleton();
|
|
|
|
|
const Ref<TileSet> &tile_set = get_effective_tile_set();
|
|
|
|
|
|
|
|
|
|
// Check if we should cleanup everything.
|
|
|
|
|
bool forced_cleanup = in_destructor || !enabled || !navigation_enabled || !is_inside_tree() || !tile_set.is_valid();
|
|
|
|
|
|
|
|
|
|
// ----------- Layer level processing -----------
|
|
|
|
|
if (forced_cleanup) {
|
|
|
|
|
if (navigation_map.is_valid() && !uses_world_navigation_map) {
|
|
|
|
|
ns->free(navigation_map);
|
|
|
|
|
navigation_map = RID();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Update navigation maps.
|
|
|
|
|
if (!navigation_map.is_valid()) {
|
|
|
|
|
if (layer_index_in_tile_map_node == 0) {
|
|
|
|
|
// Use the default World2D navigation map for the first layer when empty.
|
|
|
|
|
navigation_map = get_world_2d()->get_navigation_map();
|
|
|
|
|
uses_world_navigation_map = true;
|
|
|
|
|
} else {
|
|
|
|
|
RID new_layer_map = ns->map_create();
|
|
|
|
|
// Set the default NavigationPolygon cell_size on the new map as a mismatch causes an error.
|
|
|
|
|
ns->map_set_cell_size(new_layer_map, 1.0);
|
|
|
|
|
ns->map_set_active(new_layer_map, true);
|
|
|
|
|
navigation_map = new_layer_map;
|
|
|
|
|
uses_world_navigation_map = false;
|
|
|
|
|
// All this processing is kept for compatibility with the TileMap node.
|
|
|
|
|
// Otherwise, layers shall use the World2D navigation map or define a custom one with set_navigation_map(...).
|
|
|
|
|
if (tile_map_node) {
|
|
|
|
|
if (forced_cleanup) {
|
|
|
|
|
if (navigation_map_override.is_valid()) {
|
|
|
|
|
ns->free(navigation_map_override);
|
|
|
|
|
navigation_map_override = RID();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Update navigation maps.
|
|
|
|
|
if (!navigation_map_override.is_valid()) {
|
|
|
|
|
if (layer_index_in_tile_map_node > 0) {
|
|
|
|
|
// Create a dedicated map for each layer.
|
|
|
|
|
RID new_layer_map = ns->map_create();
|
|
|
|
|
// Set the default NavigationPolygon cell_size on the new map as a mismatch causes an error.
|
|
|
|
|
ns->map_set_cell_size(new_layer_map, 1.0);
|
|
|
|
|
ns->map_set_active(new_layer_map, true);
|
|
|
|
|
navigation_map_override = new_layer_map;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -979,7 +967,7 @@ void TileMapLayer::_navigation_update() {
|
|
|
|
|
_navigation_clear_cell(kv.value);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (_navigation_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) {
|
|
|
|
|
if (_navigation_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE] || dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_MAP]) {
|
|
|
|
|
// Update all cells.
|
|
|
|
|
for (KeyValue<Vector2i, CellData> &kv : tile_map) {
|
|
|
|
|
_navigation_update_cell(kv.value);
|
|
|
|
|
@ -1033,10 +1021,11 @@ void TileMapLayer::_navigation_clear_cell(CellData &r_cell_data) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) {
|
|
|
|
|
const TileMap *tile_map_node = _fetch_tilemap();
|
|
|
|
|
const Ref<TileSet> &tile_set = get_effective_tile_set();
|
|
|
|
|
NavigationServer2D *ns = NavigationServer2D::get_singleton();
|
|
|
|
|
Transform2D gl_xform = get_global_transform();
|
|
|
|
|
RID navigation_map = navigation_map_override.is_valid() ? navigation_map_override : get_world_2d()->get_navigation_map();
|
|
|
|
|
ERR_FAIL_COND(navigation_map.is_null());
|
|
|
|
|
|
|
|
|
|
// Get the navigation polygons and create regions.
|
|
|
|
|
TileMapCell &c = r_cell_data.cell;
|
|
|
|
|
@ -1084,7 +1073,7 @@ void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) {
|
|
|
|
|
if (!region.is_valid()) {
|
|
|
|
|
region = ns->region_create();
|
|
|
|
|
}
|
|
|
|
|
ns->region_set_owner_id(region, tile_map_node->get_instance_id());
|
|
|
|
|
ns->region_set_owner_id(region, tile_map_node ? tile_map_node->get_instance_id() : get_instance_id());
|
|
|
|
|
ns->region_set_map(region, navigation_map);
|
|
|
|
|
ns->region_set_transform(region, gl_xform * tile_transform);
|
|
|
|
|
ns->region_set_navigation_layers(region, tile_set->get_navigation_layer_layers(navigation_layer_index));
|
|
|
|
|
@ -1111,16 +1100,15 @@ void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) {
|
|
|
|
|
#ifdef DEBUG_ENABLED
|
|
|
|
|
void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data) {
|
|
|
|
|
// Draw the debug collision shapes.
|
|
|
|
|
const TileMap *tile_map_node = _fetch_tilemap();
|
|
|
|
|
bool show_navigation = false;
|
|
|
|
|
switch (tile_map_node->get_navigation_visibility_mode()) {
|
|
|
|
|
case TileMap::VISIBILITY_MODE_DEFAULT:
|
|
|
|
|
switch (navigation_visibility_mode) {
|
|
|
|
|
case TileMapLayer::VISIBILITY_MODE_DEFAULT:
|
|
|
|
|
show_navigation = !Engine::get_singleton()->is_editor_hint() && get_tree()->is_debugging_navigation_hint();
|
|
|
|
|
break;
|
|
|
|
|
case TileMap::VISIBILITY_MODE_FORCE_HIDE:
|
|
|
|
|
case TileMapLayer::VISIBILITY_MODE_FORCE_HIDE:
|
|
|
|
|
show_navigation = false;
|
|
|
|
|
break;
|
|
|
|
|
case TileMap::VISIBILITY_MODE_FORCE_SHOW:
|
|
|
|
|
case TileMapLayer::VISIBILITY_MODE_FORCE_SHOW:
|
|
|
|
|
show_navigation = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@ -1250,13 +1238,14 @@ void TileMapLayer::_scenes_update() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::_scenes_clear_cell(CellData &r_cell_data) {
|
|
|
|
|
const TileMap *tile_map_node = _fetch_tilemap();
|
|
|
|
|
if (!tile_map_node) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cleanup existing scene.
|
|
|
|
|
Node *node = tile_map_node->get_node_or_null(r_cell_data.scene);
|
|
|
|
|
Node *node = nullptr;
|
|
|
|
|
if (tile_map_node) {
|
|
|
|
|
// Compatibility with TileMap.
|
|
|
|
|
node = tile_map_node->get_node_or_null(r_cell_data.scene);
|
|
|
|
|
} else {
|
|
|
|
|
node = get_node_or_null(r_cell_data.scene);
|
|
|
|
|
}
|
|
|
|
|
if (node) {
|
|
|
|
|
node->queue_free();
|
|
|
|
|
}
|
|
|
|
|
@ -1264,7 +1253,6 @@ void TileMapLayer::_scenes_clear_cell(CellData &r_cell_data) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) {
|
|
|
|
|
TileMap *tile_map_node = _fetch_tilemap();
|
|
|
|
|
const Ref<TileSet> &tile_set = get_effective_tile_set();
|
|
|
|
|
|
|
|
|
|
// Clear the scene in any case.
|
|
|
|
|
@ -1292,7 +1280,12 @@ void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) {
|
|
|
|
|
xform.set_origin(tile_set->map_to_local(r_cell_data.coords));
|
|
|
|
|
scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform());
|
|
|
|
|
}
|
|
|
|
|
tile_map_node->add_child(scene);
|
|
|
|
|
if (tile_map_node) {
|
|
|
|
|
// Compatibility with TileMap.
|
|
|
|
|
tile_map_node->add_child(scene);
|
|
|
|
|
} else {
|
|
|
|
|
add_child(scene);
|
|
|
|
|
}
|
|
|
|
|
r_cell_data.scene = scene->get_name();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1352,26 +1345,28 @@ void TileMapLayer::_scenes_draw_cell_debug(const RID &p_canvas_item, const Vecto
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::_build_runtime_update_tile_data() {
|
|
|
|
|
const TileMap *tile_map_node = _fetch_tilemap();
|
|
|
|
|
const Ref<TileSet> &tile_set = get_effective_tile_set();
|
|
|
|
|
|
|
|
|
|
// Check if we should cleanup everything.
|
|
|
|
|
bool forced_cleanup = in_destructor || !enabled || !tile_set.is_valid() || !is_visible_in_tree();
|
|
|
|
|
if (!forced_cleanup) {
|
|
|
|
|
if (tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update)) {
|
|
|
|
|
bool valid_runtime_update = GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update);
|
|
|
|
|
bool valid_runtime_update_for_tilemap = tile_map_node && tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update); // For keeping compatibility.
|
|
|
|
|
if (valid_runtime_update || valid_runtime_update_for_tilemap) {
|
|
|
|
|
bool use_tilemap_for_runtime = valid_runtime_update_for_tilemap && !valid_runtime_update;
|
|
|
|
|
if (_runtime_update_tile_data_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET]) {
|
|
|
|
|
_runtime_update_needs_all_cells_cleaned_up = true;
|
|
|
|
|
for (KeyValue<Vector2i, CellData> &E : tile_map) {
|
|
|
|
|
_build_runtime_update_tile_data_for_cell(E.value);
|
|
|
|
|
_build_runtime_update_tile_data_for_cell(E.value, use_tilemap_for_runtime);
|
|
|
|
|
}
|
|
|
|
|
} else if (dirty.flags[DIRTY_FLAGS_TILE_MAP_RUNTIME_UPDATE]) {
|
|
|
|
|
} else if (dirty.flags[DIRTY_FLAGS_LAYER_RUNTIME_UPDATE]) {
|
|
|
|
|
for (KeyValue<Vector2i, CellData> &E : tile_map) {
|
|
|
|
|
_build_runtime_update_tile_data_for_cell(E.value, true);
|
|
|
|
|
_build_runtime_update_tile_data_for_cell(E.value, use_tilemap_for_runtime, true);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) {
|
|
|
|
|
CellData &cell_data = *cell_data_list_element->self();
|
|
|
|
|
_build_runtime_update_tile_data_for_cell(cell_data);
|
|
|
|
|
_build_runtime_update_tile_data_for_cell(cell_data, use_tilemap_for_runtime);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1382,8 +1377,7 @@ void TileMapLayer::_build_runtime_update_tile_data() {
|
|
|
|
|
_runtime_update_tile_data_was_cleaned_up = forced_cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::_build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_auto_add_to_dirty_list) {
|
|
|
|
|
TileMap *tile_map_node = _fetch_tilemap();
|
|
|
|
|
void TileMapLayer::_build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_use_tilemap_for_runtime, bool p_auto_add_to_dirty_list) {
|
|
|
|
|
const Ref<TileSet> &tile_set = get_effective_tile_set();
|
|
|
|
|
|
|
|
|
|
TileMapCell &c = r_cell_data.cell;
|
|
|
|
|
@ -1395,18 +1389,37 @@ void TileMapLayer::_build_runtime_update_tile_data_for_cell(CellData &r_cell_dat
|
|
|
|
|
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
|
|
|
|
|
if (atlas_source) {
|
|
|
|
|
bool ret = false;
|
|
|
|
|
if (tile_map_node->GDVIRTUAL_CALL(_use_tile_data_runtime_update, layer_index_in_tile_map_node, r_cell_data.coords, ret) && ret) {
|
|
|
|
|
TileData *tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
|
|
|
|
|
|
|
|
|
|
// Create the runtime TileData.
|
|
|
|
|
TileData *tile_data_runtime_use = tile_data->duplicate();
|
|
|
|
|
tile_data_runtime_use->set_allow_transform(true);
|
|
|
|
|
r_cell_data.runtime_tile_data_cache = tile_data_runtime_use;
|
|
|
|
|
if (p_use_tilemap_for_runtime) {
|
|
|
|
|
// Compatibility with TileMap.
|
|
|
|
|
if (tile_map_node->GDVIRTUAL_CALL(_use_tile_data_runtime_update, layer_index_in_tile_map_node, r_cell_data.coords, ret) && ret) {
|
|
|
|
|
TileData *tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
|
|
|
|
|
|
|
|
|
|
tile_map_node->GDVIRTUAL_CALL(_tile_data_runtime_update, layer_index_in_tile_map_node, r_cell_data.coords, tile_data_runtime_use);
|
|
|
|
|
// Create the runtime TileData.
|
|
|
|
|
TileData *tile_data_runtime_use = tile_data->duplicate();
|
|
|
|
|
tile_data_runtime_use->set_allow_transform(true);
|
|
|
|
|
r_cell_data.runtime_tile_data_cache = tile_data_runtime_use;
|
|
|
|
|
|
|
|
|
|
if (p_auto_add_to_dirty_list) {
|
|
|
|
|
dirty.cell_list.add(&r_cell_data.dirty_list_element);
|
|
|
|
|
tile_map_node->GDVIRTUAL_CALL(_tile_data_runtime_update, layer_index_in_tile_map_node, r_cell_data.coords, tile_data_runtime_use);
|
|
|
|
|
|
|
|
|
|
if (p_auto_add_to_dirty_list) {
|
|
|
|
|
dirty.cell_list.add(&r_cell_data.dirty_list_element);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (GDVIRTUAL_CALL(_use_tile_data_runtime_update, r_cell_data.coords, ret) && ret) {
|
|
|
|
|
TileData *tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
|
|
|
|
|
|
|
|
|
|
// Create the runtime TileData.
|
|
|
|
|
TileData *tile_data_runtime_use = tile_data->duplicate();
|
|
|
|
|
tile_data_runtime_use->set_allow_transform(true);
|
|
|
|
|
r_cell_data.runtime_tile_data_cache = tile_data_runtime_use;
|
|
|
|
|
|
|
|
|
|
GDVIRTUAL_CALL(_tile_data_runtime_update, r_cell_data.coords, tile_data_runtime_use);
|
|
|
|
|
|
|
|
|
|
if (p_auto_add_to_dirty_list) {
|
|
|
|
|
dirty.cell_list.add(&r_cell_data.dirty_list_element);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1611,8 +1624,7 @@ void TileMapLayer::_renamed() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::_update_notify_local_transform() {
|
|
|
|
|
TileMap *tile_map_node = _fetch_tilemap();
|
|
|
|
|
bool notify = tile_map_node->is_collision_animatable() || is_y_sort_enabled();
|
|
|
|
|
bool notify = is_using_kinematic_bodies() || is_y_sort_enabled();
|
|
|
|
|
if (!notify) {
|
|
|
|
|
if (is_y_sort_enabled()) {
|
|
|
|
|
notify = true;
|
|
|
|
|
@ -1727,16 +1739,23 @@ void TileMapLayer::_notification(int p_what) {
|
|
|
|
|
void TileMapLayer::_bind_methods() {
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMapLayer::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(0));
|
|
|
|
|
|
|
|
|
|
GDVIRTUAL_BIND(_use_tile_data_runtime_update, "coords");
|
|
|
|
|
GDVIRTUAL_BIND(_tile_data_runtime_update, "coords", "tile_data");
|
|
|
|
|
|
|
|
|
|
ADD_SIGNAL(MethodInfo(CoreStringNames::get_singleton()->changed));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::set_layer_index_in_tile_map_node(int p_index) {
|
|
|
|
|
if (p_index == layer_index_in_tile_map_node) {
|
|
|
|
|
return;
|
|
|
|
|
void TileMapLayer::set_as_tile_map_internal_node(int p_index) {
|
|
|
|
|
// Compatibility with TileMap.
|
|
|
|
|
ERR_FAIL_NULL(get_parent());
|
|
|
|
|
tile_map_node = Object::cast_to<TileMap>(get_parent());
|
|
|
|
|
set_use_parent_material(true);
|
|
|
|
|
force_parent_owned();
|
|
|
|
|
if (layer_index_in_tile_map_node != p_index) {
|
|
|
|
|
layer_index_in_tile_map_node = p_index;
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE] = true;
|
|
|
|
|
_queue_internal_update();
|
|
|
|
|
}
|
|
|
|
|
layer_index_in_tile_map_node = p_index;
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE] = true;
|
|
|
|
|
_queue_internal_update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Rect2 TileMapLayer::get_rect(bool &r_changed) const {
|
|
|
|
|
@ -2085,7 +2104,7 @@ void TileMapLayer::set_tile_data(TileMapDataFormat p_format, const Vector<int> &
|
|
|
|
|
clear();
|
|
|
|
|
|
|
|
|
|
#ifdef DISABLE_DEPRECATED
|
|
|
|
|
ERR_FAIL_COND_MSG(p_format != TileMapDataFormat::FORMAT_3, vformat("Cannot handle deprecated TileMap data format version %d. This Godot version was compiled with no support for deprecated data.", p_format));
|
|
|
|
|
ERR_FAIL_COND_MSG(p_format != TileMapDataFormat::FORMAT_3, vformat("Cannot handle deprecated TileMapLayer data format version %d. This Godot version was compiled with no support for deprecated data.", p_format));
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < c; i += offset) {
|
|
|
|
|
@ -2176,7 +2195,7 @@ Vector<int> TileMapLayer::get_tile_data() const {
|
|
|
|
|
return tile_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::notify_tile_map_change(DirtyFlags p_what) {
|
|
|
|
|
void TileMapLayer::notify_tile_map_layer_group_change(DirtyFlags p_what) {
|
|
|
|
|
if (p_what == DIRTY_FLAGS_LAYER_GROUP_SELECTED_LAYERS ||
|
|
|
|
|
p_what == DIRTY_FLAGS_LAYER_GROUP_HIGHLIGHT_SELECTED ||
|
|
|
|
|
p_what == DIRTY_FLAGS_LAYER_GROUP_TILE_SET) {
|
|
|
|
|
@ -2192,6 +2211,12 @@ void TileMapLayer::update_internals() {
|
|
|
|
|
_deferred_internal_update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::notify_runtime_tile_data_update() {
|
|
|
|
|
dirty.flags[TileMapLayer::DIRTY_FLAGS_LAYER_RUNTIME_UPDATE] = true;
|
|
|
|
|
_queue_internal_update();
|
|
|
|
|
emit_signal(CoreStringNames::get_singleton()->changed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
|
|
|
|
|
// Set the current cell tile (using integer position).
|
|
|
|
|
Vector2i pk(p_coords);
|
|
|
|
|
@ -2532,8 +2557,9 @@ void TileMapLayer::set_enabled(bool p_enabled) {
|
|
|
|
|
_queue_internal_update();
|
|
|
|
|
emit_signal(CoreStringNames::get_singleton()->changed);
|
|
|
|
|
|
|
|
|
|
TileMap *tile_map_node = _fetch_tilemap();
|
|
|
|
|
tile_map_node->update_configuration_warnings();
|
|
|
|
|
if (tile_map_node) {
|
|
|
|
|
tile_map_node->update_configuration_warnings();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TileMapLayer::is_enabled() const {
|
|
|
|
|
@ -2559,8 +2585,9 @@ void TileMapLayer::set_y_sort_enabled(bool p_y_sort_enabled) {
|
|
|
|
|
_queue_internal_update();
|
|
|
|
|
emit_signal(CoreStringNames::get_singleton()->changed);
|
|
|
|
|
|
|
|
|
|
TileMap *tile_map_node = _fetch_tilemap();
|
|
|
|
|
tile_map_node->update_configuration_warnings();
|
|
|
|
|
if (tile_map_node) {
|
|
|
|
|
tile_map_node->update_configuration_warnings();
|
|
|
|
|
}
|
|
|
|
|
_update_notify_local_transform();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -2587,8 +2614,51 @@ void TileMapLayer::set_z_index(int p_z_index) {
|
|
|
|
|
_queue_internal_update();
|
|
|
|
|
emit_signal(CoreStringNames::get_singleton()->changed);
|
|
|
|
|
|
|
|
|
|
TileMap *tile_map_node = _fetch_tilemap();
|
|
|
|
|
tile_map_node->update_configuration_warnings();
|
|
|
|
|
if (tile_map_node) {
|
|
|
|
|
tile_map_node->update_configuration_warnings();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::set_light_mask(int p_light_mask) {
|
|
|
|
|
if (get_light_mask() == p_light_mask) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
CanvasItem::set_light_mask(p_light_mask);
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_LAYER_LIGHT_MASK] = true;
|
|
|
|
|
_queue_internal_update();
|
|
|
|
|
emit_signal(CoreStringNames::get_singleton()->changed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::set_texture_filter(TextureFilter p_texture_filter) {
|
|
|
|
|
// Set a default texture filter for the whole tilemap.
|
|
|
|
|
CanvasItem::set_texture_filter(p_texture_filter);
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_LAYER_TEXTURE_FILTER] = true;
|
|
|
|
|
_queue_internal_update();
|
|
|
|
|
emit_signal(CoreStringNames::get_singleton()->changed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
|
|
|
|
|
// Set a default texture repeat for the whole tilemap.
|
|
|
|
|
CanvasItem::set_texture_repeat(p_texture_repeat);
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_LAYER_TEXTURE_REPEAT] = true;
|
|
|
|
|
_queue_internal_update();
|
|
|
|
|
emit_signal(CoreStringNames::get_singleton()->changed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::set_rendering_quadrant_size(int p_size) {
|
|
|
|
|
if (rendering_quadrant_size == p_size) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_LAYER_RENDERING_QUADRANT_SIZE] = true;
|
|
|
|
|
ERR_FAIL_COND_MSG(p_size < 1, "TileMapQuadrant size cannot be smaller than 1.");
|
|
|
|
|
|
|
|
|
|
rendering_quadrant_size = p_size;
|
|
|
|
|
_queue_internal_update();
|
|
|
|
|
emit_signal(CoreStringNames::get_singleton()->changed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int TileMapLayer::get_rendering_quadrant_size() const {
|
|
|
|
|
return rendering_quadrant_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::set_use_kinematic_bodies(bool p_use_kinematic_bodies) {
|
|
|
|
|
@ -2602,6 +2672,20 @@ bool TileMapLayer::is_using_kinematic_bodies() const {
|
|
|
|
|
return use_kinematic_bodies;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::set_collision_visibility_mode(TileMapLayer::VisibilityMode p_show_collision) {
|
|
|
|
|
if (collision_visibility_mode == p_show_collision) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
collision_visibility_mode = p_show_collision;
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_LAYER_COLLISION_VISIBILITY_MODE] = true;
|
|
|
|
|
_queue_internal_update();
|
|
|
|
|
emit_signal(CoreStringNames::get_singleton()->changed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TileMapLayer::VisibilityMode TileMapLayer::get_collision_visibility_mode() const {
|
|
|
|
|
return collision_visibility_mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::set_navigation_enabled(bool p_enabled) {
|
|
|
|
|
if (navigation_enabled == p_enabled) {
|
|
|
|
|
return;
|
|
|
|
|
@ -2617,18 +2701,38 @@ bool TileMapLayer::is_navigation_enabled() const {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::set_navigation_map(RID p_map) {
|
|
|
|
|
ERR_FAIL_COND_MSG(!is_inside_tree(), "A TileMap navigation map can only be changed while inside the SceneTree.");
|
|
|
|
|
navigation_map = p_map;
|
|
|
|
|
uses_world_navigation_map = p_map == get_world_2d()->get_navigation_map();
|
|
|
|
|
if (navigation_map_override == p_map) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
navigation_map_override = p_map;
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_MAP] = true;
|
|
|
|
|
_queue_internal_update();
|
|
|
|
|
emit_signal(CoreStringNames::get_singleton()->changed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RID TileMapLayer::get_navigation_map() const {
|
|
|
|
|
if (navigation_map.is_valid()) {
|
|
|
|
|
return navigation_map;
|
|
|
|
|
if (navigation_map_override.is_valid()) {
|
|
|
|
|
return navigation_map_override;
|
|
|
|
|
} else if (is_inside_tree()) {
|
|
|
|
|
return get_world_2d()->get_navigation_map();
|
|
|
|
|
}
|
|
|
|
|
return RID();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::set_navigation_visibility_mode(TileMapLayer::VisibilityMode p_show_navigation) {
|
|
|
|
|
if (navigation_visibility_mode == p_show_navigation) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
navigation_visibility_mode = p_show_navigation;
|
|
|
|
|
dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_VISIBILITY_MODE] = true;
|
|
|
|
|
_queue_internal_update();
|
|
|
|
|
emit_signal(CoreStringNames::get_singleton()->changed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TileMapLayer::VisibilityMode TileMapLayer::get_navigation_visibility_mode() const {
|
|
|
|
|
return navigation_visibility_mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TileMapLayer::fix_invalid_tiles() {
|
|
|
|
|
Ref<TileSet> tileset = get_effective_tile_set();
|
|
|
|
|
ERR_FAIL_COND_MSG(tileset.is_null(), "Cannot call fix_invalid_tiles() on a TileMap without a valid TileSet.");
|
|
|
|
|
|