Merge pull request #61809 from groud/terrain_center_bit
This commit is contained in:
commit
d4f31e201d
|
@ -79,7 +79,7 @@
|
|||
Returns the occluder polygon of the tile for the TileSet occlusion layer with index [code]layer_id[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_peering_bit_terrain" qualifiers="const">
|
||||
<method name="get_terrain_peering_bit" qualifiers="const">
|
||||
<return type="int" />
|
||||
<argument index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor" />
|
||||
<description>
|
||||
|
@ -185,7 +185,7 @@
|
|||
Sets the occluder for the TileSet occlusion layer with index [code]layer_id[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_peering_bit_terrain">
|
||||
<method name="set_terrain_peering_bit">
|
||||
<return type="void" />
|
||||
<argument index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor" />
|
||||
<argument index="1" name="terrain" type="int" />
|
||||
|
@ -205,6 +205,8 @@
|
|||
</member>
|
||||
<member name="probability" type="float" setter="set_probability" getter="get_probability" default="1.0">
|
||||
</member>
|
||||
<member name="terrain" type="int" setter="set_terrain" getter="get_terrain" default="-1">
|
||||
</member>
|
||||
<member name="terrain_set" type="int" setter="set_terrain_set" getter="get_terrain_set" default="-1">
|
||||
</member>
|
||||
<member name="texture_offset" type="Vector2i" setter="set_texture_offset" getter="get_texture_offset" default="Vector2i(0, 0)">
|
||||
|
|
|
@ -243,15 +243,30 @@
|
|||
- The alternative tile identifier [code]alternative_tile[/code] identifies a tile alternative the source is a [TileSetAtlasSource], and the scene for a [TileSetScenesCollectionSource].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_cells_from_surrounding_terrains">
|
||||
<method name="set_cells_terrain_connect">
|
||||
<return type="void" />
|
||||
<argument index="0" name="layer" type="int" />
|
||||
<argument index="1" name="cells" type="Vector2i[]" />
|
||||
<argument index="2" name="terrain_set" type="int" />
|
||||
<argument index="3" name="ignore_empty_terrains" type="bool" default="true" />
|
||||
<argument index="3" name="terrain" type="int" />
|
||||
<argument index="4" name="ignore_empty_terrains" type="bool" default="true" />
|
||||
<description>
|
||||
Updates all the cells in the [code]cells[/code] coordinates array and replace them by tiles that matches the surrounding cells terrains. Only cells form the given [code]terrain_set[/code] are considered.
|
||||
If [code]ignore_empty_terrains[/code] is true, zones with no terrain defined are ignored to select the tiles.
|
||||
Update all the cells in the [code]cells[/code] coordinates array so that they use the given [code]terrain[/code] for the given [code]terrain_set[/code]. 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 [code]ignore_empty_terrains[/code] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints.
|
||||
If [code]ignore_empty_terrains[/code] 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, [code]set_cells_terrain_connect[/code] requires the TileMap'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" />
|
||||
<argument index="0" name="layer" type="int" />
|
||||
<argument index="1" name="path" type="Vector2i[]" />
|
||||
<argument index="2" name="terrain_set" type="int" />
|
||||
<argument index="3" name="terrain" type="int" />
|
||||
<argument index="4" name="ignore_empty_terrains" type="bool" default="true" />
|
||||
<description>
|
||||
Update all the cells in the [code]cells[/code] coordinates array so that they use the given [code]terrain[/code] for the given [code]terrain_set[/code]. 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 [code]ignore_empty_terrains[/code] 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, [code]set_cells_terrain_path[/code] requires the TileMap's TileSet to have terrains set up with all required terrain combinations. Otherwise, it may produce unexpected results.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_layer_enabled">
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg height="32" viewBox="0 0 16 16" width="32" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><circle cx="8" cy="8" r="2.000028" stroke-width="1.09711"/><g stroke-width=".5" transform="translate(0 -1036.4)"><path d="m7 1039.9h-1l2-2.5 2 2.5h-1v2h-2z"/><path d="m3.5606601 1041.3748-.7071068.707-.3535533-3.1818 3.1819804.3535-.7071067.7071.7071067.7071-1.4142135 1.4142z"/><path d="m11.0252 1039.9606-.707-.7071 3.1818-.3535-.3535 3.1819-.7071-.7071-.7071.7071-1.4142-1.4142z"/><path d="m12.43934 1047.4252.707107-.707.353553 3.1818-3.18198-.3535.707106-.7071-.707106-.7071 1.414214-1.4142z"/><path d="m4.9748005 1048.8394.707.7071-3.1818.3535.3535-3.1819.7071.7071.7071-.7071 1.4142 1.4142z"/><path d="m12.5 1043.4v-1l2.5 2-2.5 2v-1h-2v-2z"/><path d="m9 1048.9h1l-2 2.5-2-2.5h1v-2h2z"/><path d="m3.5 1045.4v1l-2.5-2 2.5-2v1h2v2z"/></g></g></svg>
|
After Width: | Height: | Size: 854 B |
|
@ -0,0 +1 @@
|
|||
<svg height="32" viewBox="0 0 16 16" width="32" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><circle cx="3" cy="1049.4" r="2.000028" stroke-width="1.09711"/><circle cx="13" cy="1039.4" r="2.000028" stroke-width="1.09711"/><path d="m7 1038.4v10h-4v2h4 2v-2-8h4v-2h-4z" stroke-width=".46291"/></g></svg>
|
After Width: | Height: | Size: 343 B |
|
@ -1676,10 +1676,15 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
|
|||
Vector<Color> color;
|
||||
color.push_back(Color(1.0, 1.0, 1.0, 0.5));
|
||||
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
|
||||
if (Geometry2D::is_point_in_polygon(xform.affine_inverse().xform(mouse_pos), polygon)) {
|
||||
p_canvas_item->draw_set_transform_matrix(p_transform * xform);
|
||||
p_canvas_item->draw_polygon(polygon, color);
|
||||
}
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
|
||||
if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
|
||||
polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
|
||||
if (Geometry2D::is_point_in_polygon(xform.affine_inverse().xform(mouse_pos), polygon)) {
|
||||
p_canvas_item->draw_set_transform_matrix(p_transform * xform);
|
||||
p_canvas_item->draw_polygon(polygon, color);
|
||||
|
@ -1806,10 +1811,19 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
|
|||
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
|
||||
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
|
||||
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
|
||||
for (int j = 0; j < polygon.size(); j++) {
|
||||
polygon.write[j] += position;
|
||||
}
|
||||
if (!Geometry2D::intersect_polygons(polygon, mouse_pos_rect_polygon).is_empty()) {
|
||||
// Draw terrain.
|
||||
p_canvas_item->draw_polygon(polygon, color);
|
||||
}
|
||||
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
|
||||
if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
|
||||
polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
|
||||
for (int j = 0; j < polygon.size(); j++) {
|
||||
polygon.write[j] += position;
|
||||
}
|
||||
|
@ -1850,10 +1864,16 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til
|
|||
Vector<Color> color;
|
||||
color.push_back(Color(1.0, 1.0, 1.0, 0.5));
|
||||
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
|
||||
if (Geometry2D::is_point_in_polygon(xform.affine_inverse().xform(mouse_pos), polygon)) {
|
||||
p_canvas_item->draw_set_transform_matrix(p_transform * xform);
|
||||
p_canvas_item->draw_polygon(polygon, color);
|
||||
}
|
||||
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
|
||||
if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
|
||||
polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
|
||||
if (Geometry2D::is_point_in_polygon(xform.affine_inverse().xform(mouse_pos), polygon)) {
|
||||
p_canvas_item->draw_set_transform_matrix(p_transform * xform);
|
||||
p_canvas_item->draw_polygon(polygon, color);
|
||||
|
@ -1926,10 +1946,11 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
|
|||
if (!drag_modified.has(cell)) {
|
||||
Dictionary dict;
|
||||
dict["terrain_set"] = tile_data->get_terrain_set();
|
||||
dict["terrain"] = tile_data->get_terrain();
|
||||
Array array;
|
||||
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
|
||||
array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
|
||||
array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
|
||||
}
|
||||
dict["terrain_peering_bits"] = array;
|
||||
drag_modified[cell] = dict;
|
||||
|
@ -1958,10 +1979,11 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
|
|||
if (!drag_modified.has(cell)) {
|
||||
Dictionary dict;
|
||||
dict["terrain_set"] = tile_data->get_terrain_set();
|
||||
dict["terrain"] = tile_data->get_terrain();
|
||||
Array array;
|
||||
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
|
||||
array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
|
||||
array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
|
||||
}
|
||||
dict["terrain_peering_bits"] = array;
|
||||
drag_modified[cell] = dict;
|
||||
|
@ -1970,12 +1992,17 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
|
|||
// Set the terrains bits.
|
||||
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
|
||||
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
|
||||
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_polygon(tile_data->get_terrain_set());
|
||||
if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) {
|
||||
tile_data->set_terrain(terrain);
|
||||
}
|
||||
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
|
||||
if (tile_data->is_valid_peering_bit_terrain(bit)) {
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(tile_data->get_terrain_set(), bit);
|
||||
if (tile_data->is_valid_terrain_peering_bit(bit)) {
|
||||
polygon = tile_set->get_terrain_peering_bit_polygon(tile_data->get_terrain_set(), bit);
|
||||
if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) {
|
||||
tile_data->set_peering_bit_terrain(bit, terrain);
|
||||
tile_data->set_terrain_peering_bit(bit, terrain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2000,12 +2027,17 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
|
|||
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
|
||||
dummy_object->set("terrain_set", terrain_set);
|
||||
dummy_object->set("terrain", -1);
|
||||
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
|
||||
if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
|
||||
dummy_object->set("terrain", tile_data->get_terrain());
|
||||
}
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
|
||||
if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
|
||||
polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
|
||||
if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
|
||||
dummy_object->set("terrain", tile_data->get_peering_bit_terrain(bit));
|
||||
dummy_object->set("terrain", tile_data->get_terrain_peering_bit(bit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2044,10 +2076,11 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
|
|||
// Save the old terrain_set and terrains bits.
|
||||
Dictionary dict;
|
||||
dict["terrain_set"] = tile_data->get_terrain_set();
|
||||
dict["terrain"] = tile_data->get_terrain();
|
||||
Array array;
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
|
||||
array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
|
||||
}
|
||||
dict["terrain_peering_bits"] = array;
|
||||
drag_modified[cell] = dict;
|
||||
|
@ -2085,10 +2118,11 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
|
|||
// Save the old terrain_set and terrains bits.
|
||||
Dictionary dict;
|
||||
dict["terrain_set"] = tile_data->get_terrain_set();
|
||||
dict["terrain"] = tile_data->get_terrain();
|
||||
Array array;
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
|
||||
array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
|
||||
}
|
||||
dict["terrain_peering_bits"] = array;
|
||||
drag_modified[cell] = dict;
|
||||
|
@ -2097,12 +2131,16 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
|
|||
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
|
||||
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
|
||||
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
|
||||
if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
|
||||
tile_data->set_terrain(terrain);
|
||||
}
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
|
||||
if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
|
||||
polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
|
||||
if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
|
||||
tile_data->set_peering_bit_terrain(bit, terrain);
|
||||
tile_data->set_terrain_peering_bit(bit, terrain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2138,10 +2176,11 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
|
|||
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0);
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E.alternative_tile), tile_data->get_terrain_set());
|
||||
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E.alternative_tile), drag_painted_value);
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.alternative_tile), tile_data->get_terrain());
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_data->is_valid_peering_bit_terrain(bit)) {
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.alternative_tile), tile_data->get_peering_bit_terrain(bit));
|
||||
if (tile_data->is_valid_terrain_peering_bit(bit)) {
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.alternative_tile), tile_data->get_terrain_peering_bit(bit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2154,10 +2193,11 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
|
|||
Vector2i coords = E.key.get_atlas_coords();
|
||||
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E.key.alternative_tile), drag_painted_value);
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E.key.alternative_tile), dict["terrain_set"]);
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.key.alternative_tile), dict["terrain"]);
|
||||
Array array = dict["terrain_peering_bits"];
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(dict["terrain_set"], bit)) {
|
||||
if (tile_set->is_valid_terrain_peering_bit(dict["terrain_set"], bit)) {
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.key.alternative_tile), array[i]);
|
||||
}
|
||||
}
|
||||
|
@ -2172,13 +2212,15 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
|
|||
for (KeyValue<TileMapCell, Variant> &E : drag_modified) {
|
||||
Dictionary dict = E.value;
|
||||
Vector2i coords = E.key.get_atlas_coords();
|
||||
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.key.alternative_tile), terrain);
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.key.alternative_tile), dict["terrain"]);
|
||||
Array array = dict["terrain_peering_bits"];
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
|
||||
if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
|
||||
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.key.alternative_tile), terrain);
|
||||
}
|
||||
if (tile_set->is_valid_peering_bit_terrain(dict["terrain_set"], bit)) {
|
||||
if (tile_set->is_valid_terrain_peering_bit(dict["terrain_set"], bit)) {
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.key.alternative_tile), array[i]);
|
||||
}
|
||||
}
|
||||
|
@ -2224,20 +2266,30 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
|
|||
Vector2i coords = E.get_atlas_coords();
|
||||
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0);
|
||||
|
||||
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
|
||||
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
|
||||
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
|
||||
for (int j = 0; j < polygon.size(); j++) {
|
||||
polygon.write[j] += position;
|
||||
}
|
||||
if (!Geometry2D::intersect_polygons(polygon, mouse_pos_rect_polygon).is_empty()) {
|
||||
// Draw terrain.
|
||||
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.alternative_tile), terrain);
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.alternative_tile), tile_data->get_terrain());
|
||||
}
|
||||
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
|
||||
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
|
||||
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
|
||||
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
|
||||
if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
|
||||
polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
|
||||
for (int j = 0; j < polygon.size(); j++) {
|
||||
polygon.write[j] += position;
|
||||
}
|
||||
if (!Geometry2D::intersect_polygons(polygon, mouse_pos_rect_polygon).is_empty()) {
|
||||
// Draw bit.
|
||||
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.alternative_tile), terrain);
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.alternative_tile), tile_data->get_peering_bit_terrain(bit));
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.alternative_tile), tile_data->get_terrain_peering_bit(bit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2267,10 +2319,11 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
|
|||
if (!drag_modified.has(cell)) {
|
||||
Dictionary dict;
|
||||
dict["terrain_set"] = tile_data->get_terrain_set();
|
||||
dict["terrain"] = tile_data->get_terrain();
|
||||
Array array;
|
||||
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
|
||||
array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
|
||||
array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
|
||||
}
|
||||
dict["terrain_peering_bits"] = array;
|
||||
drag_modified[cell] = dict;
|
||||
|
@ -2300,10 +2353,11 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
|
|||
if (!drag_modified.has(cell)) {
|
||||
Dictionary dict;
|
||||
dict["terrain_set"] = tile_data->get_terrain_set();
|
||||
dict["terrain"] = tile_data->get_terrain();
|
||||
Array array;
|
||||
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
|
||||
array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
|
||||
array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
|
||||
}
|
||||
dict["terrain_peering_bits"] = array;
|
||||
drag_modified[cell] = dict;
|
||||
|
@ -2312,12 +2366,18 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
|
|||
// Set the terrains bits.
|
||||
Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
|
||||
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
|
||||
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_polygon(tile_data->get_terrain_set());
|
||||
if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) {
|
||||
tile_data->set_terrain(terrain);
|
||||
}
|
||||
|
||||
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
|
||||
if (tile_data->is_valid_peering_bit_terrain(bit)) {
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(tile_data->get_terrain_set(), bit);
|
||||
if (tile_data->is_valid_terrain_peering_bit(bit)) {
|
||||
polygon = tile_set->get_terrain_peering_bit_polygon(tile_data->get_terrain_set(), bit);
|
||||
if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) {
|
||||
tile_data->set_peering_bit_terrain(bit, terrain);
|
||||
tile_data->set_terrain_peering_bit(bit, terrain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2343,12 +2403,18 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
|
|||
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
|
||||
dummy_object->set("terrain_set", terrain_set);
|
||||
dummy_object->set("terrain", -1);
|
||||
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
|
||||
if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
|
||||
dummy_object->set("terrain", tile_data->get_terrain());
|
||||
}
|
||||
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
|
||||
if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
|
||||
polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
|
||||
if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
|
||||
dummy_object->set("terrain", tile_data->get_peering_bit_terrain(bit));
|
||||
dummy_object->set("terrain", tile_data->get_terrain_peering_bit(bit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2380,7 +2446,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
|
|||
Array array;
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
|
||||
array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
|
||||
}
|
||||
dict["terrain_peering_bits"] = array;
|
||||
drag_modified[cell] = dict;
|
||||
|
@ -2405,10 +2471,11 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
|
|||
// Save the old terrain_set and terrains bits.
|
||||
Dictionary dict;
|
||||
dict["terrain_set"] = tile_data->get_terrain_set();
|
||||
dict["terrain"] = tile_data->get_terrain();
|
||||
Array array;
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
|
||||
array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
|
||||
}
|
||||
dict["terrain_peering_bits"] = array;
|
||||
drag_modified[cell] = dict;
|
||||
|
@ -2416,12 +2483,17 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
|
|||
// Set the terrain bit.
|
||||
Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
|
||||
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
|
||||
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
|
||||
if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
|
||||
tile_data->set_terrain(terrain);
|
||||
}
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
|
||||
Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
|
||||
if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
|
||||
polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
|
||||
if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
|
||||
tile_data->set_peering_bit_terrain(bit, terrain);
|
||||
tile_data->set_terrain_peering_bit(bit, terrain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2437,6 +2509,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
|
|||
Vector2i coords = E.key.get_atlas_coords();
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E.key.alternative_tile), dict["terrain_set"]);
|
||||
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E.key.alternative_tile), drag_painted_value);
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.key.alternative_tile), dict["terrain"]);
|
||||
Array array = dict["terrain_peering_bits"];
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.key.alternative_tile), array[i]);
|
||||
|
@ -2452,13 +2525,15 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
|
|||
for (KeyValue<TileMapCell, Variant> &E : drag_modified) {
|
||||
Dictionary dict = E.value;
|
||||
Vector2i coords = E.key.get_atlas_coords();
|
||||
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.key.alternative_tile), terrain);
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.key.alternative_tile), dict["terrain"]);
|
||||
Array array = dict["terrain_peering_bits"];
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
|
||||
if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
|
||||
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.key.alternative_tile), terrain);
|
||||
}
|
||||
if (tile_set->is_valid_peering_bit_terrain(dict["terrain_set"], bit)) {
|
||||
if (tile_set->is_valid_terrain_peering_bit(dict["terrain_set"], bit)) {
|
||||
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.key.alternative_tile), array[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2321,7 +2321,7 @@ Vector<TileMapEditorPlugin::TabData> TileMapEditorTerrainsPlugin::get_tabs() con
|
|||
return tabs;
|
||||
}
|
||||
|
||||
HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrains(const HashMap<Vector2i, TileSet::TerrainsPattern> &p_to_paint, int p_terrain_set) const {
|
||||
HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrain_path_or_connect(const Vector<Vector2i> &p_to_paint, int p_terrain_set, int p_terrain, bool p_connect) const {
|
||||
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
||||
if (!tile_map) {
|
||||
return HashMap<Vector2i, TileMapCell>();
|
||||
|
@ -2332,105 +2332,87 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrains(const
|
|||
return HashMap<Vector2i, TileMapCell>();
|
||||
}
|
||||
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output;
|
||||
if (p_connect) {
|
||||
terrain_fill_output = tile_map->terrain_fill_connect(tile_map_layer, p_to_paint, p_terrain_set, p_terrain, false);
|
||||
} else {
|
||||
terrain_fill_output = tile_map->terrain_fill_path(tile_map_layer, p_to_paint, p_terrain_set, p_terrain, false);
|
||||
}
|
||||
|
||||
// Make the painted path a set for faster lookups
|
||||
HashSet<Vector2i> painted_set;
|
||||
for (Vector2i coords : p_to_paint) {
|
||||
painted_set.insert(coords);
|
||||
}
|
||||
|
||||
HashMap<Vector2i, TileMapCell> output;
|
||||
|
||||
// Add the constraints from the added tiles.
|
||||
RBSet<TileMap::TerrainConstraint> added_tiles_constraints_set;
|
||||
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E_to_paint : p_to_paint) {
|
||||
Vector2i coords = E_to_paint.key;
|
||||
TileSet::TerrainsPattern terrains_pattern = E_to_paint.value;
|
||||
|
||||
RBSet<TileMap::TerrainConstraint> cell_constraints = tile_map->get_terrain_constraints_from_added_tile(coords, p_terrain_set, terrains_pattern);
|
||||
for (const TileMap::TerrainConstraint &E : cell_constraints) {
|
||||
added_tiles_constraints_set.insert(E);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the list of potential tiles to replace.
|
||||
RBSet<Vector2i> potential_to_replace;
|
||||
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E_to_paint : p_to_paint) {
|
||||
Vector2i coords = E_to_paint.key;
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
if (tile_map->is_existing_neighbor(TileSet::CellNeighbor(i))) {
|
||||
Vector2i neighbor = tile_map->get_neighbor_cell(coords, TileSet::CellNeighbor(i));
|
||||
if (!p_to_paint.has(neighbor)) {
|
||||
potential_to_replace.insert(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set of tiles to replace
|
||||
RBSet<Vector2i> to_replace;
|
||||
|
||||
// Add the central tiles to the one to replace.
|
||||
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E_to_paint : p_to_paint) {
|
||||
to_replace.insert(E_to_paint.key);
|
||||
}
|
||||
|
||||
// Add the constraints from the surroundings of the modified areas.
|
||||
RBSet<TileMap::TerrainConstraint> removed_cells_constraints_set;
|
||||
bool to_replace_modified = true;
|
||||
while (to_replace_modified) {
|
||||
// Get the constraints from the removed cells.
|
||||
removed_cells_constraints_set = tile_map->get_terrain_constraints_from_removed_cells_list(tile_map_layer, to_replace, p_terrain_set, false);
|
||||
|
||||
// Filter the sources to make sure they are in the potential_to_replace.
|
||||
RBMap<TileMap::TerrainConstraint, RBSet<Vector2i>> per_constraint_tiles;
|
||||
for (const TileMap::TerrainConstraint &E : removed_cells_constraints_set) {
|
||||
HashMap<Vector2i, TileSet::CellNeighbor> sources_of_constraint = E.get_overlapping_coords_and_peering_bits();
|
||||
for (const KeyValue<Vector2i, TileSet::CellNeighbor> &E_source_tile_of_constraint : sources_of_constraint) {
|
||||
if (potential_to_replace.has(E_source_tile_of_constraint.key)) {
|
||||
per_constraint_tiles[E].insert(E_source_tile_of_constraint.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
to_replace_modified = false;
|
||||
for (const TileMap::TerrainConstraint &E : added_tiles_constraints_set) {
|
||||
TileMap::TerrainConstraint c = E;
|
||||
// Check if we have a conflict in constraints.
|
||||
if (removed_cells_constraints_set.has(c) && removed_cells_constraints_set.find(c)->get().get_terrain() != c.get_terrain()) {
|
||||
// If we do, we search for a neighbor to remove.
|
||||
if (per_constraint_tiles.has(c) && !per_constraint_tiles[c].is_empty()) {
|
||||
// Remove it.
|
||||
Vector2i to_add_to_remove = per_constraint_tiles[c].front()->get();
|
||||
potential_to_replace.erase(to_add_to_remove);
|
||||
to_replace.insert(to_add_to_remove);
|
||||
to_replace_modified = true;
|
||||
for (KeyValue<TileMap::TerrainConstraint, RBSet<Vector2i>> &E_source_tiles_of_constraint : per_constraint_tiles) {
|
||||
E_source_tiles_of_constraint.value.erase(to_add_to_remove);
|
||||
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
|
||||
if (painted_set.has(E.key)) {
|
||||
// Paint a random tile with the correct terrain for the painted path.
|
||||
output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
|
||||
} else {
|
||||
// Avoids updating the painted path from the output if the new pattern is the same as before.
|
||||
bool keep_old = false;
|
||||
TileMapCell cell = tile_map->get_cell(tile_map_layer, E.key);
|
||||
if (cell.source_id != TileSet::INVALID_SOURCE) {
|
||||
TileSetSource *source = *tile_set->get_source(cell.source_id);
|
||||
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
|
||||
if (atlas_source) {
|
||||
// Get tile data.
|
||||
TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
|
||||
if (tile_data && tile_data->get_terrains_pattern() == E.value) {
|
||||
keep_old = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!keep_old) {
|
||||
output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrain_pattern(const Vector<Vector2i> &p_to_paint, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const {
|
||||
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
|
||||
if (!tile_map) {
|
||||
return HashMap<Vector2i, TileMapCell>();
|
||||
}
|
||||
|
||||
Ref<TileSet> tile_set = tile_map->get_tileset();
|
||||
if (!tile_set.is_valid()) {
|
||||
return HashMap<Vector2i, TileMapCell>();
|
||||
}
|
||||
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = tile_map->terrain_fill_pattern(tile_map_layer, p_to_paint, p_terrain_set, p_terrains_pattern, false);
|
||||
|
||||
// Make the painted path a set for faster lookups
|
||||
HashSet<Vector2i> painted_set;
|
||||
for (Vector2i coords : p_to_paint) {
|
||||
painted_set.insert(coords);
|
||||
}
|
||||
|
||||
HashMap<Vector2i, TileMapCell> output;
|
||||
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
|
||||
if (painted_set.has(E.key)) {
|
||||
// Paint a random tile with the correct terrain for the painted path.
|
||||
output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
|
||||
} else {
|
||||
// Avoids updating the painted path from the output if the new pattern is the same as before.
|
||||
TileMapCell cell = tile_map->get_cell(tile_map_layer, E.key);
|
||||
if (cell.source_id != TileSet::INVALID_SOURCE) {
|
||||
TileSetSource *source = *tile_set->get_source(cell.source_id);
|
||||
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
|
||||
if (atlas_source) {
|
||||
// Get tile data.
|
||||
TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
|
||||
if (tile_data && !(tile_data->get_terrains_pattern() == E.value)) {
|
||||
output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Combine all constraints together.
|
||||
RBSet<TileMap::TerrainConstraint> constraints = removed_cells_constraints_set;
|
||||
for (const TileMap::TerrainConstraint &E : added_tiles_constraints_set) {
|
||||
constraints.insert(E);
|
||||
}
|
||||
|
||||
// Remove the central tiles from the ones to replace.
|
||||
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E_to_paint : p_to_paint) {
|
||||
to_replace.erase(E_to_paint.key);
|
||||
}
|
||||
|
||||
// Run WFC to fill the holes with the constraints.
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> wfc_output = tile_map->terrain_wave_function_collapse(to_replace, p_terrain_set, constraints);
|
||||
|
||||
// Actually paint the tiles.
|
||||
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E_to_paint : p_to_paint) {
|
||||
output[E_to_paint.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E_to_paint.value);
|
||||
}
|
||||
|
||||
// Use the WFC run for the output.
|
||||
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : wfc_output) {
|
||||
output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -2445,19 +2427,21 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_line(Vector2i
|
|||
return HashMap<Vector2i, TileMapCell>();
|
||||
}
|
||||
|
||||
TileSet::TerrainsPattern terrains_pattern;
|
||||
if (p_erase) {
|
||||
terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
|
||||
} else {
|
||||
terrains_pattern = selected_terrains_pattern;
|
||||
}
|
||||
if (selected_type == SELECTED_TYPE_CONNECT) {
|
||||
return _draw_terrain_path_or_connect(TileMapEditor::get_line(tile_map, p_start_cell, p_end_cell), selected_terrain_set, selected_terrain, true);
|
||||
} else if (selected_type == SELECTED_TYPE_PATH) {
|
||||
return _draw_terrain_path_or_connect(TileMapEditor::get_line(tile_map, p_start_cell, p_end_cell), selected_terrain_set, selected_terrain, false);
|
||||
} else { // SELECTED_TYPE_PATTERN
|
||||
TileSet::TerrainsPattern terrains_pattern;
|
||||
if (p_erase) {
|
||||
terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
|
||||
} else {
|
||||
terrains_pattern = selected_terrains_pattern;
|
||||
}
|
||||
|
||||
Vector<Vector2i> line = TileMapEditor::get_line(tile_map, p_start_cell, p_end_cell);
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> to_draw;
|
||||
for (int i = 0; i < line.size(); i++) {
|
||||
to_draw[line[i]] = terrains_pattern;
|
||||
Vector<Vector2i> line = TileMapEditor::get_line(tile_map, p_start_cell, p_end_cell);
|
||||
return _draw_terrain_pattern(line, selected_terrain_set, terrains_pattern);
|
||||
}
|
||||
return _draw_terrains(to_draw, selected_terrain_set);
|
||||
}
|
||||
|
||||
HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_rect(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase) {
|
||||
|
@ -2471,25 +2455,29 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_rect(Vector2i
|
|||
return HashMap<Vector2i, TileMapCell>();
|
||||
}
|
||||
|
||||
TileSet::TerrainsPattern terrains_pattern;
|
||||
if (p_erase) {
|
||||
terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
|
||||
} else {
|
||||
terrains_pattern = selected_terrains_pattern;
|
||||
}
|
||||
|
||||
Rect2i rect;
|
||||
rect.set_position(p_start_cell);
|
||||
rect.set_end(p_end_cell);
|
||||
rect = rect.abs();
|
||||
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> to_draw;
|
||||
Vector<Vector2i> to_draw;
|
||||
for (int x = rect.position.x; x <= rect.get_end().x; x++) {
|
||||
for (int y = rect.position.y; y <= rect.get_end().y; y++) {
|
||||
to_draw[Vector2i(x, y)] = terrains_pattern;
|
||||
to_draw.append(Vector2i(x, y));
|
||||
}
|
||||
}
|
||||
return _draw_terrains(to_draw, selected_terrain_set);
|
||||
|
||||
if (selected_type == SELECTED_TYPE_CONNECT || selected_type == SELECTED_TYPE_PATH) {
|
||||
return _draw_terrain_path_or_connect(to_draw, selected_terrain_set, selected_terrain, true);
|
||||
} else { // SELECTED_TYPE_PATTERN
|
||||
TileSet::TerrainsPattern terrains_pattern;
|
||||
if (p_erase) {
|
||||
terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
|
||||
} else {
|
||||
terrains_pattern = selected_terrains_pattern;
|
||||
}
|
||||
return _draw_terrain_pattern(to_draw, selected_terrain_set, terrains_pattern);
|
||||
}
|
||||
}
|
||||
|
||||
RBSet<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i p_coords, bool p_contiguous) {
|
||||
|
@ -2614,20 +2602,23 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_bucket_fill(Ve
|
|||
return HashMap<Vector2i, TileMapCell>();
|
||||
}
|
||||
|
||||
TileSet::TerrainsPattern terrains_pattern;
|
||||
if (p_erase) {
|
||||
terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
|
||||
} else {
|
||||
terrains_pattern = selected_terrains_pattern;
|
||||
}
|
||||
|
||||
RBSet<Vector2i> cells_to_draw = _get_cells_for_bucket_fill(p_coords, p_contiguous);
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> to_draw;
|
||||
for (const Vector2i &coords : cells_to_draw) {
|
||||
to_draw[coords] = terrains_pattern;
|
||||
Vector<Vector2i> cells_to_draw_as_vector;
|
||||
for (Vector2i cell : cells_to_draw) {
|
||||
cells_to_draw_as_vector.append(cell);
|
||||
}
|
||||
|
||||
return _draw_terrains(to_draw, selected_terrain_set);
|
||||
if (selected_type == SELECTED_TYPE_CONNECT || selected_type == SELECTED_TYPE_PATH) {
|
||||
return _draw_terrain_path_or_connect(cells_to_draw_as_vector, selected_terrain_set, selected_terrain, true);
|
||||
} else { // SELECTED_TYPE_PATTERN
|
||||
TileSet::TerrainsPattern terrains_pattern;
|
||||
if (p_erase) {
|
||||
terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
|
||||
} else {
|
||||
terrains_pattern = selected_terrains_pattern;
|
||||
}
|
||||
return _draw_terrain_pattern(cells_to_draw_as_vector, selected_terrain_set, terrains_pattern);
|
||||
}
|
||||
}
|
||||
|
||||
void TileMapEditorTerrainsPlugin::_stop_dragging() {
|
||||
|
@ -2696,11 +2687,13 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
|
|||
if (tree_item) {
|
||||
for (int i = 0; i < terrains_tile_list->get_item_count(); i++) {
|
||||
Dictionary metadata_dict = terrains_tile_list->get_item_metadata(i);
|
||||
TileSet::TerrainsPattern in_meta_terrains_pattern(*tile_set, new_terrain_set);
|
||||
in_meta_terrains_pattern.set_terrains_from_array(metadata_dict["terrains_pattern"]);
|
||||
if (in_meta_terrains_pattern == terrains_pattern) {
|
||||
terrains_tile_list->select(i);
|
||||
break;
|
||||
if (int(metadata_dict["type"]) == SELECTED_TYPE_PATTERN) {
|
||||
TileSet::TerrainsPattern in_meta_terrains_pattern(*tile_set, new_terrain_set);
|
||||
in_meta_terrains_pattern.from_array(metadata_dict["terrains_pattern"]);
|
||||
if (in_meta_terrains_pattern == terrains_pattern) {
|
||||
terrains_tile_list->select(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2773,22 +2766,33 @@ void TileMapEditorTerrainsPlugin::_update_selection() {
|
|||
}
|
||||
|
||||
// Get the selected terrain.
|
||||
selected_terrains_pattern = TileSet::TerrainsPattern();
|
||||
selected_terrain_set = -1;
|
||||
selected_terrains_pattern = TileSet::TerrainsPattern();
|
||||
|
||||
TreeItem *selected_tree_item = terrains_tree->get_selected();
|
||||
if (selected_tree_item && selected_tree_item->get_metadata(0)) {
|
||||
Dictionary metadata_dict = selected_tree_item->get_metadata(0);
|
||||
// Selected terrain
|
||||
selected_terrain_set = metadata_dict["terrain_set"];
|
||||
selected_terrain = metadata_dict["terrain_id"];
|
||||
|
||||
// Selected tile
|
||||
// Selected mode/terrain pattern
|
||||
if (erase_button->is_pressed()) {
|
||||
selected_type = SELECTED_TYPE_PATTERN;
|
||||
selected_terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
|
||||
} else if (terrains_tile_list->is_anything_selected()) {
|
||||
metadata_dict = terrains_tile_list->get_item_metadata(terrains_tile_list->get_selected_items()[0]);
|
||||
selected_terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
|
||||
selected_terrains_pattern.set_terrains_from_array(metadata_dict["terrains_pattern"]);
|
||||
if (int(metadata_dict["type"]) == SELECTED_TYPE_CONNECT) {
|
||||
selected_type = SELECTED_TYPE_CONNECT;
|
||||
} else if (int(metadata_dict["type"]) == SELECTED_TYPE_PATH) {
|
||||
selected_type = SELECTED_TYPE_PATH;
|
||||
} else if (int(metadata_dict["type"]) == SELECTED_TYPE_PATTERN) {
|
||||
selected_type = SELECTED_TYPE_PATTERN;
|
||||
selected_terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
|
||||
selected_terrains_pattern.from_array(metadata_dict["terrains_pattern"]);
|
||||
} else {
|
||||
ERR_FAIL();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2865,7 +2869,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
|
|||
} else {
|
||||
// Paint otherwise.
|
||||
if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
|
||||
if (selected_terrain_set < 0 || !selected_terrains_pattern.is_valid()) {
|
||||
if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2880,21 +2884,21 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
|
|||
tile_map->set_cell(tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
|
||||
}
|
||||
} else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CTRL))) {
|
||||
if (selected_terrain_set < 0 || !selected_terrains_pattern.is_valid()) {
|
||||
if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) {
|
||||
return true;
|
||||
}
|
||||
drag_type = DRAG_TYPE_LINE;
|
||||
drag_start_mouse_pos = mpos;
|
||||
drag_modified.clear();
|
||||
} else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CTRL))) {
|
||||
if (selected_terrain_set < 0 || !selected_terrains_pattern.is_valid()) {
|
||||
if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) {
|
||||
return true;
|
||||
}
|
||||
drag_type = DRAG_TYPE_RECT;
|
||||
drag_start_mouse_pos = mpos;
|
||||
drag_modified.clear();
|
||||
} else if (tool_buttons_group->get_pressed_button() == bucket_tool_button) {
|
||||
if (selected_terrain_set < 0 || !selected_terrains_pattern.is_valid()) {
|
||||
if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) {
|
||||
return true;
|
||||
}
|
||||
drag_type = DRAG_TYPE_BUCKET;
|
||||
|
@ -3105,11 +3109,18 @@ void TileMapEditorTerrainsPlugin::_update_terrains_cache() {
|
|||
cell.alternative_tile = alternative_id;
|
||||
|
||||
TileSet::TerrainsPattern terrains_pattern = tile_data->get_terrains_pattern();
|
||||
|
||||
// Terrain center bit
|
||||
int terrain = terrains_pattern.get_terrain();
|
||||
if (terrain >= 0 && terrain < (int)per_terrain_terrains_patterns[terrain_set].size()) {
|
||||
per_terrain_terrains_patterns[terrain_set][terrain].insert(terrains_pattern);
|
||||
}
|
||||
|
||||
// Terrain bits.
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
|
||||
int terrain = terrains_pattern.get_terrain(bit);
|
||||
if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
|
||||
terrain = terrains_pattern.get_terrain_peering_bit(bit);
|
||||
if (terrain >= 0 && terrain < (int)per_terrain_terrains_patterns[terrain_set].size()) {
|
||||
per_terrain_terrains_patterns[terrain_set][terrain].insert(terrains_pattern);
|
||||
}
|
||||
|
@ -3191,6 +3202,19 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
|
|||
ERR_FAIL_INDEX(selected_terrain_set, tile_set->get_terrain_sets_count());
|
||||
ERR_FAIL_INDEX(selected_terrain_id, tile_set->get_terrains_count(selected_terrain_set));
|
||||
|
||||
// Add the two first generic modes
|
||||
int item_index = terrains_tile_list->add_icon_item(main_vbox_container->get_theme_icon(SNAME("TerrainConnect"), SNAME("EditorIcons")));
|
||||
terrains_tile_list->set_item_tooltip(item_index, TTR("Connect mode: paints a terrain, then connects it with the surrounding tiles with the same terrain."));
|
||||
Dictionary list_metadata_dict;
|
||||
list_metadata_dict["type"] = SELECTED_TYPE_CONNECT;
|
||||
terrains_tile_list->set_item_metadata(item_index, list_metadata_dict);
|
||||
|
||||
item_index = terrains_tile_list->add_icon_item(main_vbox_container->get_theme_icon(SNAME("TerrainPath"), SNAME("EditorIcons")));
|
||||
terrains_tile_list->set_item_tooltip(item_index, TTR("Path mode: paints a terrain, thens connects it to the previous tile painted withing the same stroke."));
|
||||
list_metadata_dict = Dictionary();
|
||||
list_metadata_dict["type"] = SELECTED_TYPE_PATH;
|
||||
terrains_tile_list->set_item_metadata(item_index, list_metadata_dict);
|
||||
|
||||
// Sort the items in a map by the number of corresponding terrains.
|
||||
RBMap<int, RBSet<TileSet::TerrainsPattern>> sorted;
|
||||
|
||||
|
@ -3200,7 +3224,7 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
|
|||
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(selected_terrain_set, bit) && E.get_terrain(bit) == selected_terrain_id) {
|
||||
if (tile_set->is_valid_terrain_peering_bit(selected_terrain_set, bit) && E.get_terrain_peering_bit(bit) == selected_terrain_id) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
@ -3241,12 +3265,13 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
|
|||
}
|
||||
|
||||
// Create the ItemList's item.
|
||||
int item_index = terrains_tile_list->add_item("");
|
||||
item_index = terrains_tile_list->add_item("");
|
||||
terrains_tile_list->set_item_icon(item_index, icon);
|
||||
terrains_tile_list->set_item_icon_region(item_index, region);
|
||||
terrains_tile_list->set_item_icon_transposed(item_index, transpose);
|
||||
Dictionary list_metadata_dict;
|
||||
list_metadata_dict["terrains_pattern"] = terrains_pattern.get_terrains_as_array();
|
||||
list_metadata_dict = Dictionary();
|
||||
list_metadata_dict["type"] = SELECTED_TYPE_PATTERN;
|
||||
list_metadata_dict["terrains_pattern"] = terrains_pattern.as_array();
|
||||
terrains_tile_list->set_item_metadata(item_index, list_metadata_dict);
|
||||
}
|
||||
}
|
||||
|
@ -3264,6 +3289,8 @@ void TileMapEditorTerrainsPlugin::_update_theme() {
|
|||
|
||||
picker_button->set_icon(main_vbox_container->get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
|
||||
erase_button->set_icon(main_vbox_container->get_theme_icon(SNAME("Eraser"), SNAME("EditorIcons")));
|
||||
|
||||
_update_tiles_list();
|
||||
}
|
||||
|
||||
void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) {
|
||||
|
@ -3303,7 +3330,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
|
|||
terrains_tile_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
terrains_tile_list->set_max_columns(0);
|
||||
terrains_tile_list->set_same_column_width(true);
|
||||
terrains_tile_list->set_fixed_icon_size(Size2(30, 30) * EDSCALE);
|
||||
terrains_tile_list->set_fixed_icon_size(Size2(32, 32) * EDSCALE);
|
||||
terrains_tile_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
|
||||
tilemap_tab_terrains->add_child(terrains_tile_list);
|
||||
|
||||
|
|
|
@ -268,14 +268,22 @@ private:
|
|||
HashMap<Vector2i, TileMapCell> drag_modified;
|
||||
|
||||
// Painting
|
||||
HashMap<Vector2i, TileMapCell> _draw_terrains(const HashMap<Vector2i, TileSet::TerrainsPattern> &p_to_paint, int p_terrain_set) const;
|
||||
HashMap<Vector2i, TileMapCell> _draw_terrain_path_or_connect(const Vector<Vector2i> &p_to_paint, int p_terrain_set, int p_terrain, bool p_connect) const;
|
||||
HashMap<Vector2i, TileMapCell> _draw_terrain_pattern(const Vector<Vector2i> &p_to_paint, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const;
|
||||
HashMap<Vector2i, TileMapCell> _draw_line(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase);
|
||||
HashMap<Vector2i, TileMapCell> _draw_rect(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase);
|
||||
RBSet<Vector2i> _get_cells_for_bucket_fill(Vector2i p_coords, bool p_contiguous);
|
||||
HashMap<Vector2i, TileMapCell> _draw_bucket_fill(Vector2i p_coords, bool p_contiguous, bool p_erase);
|
||||
void _stop_dragging();
|
||||
|
||||
enum SelectedType {
|
||||
SELECTED_TYPE_CONNECT = 0,
|
||||
SELECTED_TYPE_PATH,
|
||||
SELECTED_TYPE_PATTERN,
|
||||
};
|
||||
SelectedType selected_type;
|
||||
int selected_terrain_set = -1;
|
||||
int selected_terrain = -1;
|
||||
TileSet::TerrainsPattern selected_terrains_pattern;
|
||||
void _update_selection();
|
||||
|
||||
|
|
|
@ -2071,9 +2071,10 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
|
|||
}
|
||||
} else if (p_property == "terrain_set") {
|
||||
int current_terrain_set = tile_data_proxy->get("terrain_set");
|
||||
ADD_UNDO(tile_data_proxy, "terrain");
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(current_terrain_set, bit)) {
|
||||
if (tile_set->is_valid_terrain_peering_bit(current_terrain_set, bit)) {
|
||||
ADD_UNDO(tile_data_proxy, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -505,7 +505,7 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
|
|||
for (int terrain_set_index = begin; terrain_set_index < end; terrain_set_index++) {
|
||||
for (int l = 0; l < TileSet::CELL_NEIGHBOR_MAX; l++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(l);
|
||||
if (tile_data->is_valid_peering_bit_terrain(bit)) {
|
||||
if (tile_data->is_valid_terrain_peering_bit(bit)) {
|
||||
ADD_UNDO(tile_data, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[l]));
|
||||
}
|
||||
}
|
||||
|
@ -513,7 +513,7 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
|
|||
} else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "terrain_") {
|
||||
for (int terrain_index = 0; terrain_index < TileSet::CELL_NEIGHBOR_MAX; terrain_index++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(terrain_index);
|
||||
if (tile_data->is_valid_peering_bit_terrain(bit)) {
|
||||
if (tile_data->is_valid_terrain_peering_bit(bit)) {
|
||||
ADD_UNDO(tile_data, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[terrain_index]));
|
||||
}
|
||||
}
|
||||
|
@ -607,9 +607,10 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p
|
|||
|
||||
if (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "mode") {
|
||||
ADD_UNDO(tile_data, "terrain_set");
|
||||
ADD_UNDO(tile_data, "terrain");
|
||||
for (int l = 0; l < TileSet::CELL_NEIGHBOR_MAX; l++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(l);
|
||||
if (tile_data->is_valid_peering_bit_terrain(bit)) {
|
||||
if (tile_data->is_valid_terrain_peering_bit(bit)) {
|
||||
ADD_UNDO(tile_data, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[l]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,27 +36,30 @@
|
|||
|
||||
HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlapping_coords_and_peering_bits() const {
|
||||
HashMap<Vector2i, TileSet::CellNeighbor> output;
|
||||
|
||||
ERR_FAIL_COND_V(is_center_bit(), output);
|
||||
|
||||
Ref<TileSet> tile_set = tile_map->get_tileset();
|
||||
ERR_FAIL_COND_V(!tile_set.is_valid(), output);
|
||||
|
||||
TileSet::TileShape shape = tile_set->get_tile_shape();
|
||||
if (shape == TileSet::TILE_SHAPE_SQUARE) {
|
||||
switch (bit) {
|
||||
case 0:
|
||||
case 1:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
|
||||
|
@ -67,23 +70,23 @@ HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlap
|
|||
}
|
||||
} else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
|
||||
switch (bit) {
|
||||
case 0:
|
||||
case 1:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_CORNER)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_CORNER;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
|
||||
break;
|
||||
|
@ -95,25 +98,25 @@ HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlap
|
|||
TileSet::TileOffsetAxis offset_axis = tile_set->get_tile_offset_axis();
|
||||
if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
|
||||
switch (bit) {
|
||||
case 0:
|
||||
case 1:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_CORNER;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
|
||||
break;
|
||||
|
@ -122,25 +125,25 @@ HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlap
|
|||
}
|
||||
} else {
|
||||
switch (bit) {
|
||||
case 0:
|
||||
case 1:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
|
||||
output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
|
||||
break;
|
||||
|
@ -152,6 +155,17 @@ HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlap
|
|||
return output;
|
||||
}
|
||||
|
||||
TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain) {
|
||||
tile_map = p_tile_map;
|
||||
|
||||
Ref<TileSet> tile_set = tile_map->get_tileset();
|
||||
ERR_FAIL_COND(!tile_set.is_valid());
|
||||
|
||||
bit = 0;
|
||||
base_cell_coords = p_position;
|
||||
terrain = p_terrain;
|
||||
}
|
||||
|
||||
TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain) {
|
||||
// The way we build the constraint make it easy to detect conflicting constraints.
|
||||
tile_map = p_tile_map;
|
||||
|
@ -163,35 +177,35 @@ TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const V
|
|||
if (shape == TileSet::TILE_SHAPE_SQUARE) {
|
||||
switch (p_bit) {
|
||||
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
|
||||
bit = 0;
|
||||
bit = 1;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
|
||||
bit = 1;
|
||||
bit = 2;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
|
||||
bit = 2;
|
||||
bit = 3;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
|
||||
bit = 1;
|
||||
bit = 2;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
|
||||
bit = 0;
|
||||
bit = 1;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
|
||||
bit = 1;
|
||||
bit = 2;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_SIDE:
|
||||
bit = 2;
|
||||
bit = 3;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
|
||||
bit = 1;
|
||||
bit = 2;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
|
||||
break;
|
||||
default:
|
||||
|
@ -201,35 +215,35 @@ TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const V
|
|||
} else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
|
||||
switch (p_bit) {
|
||||
case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
|
||||
bit = 1;
|
||||
bit = 2;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
|
||||
bit = 0;
|
||||
bit = 1;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
|
||||
bit = 1;
|
||||
bit = 2;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
|
||||
bit = 2;
|
||||
bit = 3;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
|
||||
bit = 1;
|
||||
bit = 2;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
|
||||
bit = 0;
|
||||
bit = 1;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_CORNER:
|
||||
bit = 1;
|
||||
bit = 2;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_CORNER);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
|
||||
bit = 2;
|
||||
bit = 3;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
|
||||
break;
|
||||
default:
|
||||
|
@ -242,51 +256,51 @@ TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const V
|
|||
if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
|
||||
switch (p_bit) {
|
||||
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
|
||||
bit = 0;
|
||||
bit = 1;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
|
||||
bit = 1;
|
||||
bit = 2;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
|
||||
bit = 2;
|
||||
bit = 3;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
|
||||
bit = 3;
|
||||
bit = 4;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
|
||||
bit = 4;
|
||||
bit = 5;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
|
||||
bit = 1;
|
||||
bit = 2;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
|
||||
bit = 0;
|
||||
bit = 1;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
|
||||
bit = 3;
|
||||
bit = 4;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
|
||||
bit = 2;
|
||||
bit = 3;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_CORNER:
|
||||
bit = 1;
|
||||
bit = 2;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
|
||||
bit = 4;
|
||||
bit = 5;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
|
||||
bit = 3;
|
||||
bit = 4;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
|
||||
break;
|
||||
default:
|
||||
|
@ -296,51 +310,51 @@ TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const V
|
|||
} else {
|
||||
switch (p_bit) {
|
||||
case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
|
||||
bit = 0;
|
||||
bit = 1;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
|
||||
bit = 1;
|
||||
bit = 2;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
|
||||
bit = 2;
|
||||
bit = 3;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
|
||||
bit = 3;
|
||||
bit = 4;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
|
||||
bit = 0;
|
||||
bit = 1;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
|
||||
bit = 4;
|
||||
bit = 5;
|
||||
base_cell_coords = p_position;
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
|
||||
bit = 2;
|
||||
bit = 3;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
|
||||
bit = 1;
|
||||
bit = 2;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
|
||||
bit = 0;
|
||||
bit = 1;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_SIDE:
|
||||
bit = 3;
|
||||
bit = 4;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
|
||||
bit = 2;
|
||||
bit = 3;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
|
||||
break;
|
||||
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
|
||||
bit = 4;
|
||||
bit = 5;
|
||||
base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
|
||||
break;
|
||||
default:
|
||||
|
@ -2149,37 +2163,75 @@ void TileMap::set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPat
|
|||
}
|
||||
}
|
||||
|
||||
RBSet<TileSet::TerrainsPattern> TileMap::_get_valid_terrains_patterns_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints) {
|
||||
TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints) {
|
||||
if (!tile_set.is_valid()) {
|
||||
return RBSet<TileSet::TerrainsPattern>();
|
||||
return TileSet::TerrainsPattern();
|
||||
}
|
||||
|
||||
// Returns all tiles compatible with the given constraints.
|
||||
RBSet<TileSet::TerrainsPattern> compatible_terrain_tile_patterns;
|
||||
for (TileSet::TerrainsPattern &terrain_pattern : tile_set->get_terrains_pattern_set(p_terrain_set)) {
|
||||
int valid = true;
|
||||
RBMap<TileSet::TerrainsPattern, int> terrain_pattern_score;
|
||||
RBSet<TileSet::TerrainsPattern> pattern_set = tile_set->get_terrains_pattern_set(p_terrain_set);
|
||||
ERR_FAIL_COND_V(pattern_set.is_empty(), TileSet::TerrainsPattern());
|
||||
for (TileSet::TerrainsPattern &terrain_pattern : pattern_set) {
|
||||
int score = 0;
|
||||
|
||||
// Check the center bit constraint
|
||||
TerrainConstraint terrain_constraint = TerrainConstraint(this, p_position, terrain_pattern.get_terrain());
|
||||
RBSet<TerrainConstraint>::Element *in_set_constraint_element = p_constraints.find(terrain_constraint);
|
||||
if (in_set_constraint_element && in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) {
|
||||
score += in_set_constraint_element->get().get_priority();
|
||||
}
|
||||
|
||||
// Check the surrounding bits
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, bit)) {
|
||||
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
|
||||
// Check if the bit is compatible with the constraints.
|
||||
TerrainConstraint terrain_bit_constraint = TerrainConstraint(this, p_position, bit, terrain_pattern.get_terrain(bit));
|
||||
RBSet<TerrainConstraint>::Element *in_set_constraint_element = p_constraints.find(terrain_bit_constraint);
|
||||
TerrainConstraint terrain_bit_constraint = TerrainConstraint(this, p_position, bit, terrain_pattern.get_terrain_peering_bit(bit));
|
||||
in_set_constraint_element = p_constraints.find(terrain_bit_constraint);
|
||||
if (in_set_constraint_element && in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) {
|
||||
valid = false;
|
||||
break;
|
||||
score += in_set_constraint_element->get().get_priority();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
compatible_terrain_tile_patterns.insert(terrain_pattern);
|
||||
terrain_pattern_score[terrain_pattern] = score;
|
||||
}
|
||||
|
||||
// Compute the minimum score
|
||||
TileSet::TerrainsPattern min_score_pattern;
|
||||
int min_score = INT32_MAX;
|
||||
for (KeyValue<TileSet::TerrainsPattern, int> E : terrain_pattern_score) {
|
||||
if (E.value < min_score) {
|
||||
min_score_pattern = E.key;
|
||||
min_score = E.value;
|
||||
}
|
||||
}
|
||||
|
||||
return compatible_terrain_tile_patterns;
|
||||
return min_score_pattern;
|
||||
}
|
||||
|
||||
RBSet<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_removed_cells_list(int p_layer, const RBSet<Vector2i> &p_to_replace, int p_terrain_set, bool p_ignore_empty_terrains) const {
|
||||
RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_added_pattern(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const {
|
||||
if (!tile_set.is_valid()) {
|
||||
return RBSet<TerrainConstraint>();
|
||||
}
|
||||
|
||||
// Compute the constraints needed from the surrounding tiles.
|
||||
RBSet<TerrainConstraint> output;
|
||||
output.insert(TerrainConstraint(this, p_position, p_terrains_pattern.get_terrain()));
|
||||
|
||||
for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor side = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, side)) {
|
||||
TerrainConstraint c = TerrainConstraint(this, p_position, side, p_terrains_pattern.get_terrain_peering_bit(side));
|
||||
output.insert(c);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_list(int p_layer, const RBSet<Vector2i> &p_cell_list, int p_terrain_set, bool p_ignore_empty_terrains) const {
|
||||
if (!tile_set.is_valid()) {
|
||||
return RBSet<TerrainConstraint>();
|
||||
}
|
||||
|
@ -2187,12 +2239,12 @@ RBSet<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_removed_
|
|||
ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), RBSet<TerrainConstraint>());
|
||||
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), RBSet<TerrainConstraint>());
|
||||
|
||||
// Build a set of dummy constraints get the constrained points.
|
||||
// Build a set of dummy constraints to get the constrained points.
|
||||
RBSet<TerrainConstraint> dummy_constraints;
|
||||
for (const Vector2i &E : p_to_replace) {
|
||||
for (const Vector2i &E : p_cell_list) {
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over sides.
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, bit)) {
|
||||
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
|
||||
dummy_constraints.insert(TerrainConstraint(this, E, bit, -1));
|
||||
}
|
||||
}
|
||||
|
@ -2200,35 +2252,31 @@ RBSet<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_removed_
|
|||
|
||||
// For each constrained point, we get all overlapping tiles, and select the most adequate terrain for it.
|
||||
RBSet<TerrainConstraint> constraints;
|
||||
for (const TerrainConstraint &E : dummy_constraints) {
|
||||
TerrainConstraint c = E;
|
||||
|
||||
for (const TerrainConstraint &E_constraint : dummy_constraints) {
|
||||
HashMap<int, int> terrain_count;
|
||||
|
||||
// Count the number of occurrences per terrain.
|
||||
HashMap<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = c.get_overlapping_coords_and_peering_bits();
|
||||
HashMap<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = E_constraint.get_overlapping_coords_and_peering_bits();
|
||||
for (const KeyValue<Vector2i, TileSet::CellNeighbor> &E_overlapping : overlapping_terrain_bits) {
|
||||
if (!p_to_replace.has(E_overlapping.key)) {
|
||||
TileData *neighbor_tile_data = nullptr;
|
||||
TileMapCell neighbor_cell = get_cell(p_layer, E_overlapping.key);
|
||||
if (neighbor_cell.source_id != TileSet::INVALID_SOURCE) {
|
||||
Ref<TileSetSource> source = tile_set->get_source(neighbor_cell.source_id);
|
||||
Ref<TileSetAtlasSource> atlas_source = source;
|
||||
if (atlas_source.is_valid()) {
|
||||
TileData *tile_data = atlas_source->get_tile_data(neighbor_cell.get_atlas_coords(), neighbor_cell.alternative_tile);
|
||||
if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
|
||||
neighbor_tile_data = tile_data;
|
||||
}
|
||||
TileData *neighbor_tile_data = nullptr;
|
||||
TileMapCell neighbor_cell = get_cell(p_layer, E_overlapping.key);
|
||||
if (neighbor_cell.source_id != TileSet::INVALID_SOURCE) {
|
||||
Ref<TileSetSource> source = tile_set->get_source(neighbor_cell.source_id);
|
||||
Ref<TileSetAtlasSource> atlas_source = source;
|
||||
if (atlas_source.is_valid()) {
|
||||
TileData *tile_data = atlas_source->get_tile_data(neighbor_cell.get_atlas_coords(), neighbor_cell.alternative_tile);
|
||||
if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
|
||||
neighbor_tile_data = tile_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int terrain = neighbor_tile_data ? neighbor_tile_data->get_peering_bit_terrain(TileSet::CellNeighbor(E_overlapping.value)) : -1;
|
||||
if (!p_ignore_empty_terrains || terrain >= 0) {
|
||||
if (!terrain_count.has(terrain)) {
|
||||
terrain_count[terrain] = 0;
|
||||
}
|
||||
terrain_count[terrain] += 1;
|
||||
int terrain = neighbor_tile_data ? neighbor_tile_data->get_terrain_peering_bit(TileSet::CellNeighbor(E_overlapping.value)) : -1;
|
||||
if (!p_ignore_empty_terrains || terrain >= 0) {
|
||||
if (!terrain_count.has(terrain)) {
|
||||
terrain_count[terrain] = 0;
|
||||
}
|
||||
terrain_count[terrain] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2244,33 +2292,34 @@ RBSet<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_removed_
|
|||
|
||||
// Set the adequate terrain.
|
||||
if (max > 0) {
|
||||
TerrainConstraint c = E_constraint;
|
||||
c.set_terrain(max_terrain);
|
||||
constraints.insert(c);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the centers as constraints
|
||||
for (Vector2i E_coords : p_cell_list) {
|
||||
TileData *tile_data = nullptr;
|
||||
TileMapCell cell = get_cell(p_layer, E_coords);
|
||||
if (cell.source_id != TileSet::INVALID_SOURCE) {
|
||||
Ref<TileSetSource> source = tile_set->get_source(cell.source_id);
|
||||
Ref<TileSetAtlasSource> atlas_source = source;
|
||||
if (atlas_source.is_valid()) {
|
||||
tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
|
||||
}
|
||||
}
|
||||
|
||||
int terrain = (tile_data && tile_data->get_terrain_set() == p_terrain_set) ? tile_data->get_terrain() : -1;
|
||||
if (!p_ignore_empty_terrains || terrain >= 0) {
|
||||
constraints.insert(TerrainConstraint(this, E_coords, terrain));
|
||||
}
|
||||
}
|
||||
|
||||
return constraints;
|
||||
}
|
||||
|
||||
RBSet<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_added_tile(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const {
|
||||
if (!tile_set.is_valid()) {
|
||||
return RBSet<TerrainConstraint>();
|
||||
}
|
||||
|
||||
// Compute the constraints needed from the surrounding tiles.
|
||||
RBSet<TerrainConstraint> output;
|
||||
for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor side = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, side)) {
|
||||
TerrainConstraint c = TerrainConstraint(this, p_position, side, p_terrains_pattern.get_terrain(side));
|
||||
output.insert(c);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_wave_function_collapse(const RBSet<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints) {
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints) {
|
||||
if (!tile_set.is_valid()) {
|
||||
return HashMap<Vector2i, TileSet::TerrainsPattern>();
|
||||
}
|
||||
|
@ -2278,110 +2327,287 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_wave_function_colla
|
|||
// Copy the constraints set.
|
||||
RBSet<TerrainConstraint> constraints = p_constraints;
|
||||
|
||||
// Compute all acceptable patterns for each cell.
|
||||
HashMap<Vector2i, RBSet<TileSet::TerrainsPattern>> per_cell_acceptable_tiles;
|
||||
for (Vector2i cell : p_to_replace) {
|
||||
per_cell_acceptable_tiles[cell] = _get_valid_terrains_patterns_for_constraints(p_terrain_set, cell, constraints);
|
||||
}
|
||||
|
||||
// Output map.
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> output;
|
||||
|
||||
// Add all positions to a set.
|
||||
RBSet<Vector2i> to_replace = RBSet<Vector2i>(p_to_replace);
|
||||
while (!to_replace.is_empty()) {
|
||||
// Compute the minimum number of tile possibilities for each cell.
|
||||
int min_nb_possibilities = 100000000;
|
||||
for (const KeyValue<Vector2i, RBSet<TileSet::TerrainsPattern>> &E : per_cell_acceptable_tiles) {
|
||||
min_nb_possibilities = MIN(min_nb_possibilities, E.value.size());
|
||||
}
|
||||
for (int i = 0; i < p_to_replace.size(); i++) {
|
||||
const Vector2i &coords = p_to_replace[i];
|
||||
|
||||
// Get the set of possible cells to fill, out of the most constrained ones.
|
||||
LocalVector<Vector2i> to_choose_from;
|
||||
for (const KeyValue<Vector2i, RBSet<TileSet::TerrainsPattern>> &E : per_cell_acceptable_tiles) {
|
||||
if (E.value.size() == min_nb_possibilities) {
|
||||
to_choose_from.push_back(E.key);
|
||||
}
|
||||
}
|
||||
// Select the best pattern for the given constraints
|
||||
TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints);
|
||||
|
||||
// Randomly a cell to fill out of the most constrained.
|
||||
Vector2i selected_cell_to_replace = to_choose_from[Math::random(0, to_choose_from.size() - 1)];
|
||||
|
||||
// Get the list of acceptable patterns for the given cell.
|
||||
RBSet<TileSet::TerrainsPattern> valid_tiles = per_cell_acceptable_tiles[selected_cell_to_replace];
|
||||
if (valid_tiles.is_empty()) {
|
||||
break; // No possibilities :/
|
||||
}
|
||||
|
||||
// Out of the possible patterns, prioritize the one which have the least amount of different terrains.
|
||||
LocalVector<TileSet::TerrainsPattern> valid_tiles_with_least_amount_of_terrains;
|
||||
int min_terrain_count = 10000;
|
||||
LocalVector<int> terrains_counts;
|
||||
int pattern_index = 0;
|
||||
for (const TileSet::TerrainsPattern &pattern : valid_tiles) {
|
||||
RBSet<int> terrains;
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor side = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, side)) {
|
||||
terrains.insert(pattern.get_terrain(side));
|
||||
}
|
||||
}
|
||||
min_terrain_count = MIN(min_terrain_count, terrains.size());
|
||||
terrains_counts.push_back(terrains.size());
|
||||
pattern_index++;
|
||||
}
|
||||
pattern_index = 0;
|
||||
for (const TileSet::TerrainsPattern &pattern : valid_tiles) {
|
||||
if (terrains_counts[pattern_index] == min_terrain_count) {
|
||||
valid_tiles_with_least_amount_of_terrains.push_back(pattern);
|
||||
}
|
||||
pattern_index++;
|
||||
}
|
||||
|
||||
// Randomly select a pattern out of the remaining ones.
|
||||
TileSet::TerrainsPattern selected_terrain_tile_pattern = valid_tiles_with_least_amount_of_terrains[Math::random(0, valid_tiles_with_least_amount_of_terrains.size() - 1)];
|
||||
|
||||
// Set the selected cell into the output.
|
||||
output[selected_cell_to_replace] = selected_terrain_tile_pattern;
|
||||
to_replace.erase(selected_cell_to_replace);
|
||||
per_cell_acceptable_tiles.erase(selected_cell_to_replace);
|
||||
|
||||
// Add the new constraints from the added tiles.
|
||||
RBSet<TerrainConstraint> new_constraints = get_terrain_constraints_from_added_tile(selected_cell_to_replace, p_terrain_set, selected_terrain_tile_pattern);
|
||||
// Update the constraint set with the new ones
|
||||
RBSet<TerrainConstraint> new_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, pattern);
|
||||
for (const TerrainConstraint &E_constraint : new_constraints) {
|
||||
constraints.insert(E_constraint);
|
||||
if (constraints.has(E_constraint)) {
|
||||
constraints.erase(E_constraint);
|
||||
}
|
||||
TerrainConstraint c = E_constraint;
|
||||
c.set_priority(5);
|
||||
constraints.insert(c);
|
||||
}
|
||||
|
||||
// Compute valid tiles again for neighbors.
|
||||
for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor side = TileSet::CellNeighbor(i);
|
||||
if (is_existing_neighbor(side)) {
|
||||
Vector2i neighbor = get_neighbor_cell(selected_cell_to_replace, side);
|
||||
if (to_replace.has(neighbor)) {
|
||||
per_cell_acceptable_tiles[neighbor] = _get_valid_terrains_patterns_for_constraints(p_terrain_set, neighbor, constraints);
|
||||
}
|
||||
}
|
||||
}
|
||||
output[coords] = pattern;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
void TileMap::set_cells_from_surrounding_terrains(int p_layer, TypedArray<Vector2i> p_coords_array, int p_terrain_set, bool p_ignore_empty_terrains) {
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> output;
|
||||
ERR_FAIL_COND_V(!tile_set.is_valid(), output);
|
||||
ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output);
|
||||
|
||||
// Build list and set of tiles that can be modified (painted and their surroundings)
|
||||
Vector<Vector2i> can_modify_list;
|
||||
RBSet<Vector2i> can_modify_set;
|
||||
RBSet<Vector2i> painted_set;
|
||||
for (int i = p_coords_array.size() - 1; i >= 0; i--) {
|
||||
const Vector2i &coords = p_coords_array[i];
|
||||
can_modify_list.push_back(coords);
|
||||
can_modify_set.insert(coords);
|
||||
painted_set.insert(coords);
|
||||
}
|
||||
for (Vector2i coords : p_coords_array) {
|
||||
// Find the adequate neighbor
|
||||
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
|
||||
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
|
||||
Vector2i neighbor = get_neighbor_cell(coords, bit);
|
||||
if (!can_modify_set.has(neighbor)) {
|
||||
can_modify_list.push_back(neighbor);
|
||||
can_modify_set.insert(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build a set, out of the possibly modified tiles, of the one with a center bit that is set (or will be) to the painted terrain
|
||||
RBSet<Vector2i> cells_with_terrain_center_bit;
|
||||
for (Vector2i coords : can_modify_set) {
|
||||
bool connect = false;
|
||||
if (painted_set.has(coords)) {
|
||||
connect = true;
|
||||
} else {
|
||||
// Get the center bit of the cell
|
||||
TileData *tile_data = nullptr;
|
||||
TileMapCell cell = get_cell(p_layer, coords);
|
||||
if (cell.source_id != TileSet::INVALID_SOURCE) {
|
||||
Ref<TileSetSource> source = tile_set->get_source(cell.source_id);
|
||||
Ref<TileSetAtlasSource> atlas_source = source;
|
||||
if (atlas_source.is_valid()) {
|
||||
tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
|
||||
}
|
||||
}
|
||||
|
||||
if (tile_data && tile_data->get_terrain_set() == p_terrain_set && tile_data->get_terrain() == p_terrain) {
|
||||
connect = true;
|
||||
}
|
||||
}
|
||||
if (connect) {
|
||||
cells_with_terrain_center_bit.insert(coords);
|
||||
}
|
||||
}
|
||||
|
||||
RBSet<TerrainConstraint> constraints;
|
||||
|
||||
// Add new constraints from the path drawn.
|
||||
for (Vector2i coords : p_coords_array) {
|
||||
// Constraints on the center bit.
|
||||
TerrainConstraint c = TerrainConstraint(this, coords, p_terrain);
|
||||
c.set_priority(10);
|
||||
constraints.insert(c);
|
||||
|
||||
// Constraints on the connecting bits.
|
||||
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
|
||||
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
|
||||
c = TerrainConstraint(this, coords, bit, p_terrain);
|
||||
c.set_priority(10);
|
||||
if ((int(bit) % 2) == 0) {
|
||||
// Side peering bits: add the constraint if the center is of the same terrain
|
||||
Vector2i neighbor = get_neighbor_cell(coords, bit);
|
||||
if (cells_with_terrain_center_bit.has(neighbor)) {
|
||||
constraints.insert(c);
|
||||
}
|
||||
} else {
|
||||
// Corner peering bits: add the constraint if all tiles on the constraint has the same center bit
|
||||
HashMap<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = c.get_overlapping_coords_and_peering_bits();
|
||||
bool valid = true;
|
||||
for (KeyValue<Vector2i, TileSet::CellNeighbor> kv : overlapping_terrain_bits) {
|
||||
if (!cells_with_terrain_center_bit.has(kv.key)) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valid) {
|
||||
constraints.insert(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fills in the constraint list from existing tiles.
|
||||
for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) {
|
||||
constraints.insert(c);
|
||||
}
|
||||
|
||||
// Fill the terrains.
|
||||
output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
|
||||
return output;
|
||||
}
|
||||
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_layer, const Vector<Vector2i> &p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> output;
|
||||
ERR_FAIL_COND_V(!tile_set.is_valid(), output);
|
||||
ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output);
|
||||
|
||||
// Make sure the path is correct and build the peering bit list while doing it.
|
||||
Vector<TileSet::CellNeighbor> neighbor_list;
|
||||
for (int i = 0; i < p_path.size() - 1; i++) {
|
||||
// Find the adequate neighbor
|
||||
TileSet::CellNeighbor found_bit = TileSet::CELL_NEIGHBOR_MAX;
|
||||
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
|
||||
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
|
||||
if (get_neighbor_cell(p_path[i], bit) == p_path[i + 1]) {
|
||||
found_bit = bit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ERR_FAIL_COND_V_MSG(found_bit == TileSet::CELL_NEIGHBOR_MAX, output, vformat("Invalid terrain path, %s is not a neighbouring tile of %s", p_path[i + 1], p_path[i]));
|
||||
neighbor_list.push_back(found_bit);
|
||||
}
|
||||
|
||||
// Build list and set of tiles that can be modified (painted and their surroundings)
|
||||
Vector<Vector2i> can_modify_list;
|
||||
RBSet<Vector2i> can_modify_set;
|
||||
for (int i = p_path.size() - 1; i >= 0; i--) {
|
||||
const Vector2i &coords = p_path[i];
|
||||
can_modify_list.push_back(coords);
|
||||
can_modify_set.insert(coords);
|
||||
}
|
||||
for (Vector2i coords : p_path) {
|
||||
// Find the adequate neighbor
|
||||
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
|
||||
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
|
||||
Vector2i neighbor = get_neighbor_cell(coords, bit);
|
||||
if (!can_modify_set.has(neighbor)) {
|
||||
can_modify_list.push_back(neighbor);
|
||||
can_modify_set.insert(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RBSet<TerrainConstraint> constraints;
|
||||
|
||||
// Add new constraints from the path drawn.
|
||||
for (Vector2i coords : p_path) {
|
||||
// Constraints on the center bit
|
||||
TerrainConstraint c = TerrainConstraint(this, coords, p_terrain);
|
||||
c.set_priority(10);
|
||||
constraints.insert(c);
|
||||
}
|
||||
for (int i = 0; i < p_path.size() - 1; i++) {
|
||||
// Constraints on the peering bits.
|
||||
TerrainConstraint c = TerrainConstraint(this, p_path[i], neighbor_list[i], p_terrain);
|
||||
c.set_priority(10);
|
||||
constraints.insert(c);
|
||||
}
|
||||
|
||||
// Fills in the constraint list from existing tiles.
|
||||
for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) {
|
||||
constraints.insert(c);
|
||||
}
|
||||
|
||||
// Fill the terrains.
|
||||
output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
|
||||
return output;
|
||||
}
|
||||
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains) {
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> output;
|
||||
ERR_FAIL_COND_V(!tile_set.is_valid(), output);
|
||||
ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output);
|
||||
|
||||
// Build list and set of tiles that can be modified (painted and their surroundings).
|
||||
Vector<Vector2i> can_modify_list;
|
||||
RBSet<Vector2i> can_modify_set;
|
||||
for (int i = p_coords_array.size() - 1; i >= 0; i--) {
|
||||
const Vector2i &coords = p_coords_array[i];
|
||||
can_modify_list.push_back(coords);
|
||||
can_modify_set.insert(coords);
|
||||
}
|
||||
for (Vector2i coords : p_coords_array) {
|
||||
// Find the adequate neighbor
|
||||
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
|
||||
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
|
||||
Vector2i neighbor = get_neighbor_cell(coords, bit);
|
||||
if (!can_modify_set.has(neighbor)) {
|
||||
can_modify_list.push_back(neighbor);
|
||||
can_modify_set.insert(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add constraint by the new ones.
|
||||
RBSet<TerrainConstraint> constraints;
|
||||
|
||||
// Add new constraints from the path drawn.
|
||||
for (Vector2i coords : p_coords_array) {
|
||||
// Constraints on the center bit
|
||||
RBSet<TerrainConstraint> added_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, p_terrains_pattern);
|
||||
for (TerrainConstraint c : added_constraints) {
|
||||
c.set_priority(10);
|
||||
constraints.insert(c);
|
||||
}
|
||||
}
|
||||
|
||||
// Fills in the constraint list from modified tiles border.
|
||||
for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) {
|
||||
constraints.insert(c);
|
||||
}
|
||||
|
||||
// Fill the terrains.
|
||||
output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
|
||||
return output;
|
||||
}
|
||||
|
||||
void TileMap::set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
|
||||
ERR_FAIL_COND(!tile_set.is_valid());
|
||||
ERR_FAIL_INDEX(p_layer, (int)layers.size());
|
||||
ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count());
|
||||
|
||||
RBSet<Vector2i> coords_set;
|
||||
for (int i = 0; i < p_coords_array.size(); i++) {
|
||||
coords_set.insert(p_coords_array[i]);
|
||||
Vector<Vector2i> vector_cells;
|
||||
for (int i = 0; i < p_cells.size(); i++) {
|
||||
vector_cells.push_back(p_cells[i]);
|
||||
}
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(p_layer, vector_cells, p_terrain_set, p_terrain, p_ignore_empty_terrains);
|
||||
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
|
||||
TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
|
||||
set_cell(p_layer, E.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
|
||||
}
|
||||
}
|
||||
|
||||
RBSet<TileMap::TerrainConstraint> constraints = get_terrain_constraints_from_removed_cells_list(p_layer, coords_set, p_terrain_set, p_ignore_empty_terrains);
|
||||
void TileMap::set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) {
|
||||
ERR_FAIL_COND(!tile_set.is_valid());
|
||||
ERR_FAIL_INDEX(p_layer, (int)layers.size());
|
||||
ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count());
|
||||
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> wfc_output = terrain_wave_function_collapse(coords_set, p_terrain_set, constraints);
|
||||
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : wfc_output) {
|
||||
TileMapCell cell = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
|
||||
set_cell(p_layer, kv.key, cell.source_id, cell.get_atlas_coords(), cell.alternative_tile);
|
||||
Vector<Vector2i> vector_path;
|
||||
for (int i = 0; i < p_path.size(); i++) {
|
||||
vector_path.push_back(p_path[i]);
|
||||
}
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_path(p_layer, vector_path, p_terrain_set, p_terrain, p_ignore_empty_terrains);
|
||||
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
|
||||
TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
|
||||
set_cell(p_layer, E.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3640,7 +3866,8 @@ void TileMap::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("map_pattern", "position_in_tilemap", "coords_in_pattern", "pattern"), &TileMap::map_pattern);
|
||||
ClassDB::bind_method(D_METHOD("set_pattern", "layer", "position", "pattern"), &TileMap::set_pattern);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_cells_from_surrounding_terrains", "layer", "cells", "terrain_set", "ignore_empty_terrains"), &TileMap::set_cells_from_surrounding_terrains, DEFVAL(true));
|
||||
ClassDB::bind_method(D_METHOD("set_cells_terrain_connect", "layer", "cells", "terrain_set", "terrain", "ignore_empty_terrains"), &TileMap::set_cells_terrain_connect, DEFVAL(true));
|
||||
ClassDB::bind_method(D_METHOD("set_cells_terrain_path", "layer", "path", "terrain_set", "terrain", "ignore_empty_terrains"), &TileMap::set_cells_terrain_path, DEFVAL(true));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("fix_invalid_tiles"), &TileMap::fix_invalid_tiles);
|
||||
ClassDB::bind_method(D_METHOD("clear_layer", "layer"), &TileMap::clear_layer);
|
||||
|
|
|
@ -119,6 +119,8 @@ public:
|
|||
int bit = -1;
|
||||
int terrain = -1;
|
||||
|
||||
int priority = 1;
|
||||
|
||||
public:
|
||||
bool operator<(const TerrainConstraint &p_other) const {
|
||||
if (base_cell_coords == p_other.base_cell_coords) {
|
||||
|
@ -128,13 +130,17 @@ public:
|
|||
}
|
||||
|
||||
String to_string() const {
|
||||
return vformat("Constraint {pos:%s, bit:%d, terrain:%d}", base_cell_coords, bit, terrain);
|
||||
return vformat("Constraint {pos:%s, bit:%d, terrain:%d, priotity:%d}", base_cell_coords, bit, terrain, priority);
|
||||
}
|
||||
|
||||
Vector2i get_base_cell_coords() const {
|
||||
return base_cell_coords;
|
||||
}
|
||||
|
||||
bool is_center_bit() const {
|
||||
return bit == 0;
|
||||
}
|
||||
|
||||
HashMap<Vector2i, TileSet::CellNeighbor> get_overlapping_coords_and_peering_bits() const;
|
||||
|
||||
void set_terrain(int p_terrain) {
|
||||
|
@ -145,8 +151,17 @@ public:
|
|||
return terrain;
|
||||
}
|
||||
|
||||
TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain);
|
||||
TerrainConstraint() {}
|
||||
void set_priority(int p_priority) {
|
||||
priority = p_priority;
|
||||
}
|
||||
|
||||
int get_priority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain); // For the center terrain bit
|
||||
TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain); // For peering bits
|
||||
TerrainConstraint(){};
|
||||
};
|
||||
|
||||
enum VisibilityMode {
|
||||
|
@ -251,7 +266,9 @@ private:
|
|||
void _scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant);
|
||||
|
||||
// Terrains.
|
||||
RBSet<TileSet::TerrainsPattern> _get_valid_terrains_patterns_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints);
|
||||
TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints);
|
||||
RBSet<TerrainConstraint> _get_terrain_constraints_from_added_pattern(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const;
|
||||
RBSet<TerrainConstraint> _get_terrain_constraints_from_cells_list(int p_layer, const RBSet<Vector2i> &p_on_map, int p_terrain_set, bool p_ignore_empty_terrains) const;
|
||||
|
||||
// Set and get tiles from data arrays.
|
||||
void _set_tile_data(int p_layer, const Vector<int> &p_data);
|
||||
|
@ -333,10 +350,13 @@ public:
|
|||
void set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPattern> p_pattern);
|
||||
|
||||
// Terrains.
|
||||
RBSet<TerrainConstraint> get_terrain_constraints_from_removed_cells_list(int p_layer, const RBSet<Vector2i> &p_to_replace, int p_terrain_set, bool p_ignore_empty_terrains = true) const; // Not exposed.
|
||||
RBSet<TerrainConstraint> get_terrain_constraints_from_added_tile(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const; // Not exposed.
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_wave_function_collapse(const RBSet<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints); // Not exposed.
|
||||
void set_cells_from_surrounding_terrains(int p_layer, TypedArray<Vector2i> p_coords_array, int p_terrain_set, bool p_ignore_empty_terrains = true);
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints); // Not exposed.
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_connect(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed.
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_path(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed.
|
||||
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true); // Not exposed.
|
||||
|
||||
void set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true);
|
||||
void set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true);
|
||||
|
||||
// Not exposed to users
|
||||
TileMapCell get_cell(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
|
||||
|
@ -365,7 +385,7 @@ public:
|
|||
// For finding tiles from collision.
|
||||
Vector2i get_coords_for_body_rid(RID p_physics_body);
|
||||
|
||||
// Fixing a nclearing methods.
|
||||
// Fixing and clearing methods.
|
||||
void fix_invalid_tiles();
|
||||
|
||||
// Clears tiles from a given layer
|
||||
|
|
|
@ -236,6 +236,9 @@ bool TileSet::TerrainsPattern::operator<(const TerrainsPattern &p_terrains_patte
|
|||
return is_valid_bit[i] < p_terrains_pattern.is_valid_bit[i];
|
||||
}
|
||||
}
|
||||
if (terrain != p_terrains_pattern.terrain) {
|
||||
return terrain < p_terrains_pattern.terrain;
|
||||
}
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
if (is_valid_bit[i] && bits[i] != p_terrains_pattern.bits[i]) {
|
||||
return bits[i] < p_terrains_pattern.bits[i];
|
||||
|
@ -253,10 +256,23 @@ bool TileSet::TerrainsPattern::operator==(const TerrainsPattern &p_terrains_patt
|
|||
return false;
|
||||
}
|
||||
}
|
||||
if (terrain != p_terrains_pattern.terrain) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TileSet::TerrainsPattern::set_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain) {
|
||||
void TileSet::TerrainsPattern::set_terrain(int p_terrain) {
|
||||
ERR_FAIL_COND(p_terrain < -1);
|
||||
|
||||
terrain = p_terrain;
|
||||
}
|
||||
|
||||
int TileSet::TerrainsPattern::get_terrain() const {
|
||||
return terrain;
|
||||
}
|
||||
|
||||
void TileSet::TerrainsPattern::set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain) {
|
||||
ERR_FAIL_COND(p_peering_bit == TileSet::CELL_NEIGHBOR_MAX);
|
||||
ERR_FAIL_COND(!is_valid_bit[p_peering_bit]);
|
||||
ERR_FAIL_COND(p_terrain < -1);
|
||||
|
@ -271,25 +287,27 @@ void TileSet::TerrainsPattern::set_terrain(TileSet::CellNeighbor p_peering_bit,
|
|||
bits[p_peering_bit] = p_terrain;
|
||||
}
|
||||
|
||||
int TileSet::TerrainsPattern::get_terrain(TileSet::CellNeighbor p_peering_bit) const {
|
||||
int TileSet::TerrainsPattern::get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
|
||||
ERR_FAIL_COND_V(p_peering_bit == TileSet::CELL_NEIGHBOR_MAX, -1);
|
||||
ERR_FAIL_COND_V(!is_valid_bit[p_peering_bit], -1);
|
||||
return bits[p_peering_bit];
|
||||
}
|
||||
|
||||
void TileSet::TerrainsPattern::set_terrains_from_array(Array p_terrains) {
|
||||
int in_array_index = 0;
|
||||
void TileSet::TerrainsPattern::from_array(Array p_terrains) {
|
||||
set_terrain(p_terrains[0]);
|
||||
int in_array_index = 1;
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
if (is_valid_bit[i]) {
|
||||
ERR_FAIL_INDEX(in_array_index, p_terrains.size());
|
||||
set_terrain(TileSet::CellNeighbor(i), p_terrains[in_array_index]);
|
||||
set_terrain_peering_bit(TileSet::CellNeighbor(i), p_terrains[in_array_index]);
|
||||
in_array_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Array TileSet::TerrainsPattern::get_terrains_as_array() const {
|
||||
Array TileSet::TerrainsPattern::as_array() const {
|
||||
Array output;
|
||||
output.push_back(get_terrain());
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
if (is_valid_bit[i]) {
|
||||
output.push_back(bits[i]);
|
||||
|
@ -297,10 +315,11 @@ Array TileSet::TerrainsPattern::get_terrains_as_array() const {
|
|||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
TileSet::TerrainsPattern::TerrainsPattern(const TileSet *p_tile_set, int p_terrain_set) {
|
||||
ERR_FAIL_COND(p_terrain_set < 0);
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
is_valid_bit[i] = (p_tile_set->is_valid_peering_bit_terrain(p_terrain_set, TileSet::CellNeighbor(i)));
|
||||
is_valid_bit[i] = (p_tile_set->is_valid_terrain_peering_bit(p_terrain_set, TileSet::CellNeighbor(i)));
|
||||
bits[i] = -1;
|
||||
}
|
||||
valid = true;
|
||||
|
@ -410,11 +429,16 @@ void TileSet::_update_terrains_cache() {
|
|||
|
||||
TileSet::TerrainsPattern terrains_pattern = tile_data->get_terrains_pattern();
|
||||
|
||||
// Main terrain.
|
||||
if (terrains_pattern.get_terrain() >= 0) {
|
||||
per_terrain_pattern_tiles[terrain_set][terrains_pattern].insert(cell);
|
||||
}
|
||||
|
||||
// Terrain bits.
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
CellNeighbor bit = CellNeighbor(i);
|
||||
if (is_valid_peering_bit_terrain(terrain_set, bit)) {
|
||||
int terrain = terrains_pattern.get_terrain(bit);
|
||||
if (is_valid_terrain_peering_bit(terrain_set, bit)) {
|
||||
int terrain = terrains_pattern.get_terrain_peering_bit(bit);
|
||||
if (terrain >= 0) {
|
||||
per_terrain_pattern_tiles[terrain_set][terrains_pattern].insert(cell);
|
||||
}
|
||||
|
@ -822,7 +846,7 @@ Color TileSet::get_terrain_color(int p_terrain_set, int p_terrain_index) const {
|
|||
return terrain_sets[p_terrain_set].terrains[p_terrain_index].color;
|
||||
}
|
||||
|
||||
bool TileSet::is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const {
|
||||
bool TileSet::is_valid_terrain_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const {
|
||||
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
|
||||
if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
|
||||
if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
|
||||
|
@ -905,13 +929,13 @@ bool TileSet::is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const {
|
||||
bool TileSet::is_valid_terrain_peering_bit(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const {
|
||||
if (p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set);
|
||||
return is_valid_peering_bit_for_mode(terrain_mode, p_peering_bit);
|
||||
return is_valid_terrain_peering_bit_for_mode(terrain_mode, p_peering_bit);
|
||||
}
|
||||
|
||||
// Navigation
|
||||
|
@ -1494,26 +1518,48 @@ void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform
|
|||
}
|
||||
}
|
||||
|
||||
Vector<Point2> TileSet::get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit) {
|
||||
Vector<Point2> TileSet::get_terrain_polygon(int p_terrain_set) {
|
||||
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
|
||||
return _get_square_terrain_polygon(tile_size);
|
||||
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
|
||||
return _get_isometric_terrain_polygon(tile_size);
|
||||
} else {
|
||||
float overlap = 0.0;
|
||||
switch (tile_shape) {
|
||||
case TileSet::TILE_SHAPE_HEXAGON:
|
||||
overlap = 0.25;
|
||||
break;
|
||||
case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
|
||||
overlap = 0.0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return _get_half_offset_terrain_polygon(tile_size, overlap, tile_offset_axis);
|
||||
}
|
||||
return Vector<Point2>();
|
||||
}
|
||||
|
||||
Vector<Point2> TileSet::get_terrain_peering_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit) {
|
||||
ERR_FAIL_COND_V(p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count(), Vector<Point2>());
|
||||
|
||||
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set);
|
||||
|
||||
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
|
||||
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
|
||||
return _get_square_corner_or_side_terrain_bit_polygon(tile_size, p_bit);
|
||||
return _get_square_corner_or_side_terrain_peering_bit_polygon(tile_size, p_bit);
|
||||
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
|
||||
return _get_square_corner_terrain_bit_polygon(tile_size, p_bit);
|
||||
return _get_square_corner_terrain_peering_bit_polygon(tile_size, p_bit);
|
||||
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
|
||||
return _get_square_side_terrain_bit_polygon(tile_size, p_bit);
|
||||
return _get_square_side_terrain_peering_bit_polygon(tile_size, p_bit);
|
||||
}
|
||||
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
|
||||
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
|
||||
return _get_isometric_corner_or_side_terrain_bit_polygon(tile_size, p_bit);
|
||||
return _get_isometric_corner_or_side_terrain_peering_bit_polygon(tile_size, p_bit);
|
||||
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
|
||||
return _get_isometric_corner_terrain_bit_polygon(tile_size, p_bit);
|
||||
return _get_isometric_corner_terrain_peering_bit_polygon(tile_size, p_bit);
|
||||
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
|
||||
return _get_isometric_side_terrain_bit_polygon(tile_size, p_bit);
|
||||
return _get_isometric_side_terrain_peering_bit_polygon(tile_size, p_bit);
|
||||
}
|
||||
} else {
|
||||
float overlap = 0.0;
|
||||
|
@ -1528,11 +1574,11 @@ Vector<Point2> TileSet::get_terrain_bit_polygon(int p_terrain_set, TileSet::Cell
|
|||
break;
|
||||
}
|
||||
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
|
||||
return _get_half_offset_corner_or_side_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis);
|
||||
return _get_half_offset_corner_or_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
|
||||
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
|
||||
return _get_half_offset_corner_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis);
|
||||
return _get_half_offset_corner_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
|
||||
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
|
||||
return _get_half_offset_side_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis);
|
||||
return _get_half_offset_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1544,30 +1590,68 @@ void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform,
|
|||
|
||||
if (terrain_bits_meshes_dirty) {
|
||||
// Recompute the meshes.
|
||||
terrain_bits_meshes.clear();
|
||||
terrain_peering_bits_meshes.clear();
|
||||
|
||||
for (int terrain_mode_index = 0; terrain_mode_index < 3; terrain_mode_index++) {
|
||||
TerrainMode terrain_mode = TerrainMode(terrain_mode_index);
|
||||
|
||||
// Center terrain
|
||||
Vector<Vector2> polygon;
|
||||
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
|
||||
polygon = _get_square_terrain_polygon(tile_size);
|
||||
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
|
||||
polygon = _get_isometric_terrain_polygon(tile_size);
|
||||
} else {
|
||||
float overlap = 0.0;
|
||||
switch (tile_shape) {
|
||||
case TileSet::TILE_SHAPE_HEXAGON:
|
||||
overlap = 0.25;
|
||||
break;
|
||||
case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
|
||||
overlap = 0.0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
polygon = _get_half_offset_terrain_polygon(tile_size, overlap, tile_offset_axis);
|
||||
}
|
||||
{
|
||||
Ref<ArrayMesh> mesh;
|
||||
mesh.instantiate();
|
||||
Vector<Vector2> uvs;
|
||||
uvs.resize(polygon.size());
|
||||
Vector<Color> colors;
|
||||
colors.resize(polygon.size());
|
||||
colors.fill(Color(1.0, 1.0, 1.0, 1.0));
|
||||
Array a;
|
||||
a.resize(Mesh::ARRAY_MAX);
|
||||
a[Mesh::ARRAY_VERTEX] = polygon;
|
||||
a[Mesh::ARRAY_TEX_UV] = uvs;
|
||||
a[Mesh::ARRAY_COLOR] = colors;
|
||||
a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
|
||||
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
|
||||
terrain_meshes[terrain_mode] = mesh;
|
||||
}
|
||||
// Peering bits
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
CellNeighbor bit = CellNeighbor(i);
|
||||
|
||||
if (is_valid_peering_bit_for_mode(terrain_mode, bit)) {
|
||||
Vector<Vector2> polygon;
|
||||
if (is_valid_terrain_peering_bit_for_mode(terrain_mode, bit)) {
|
||||
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
|
||||
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
|
||||
polygon = _get_square_corner_or_side_terrain_bit_polygon(tile_size, bit);
|
||||
polygon = _get_square_corner_or_side_terrain_peering_bit_polygon(tile_size, bit);
|
||||
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
|
||||
polygon = _get_square_corner_terrain_bit_polygon(tile_size, bit);
|
||||
polygon = _get_square_corner_terrain_peering_bit_polygon(tile_size, bit);
|
||||
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
|
||||
polygon = _get_square_side_terrain_bit_polygon(tile_size, bit);
|
||||
polygon = _get_square_side_terrain_peering_bit_polygon(tile_size, bit);
|
||||
}
|
||||
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
|
||||
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
|
||||
polygon = _get_isometric_corner_or_side_terrain_bit_polygon(tile_size, bit);
|
||||
polygon = _get_isometric_corner_or_side_terrain_peering_bit_polygon(tile_size, bit);
|
||||
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
|
||||
polygon = _get_isometric_corner_terrain_bit_polygon(tile_size, bit);
|
||||
polygon = _get_isometric_corner_terrain_peering_bit_polygon(tile_size, bit);
|
||||
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
|
||||
polygon = _get_isometric_side_terrain_bit_polygon(tile_size, bit);
|
||||
polygon = _get_isometric_side_terrain_peering_bit_polygon(tile_size, bit);
|
||||
}
|
||||
} else {
|
||||
float overlap = 0.0;
|
||||
|
@ -1582,29 +1666,30 @@ void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform,
|
|||
break;
|
||||
}
|
||||
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
|
||||
polygon = _get_half_offset_corner_or_side_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis);
|
||||
polygon = _get_half_offset_corner_or_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
|
||||
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
|
||||
polygon = _get_half_offset_corner_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis);
|
||||
polygon = _get_half_offset_corner_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
|
||||
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
|
||||
polygon = _get_half_offset_side_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis);
|
||||
polygon = _get_half_offset_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<ArrayMesh> mesh;
|
||||
mesh.instantiate();
|
||||
Vector<Vector2> uvs;
|
||||
uvs.resize(polygon.size());
|
||||
Vector<Color> colors;
|
||||
colors.resize(polygon.size());
|
||||
colors.fill(Color(1.0, 1.0, 1.0, 1.0));
|
||||
Array a;
|
||||
a.resize(Mesh::ARRAY_MAX);
|
||||
a[Mesh::ARRAY_VERTEX] = polygon;
|
||||
a[Mesh::ARRAY_TEX_UV] = uvs;
|
||||
a[Mesh::ARRAY_COLOR] = colors;
|
||||
a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
|
||||
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
|
||||
terrain_bits_meshes[terrain_mode][bit] = mesh;
|
||||
{
|
||||
Ref<ArrayMesh> mesh;
|
||||
mesh.instantiate();
|
||||
Vector<Vector2> uvs;
|
||||
uvs.resize(polygon.size());
|
||||
Vector<Color> colors;
|
||||
colors.resize(polygon.size());
|
||||
colors.fill(Color(1.0, 1.0, 1.0, 1.0));
|
||||
Array a;
|
||||
a.resize(Mesh::ARRAY_MAX);
|
||||
a[Mesh::ARRAY_VERTEX] = polygon;
|
||||
a[Mesh::ARRAY_TEX_UV] = uvs;
|
||||
a[Mesh::ARRAY_COLOR] = colors;
|
||||
a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
|
||||
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
|
||||
terrain_peering_bits_meshes[terrain_mode][bit] = mesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1618,14 +1703,21 @@ void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform,
|
|||
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(terrain_set);
|
||||
|
||||
RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
|
||||
int terrain_id = p_tile_data->get_terrain();
|
||||
if (terrain_id >= 0) {
|
||||
Color color = get_terrain_color(terrain_set, terrain_id);
|
||||
color.a = TERRAIN_ALPHA;
|
||||
p_canvas_item->draw_mesh(terrain_meshes[terrain_mode], Ref<Texture2D>(), Transform2D(), color);
|
||||
}
|
||||
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
CellNeighbor bit = CellNeighbor(i);
|
||||
if (is_valid_peering_bit_terrain(terrain_set, bit)) {
|
||||
int terrain_id = p_tile_data->get_peering_bit_terrain(bit);
|
||||
if (is_valid_terrain_peering_bit(terrain_set, bit)) {
|
||||
terrain_id = p_tile_data->get_terrain_peering_bit(bit);
|
||||
if (terrain_id >= 0) {
|
||||
Color color = get_terrain_color(terrain_set, terrain_id);
|
||||
color.a = TERRAIN_ALPHA;
|
||||
p_canvas_item->draw_mesh(terrain_bits_meshes[terrain_mode][bit], Ref<Texture2D>(), Transform2D(), color);
|
||||
p_canvas_item->draw_mesh(terrain_peering_bits_meshes[terrain_mode][bit], Ref<Texture2D>(), Transform2D(), color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1670,13 +1762,16 @@ Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) {
|
|||
for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) {
|
||||
bit_counts[terrain] = 0;
|
||||
}
|
||||
if (tile_data->get_terrain() >= 0) {
|
||||
bit_counts[tile_data->get_terrain()] += 10;
|
||||
}
|
||||
for (int terrain_bit = 0; terrain_bit < TileSet::CELL_NEIGHBOR_MAX; terrain_bit++) {
|
||||
TileSet::CellNeighbor cell_neighbor = TileSet::CellNeighbor(terrain_bit);
|
||||
if (is_valid_peering_bit_terrain(terrain_set, cell_neighbor)) {
|
||||
int terrain = tile_data->get_peering_bit_terrain(cell_neighbor);
|
||||
if (is_valid_terrain_peering_bit(terrain_set, cell_neighbor)) {
|
||||
int terrain = tile_data->get_terrain_peering_bit(cell_neighbor);
|
||||
if (terrain >= 0) {
|
||||
if (terrain >= (int)bit_counts.size()) {
|
||||
WARN_PRINT(vformat("Invalid peering bit terrain: %d", terrain));
|
||||
WARN_PRINT(vformat("Invalid terrain peering bit: %d", terrain));
|
||||
} else {
|
||||
bit_counts[terrain] += 1;
|
||||
}
|
||||
|
@ -1730,7 +1825,17 @@ void TileSet::_source_changed() {
|
|||
emit_changed();
|
||||
}
|
||||
|
||||
Vector<Point2> TileSet::_get_square_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
|
||||
Vector<Point2> TileSet::_get_square_terrain_polygon(Vector2i p_size) {
|
||||
Rect2 rect(-Vector2(p_size) / 6.0, Vector2(p_size) / 3.0);
|
||||
return {
|
||||
rect.position,
|
||||
Vector2(rect.get_end().x, rect.position.y),
|
||||
rect.get_end(),
|
||||
Vector2(rect.position.x, rect.get_end().y)
|
||||
};
|
||||
}
|
||||
|
||||
Vector<Point2> TileSet::_get_square_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
|
||||
Rect2 bit_rect;
|
||||
bit_rect.size = Vector2(p_size) / 3;
|
||||
switch (p_bit) {
|
||||
|
@ -1773,7 +1878,7 @@ Vector<Point2> TileSet::_get_square_corner_or_side_terrain_bit_polygon(Vector2i
|
|||
return polygon;
|
||||
}
|
||||
|
||||
Vector<Point2> TileSet::_get_square_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
|
||||
Vector<Point2> TileSet::_get_square_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
|
||||
Vector2 unit = Vector2(p_size) / 6.0;
|
||||
Vector<Vector2> polygon;
|
||||
switch (p_bit) {
|
||||
|
@ -1815,7 +1920,7 @@ Vector<Point2> TileSet::_get_square_corner_terrain_bit_polygon(Vector2i p_size,
|
|||
return polygon;
|
||||
}
|
||||
|
||||
Vector<Point2> TileSet::_get_square_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
|
||||
Vector<Point2> TileSet::_get_square_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
|
||||
Vector2 unit = Vector2(p_size) / 6.0;
|
||||
Vector<Vector2> polygon;
|
||||
switch (p_bit) {
|
||||
|
@ -1849,7 +1954,17 @@ Vector<Point2> TileSet::_get_square_side_terrain_bit_polygon(Vector2i p_size, Ti
|
|||
return polygon;
|
||||
}
|
||||
|
||||
Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
|
||||
Vector<Point2> TileSet::_get_isometric_terrain_polygon(Vector2i p_size) {
|
||||
Vector2 unit = Vector2(p_size) / 6.0;
|
||||
return {
|
||||
Vector2(1, 0) * unit,
|
||||
Vector2(0, 1) * unit,
|
||||
Vector2(-1, 0) * unit,
|
||||
Vector2(0, -1) * unit,
|
||||
};
|
||||
}
|
||||
|
||||
Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
|
||||
Vector2 unit = Vector2(p_size) / 6.0;
|
||||
Vector<Vector2> polygon;
|
||||
switch (p_bit) {
|
||||
|
@ -1907,7 +2022,7 @@ Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_bit_polygon(Vector
|
|||
return polygon;
|
||||
}
|
||||
|
||||
Vector<Point2> TileSet::_get_isometric_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
|
||||
Vector<Point2> TileSet::_get_isometric_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
|
||||
Vector2 unit = Vector2(p_size) / 6.0;
|
||||
Vector<Vector2> polygon;
|
||||
switch (p_bit) {
|
||||
|
@ -1949,7 +2064,7 @@ Vector<Point2> TileSet::_get_isometric_corner_terrain_bit_polygon(Vector2i p_siz
|
|||
return polygon;
|
||||
}
|
||||
|
||||
Vector<Point2> TileSet::_get_isometric_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
|
||||
Vector<Point2> TileSet::_get_isometric_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
|
||||
Vector2 unit = Vector2(p_size) / 6.0;
|
||||
Vector<Vector2> polygon;
|
||||
switch (p_bit) {
|
||||
|
@ -1983,7 +2098,30 @@ Vector<Point2> TileSet::_get_isometric_side_terrain_bit_polygon(Vector2i p_size,
|
|||
return polygon;
|
||||
}
|
||||
|
||||
Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
|
||||
Vector<Point2> TileSet::_get_half_offset_terrain_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
|
||||
Vector2 unit = Vector2(p_size) / 6.0;
|
||||
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
|
||||
return {
|
||||
Vector2(1, 1.0 - p_overlap * 2.0) * unit,
|
||||
Vector2(0, 1) * unit,
|
||||
Vector2(-1, 1.0 - p_overlap * 2.0) * unit,
|
||||
Vector2(-1, -1.0 + p_overlap * 2.0) * unit,
|
||||
Vector2(0, -1) * unit,
|
||||
Vector2(1, -1.0 + p_overlap * 2.0) * unit,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
Vector2(1, 0) * unit,
|
||||
Vector2(1.0 - p_overlap * 2.0, -1) * unit,
|
||||
Vector2(-1.0 + p_overlap * 2.0, -1) * unit,
|
||||
Vector2(-1, 0) * unit,
|
||||
Vector2(-1.0 + p_overlap * 2.0, 1) * unit,
|
||||
Vector2(1.0 - p_overlap * 2.0, 1) * unit,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
|
||||
Vector<Vector2> point_list = {
|
||||
Vector2(3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0),
|
||||
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
|
||||
|
@ -2006,12 +2144,11 @@ Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vect
|
|||
};
|
||||
|
||||
Vector2 unit = Vector2(p_size) / 6.0;
|
||||
for (int i = 0; i < point_list.size(); i++) {
|
||||
point_list.write[i] = point_list[i] * unit;
|
||||
}
|
||||
|
||||
Vector<Vector2> polygon;
|
||||
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
|
||||
for (int i = 0; i < point_list.size(); i++) {
|
||||
point_list.write[i] = point_list[i] * unit;
|
||||
}
|
||||
switch (p_bit) {
|
||||
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
|
||||
polygon.push_back(point_list[17]);
|
||||
|
@ -2071,10 +2208,8 @@ Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vect
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
|
||||
for (int i = 0; i < point_list.size(); i++) {
|
||||
point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
|
||||
}
|
||||
for (int i = 0; i < point_list.size(); i++) {
|
||||
point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
|
||||
}
|
||||
switch (p_bit) {
|
||||
case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
|
||||
|
@ -2144,7 +2279,7 @@ Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vect
|
|||
return polygon;
|
||||
}
|
||||
|
||||
Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
|
||||
Vector<Point2> TileSet::_get_half_offset_corner_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
|
||||
Vector<Vector2> point_list = {
|
||||
Vector2(3, 0),
|
||||
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
|
||||
|
@ -2161,12 +2296,11 @@ Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_s
|
|||
};
|
||||
|
||||
Vector2 unit = Vector2(p_size) / 6.0;
|
||||
for (int i = 0; i < point_list.size(); i++) {
|
||||
point_list.write[i] = point_list[i] * unit;
|
||||
}
|
||||
|
||||
Vector<Vector2> polygon;
|
||||
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
|
||||
for (int i = 0; i < point_list.size(); i++) {
|
||||
point_list.write[i] = point_list[i] * unit;
|
||||
}
|
||||
switch (p_bit) {
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
|
||||
polygon.push_back(point_list[0]);
|
||||
|
@ -2202,10 +2336,8 @@ Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_s
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
|
||||
for (int i = 0; i < point_list.size(); i++) {
|
||||
point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
|
||||
}
|
||||
for (int i = 0; i < point_list.size(); i++) {
|
||||
point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
|
||||
}
|
||||
switch (p_bit) {
|
||||
case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
|
||||
|
@ -2251,7 +2383,7 @@ Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_s
|
|||
return polygon;
|
||||
}
|
||||
|
||||
Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
|
||||
Vector<Point2> TileSet::_get_half_offset_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
|
||||
Vector<Vector2> point_list = {
|
||||
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
|
||||
Vector2(0, 3),
|
||||
|
@ -2262,12 +2394,11 @@ Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_siz
|
|||
};
|
||||
|
||||
Vector2 unit = Vector2(p_size) / 6.0;
|
||||
for (int i = 0; i < point_list.size(); i++) {
|
||||
point_list.write[i] = point_list[i] * unit;
|
||||
}
|
||||
|
||||
Vector<Vector2> polygon;
|
||||
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
|
||||
for (int i = 0; i < point_list.size(); i++) {
|
||||
point_list.write[i] = point_list[i] * unit;
|
||||
}
|
||||
switch (p_bit) {
|
||||
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
|
||||
polygon.push_back(point_list[5]);
|
||||
|
@ -2297,10 +2428,8 @@ Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_siz
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
|
||||
for (int i = 0; i < point_list.size(); i++) {
|
||||
point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
|
||||
}
|
||||
for (int i = 0; i < point_list.size(); i++) {
|
||||
point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
|
||||
}
|
||||
switch (p_bit) {
|
||||
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
|
||||
|
@ -5114,36 +5243,51 @@ int TileData::get_terrain_set() const {
|
|||
return terrain_set;
|
||||
}
|
||||
|
||||
void TileData::set_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) {
|
||||
void TileData::set_terrain(int p_terrain) {
|
||||
ERR_FAIL_COND(terrain_set < 0);
|
||||
ERR_FAIL_COND(p_terrain < -1);
|
||||
if (tile_set) {
|
||||
ERR_FAIL_COND(p_terrain >= tile_set->get_terrains_count(terrain_set));
|
||||
}
|
||||
terrain = p_terrain;
|
||||
emit_signal(SNAME("changed"));
|
||||
}
|
||||
|
||||
int TileData::get_terrain() const {
|
||||
return terrain;
|
||||
}
|
||||
|
||||
void TileData::set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) {
|
||||
ERR_FAIL_INDEX(p_peering_bit, TileSet::CellNeighbor::CELL_NEIGHBOR_MAX);
|
||||
ERR_FAIL_COND(terrain_set < 0);
|
||||
ERR_FAIL_COND(p_terrain_index < -1);
|
||||
if (tile_set) {
|
||||
ERR_FAIL_COND(p_terrain_index >= tile_set->get_terrains_count(terrain_set));
|
||||
ERR_FAIL_COND(!is_valid_peering_bit_terrain(p_peering_bit));
|
||||
ERR_FAIL_COND(!is_valid_terrain_peering_bit(p_peering_bit));
|
||||
}
|
||||
terrain_peering_bits[p_peering_bit] = p_terrain_index;
|
||||
emit_signal(SNAME("changed"));
|
||||
}
|
||||
|
||||
int TileData::get_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const {
|
||||
ERR_FAIL_COND_V(!is_valid_peering_bit_terrain(p_peering_bit), -1);
|
||||
int TileData::get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
|
||||
ERR_FAIL_COND_V(!is_valid_terrain_peering_bit(p_peering_bit), -1);
|
||||
return terrain_peering_bits[p_peering_bit];
|
||||
}
|
||||
|
||||
bool TileData::is_valid_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const {
|
||||
bool TileData::is_valid_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
|
||||
ERR_FAIL_COND_V(!tile_set, false);
|
||||
|
||||
return tile_set->is_valid_peering_bit_terrain(terrain_set, p_peering_bit);
|
||||
return tile_set->is_valid_terrain_peering_bit(terrain_set, p_peering_bit);
|
||||
}
|
||||
|
||||
TileSet::TerrainsPattern TileData::get_terrains_pattern() const {
|
||||
ERR_FAIL_COND_V(!tile_set, TileSet::TerrainsPattern());
|
||||
|
||||
TileSet::TerrainsPattern output(tile_set, terrain_set);
|
||||
output.set_terrain(terrain);
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
if (tile_set->is_valid_peering_bit_terrain(terrain_set, TileSet::CellNeighbor(i))) {
|
||||
output.set_terrain(TileSet::CellNeighbor(i), get_peering_bit_terrain(TileSet::CellNeighbor(i)));
|
||||
if (tile_set->is_valid_terrain_peering_bit(terrain_set, TileSet::CellNeighbor(i))) {
|
||||
output.set_terrain_peering_bit(TileSet::CellNeighbor(i), get_terrain_peering_bit(TileSet::CellNeighbor(i)));
|
||||
}
|
||||
}
|
||||
return output;
|
||||
|
@ -5293,7 +5437,7 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) {
|
|||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (components[1] == TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]) {
|
||||
set_peering_bit_terrain(bit, p_value);
|
||||
set_terrain_peering_bit(bit, p_value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -5455,9 +5599,9 @@ void TileData::_get_property_list(List<PropertyInfo> *p_list) const {
|
|||
p_list->push_back(PropertyInfo(Variant::NIL, "Terrains", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (is_valid_peering_bit_terrain(bit)) {
|
||||
if (is_valid_terrain_peering_bit(bit)) {
|
||||
property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]));
|
||||
if (get_peering_bit_terrain(bit) == -1) {
|
||||
if (get_terrain_peering_bit(bit) == -1) {
|
||||
property_info.usage ^= PROPERTY_USAGE_STORAGE;
|
||||
}
|
||||
p_list->push_back(property_info);
|
||||
|
@ -5531,8 +5675,10 @@ void TileData::_bind_methods() {
|
|||
// Terrain
|
||||
ClassDB::bind_method(D_METHOD("set_terrain_set", "terrain_set"), &TileData::set_terrain_set);
|
||||
ClassDB::bind_method(D_METHOD("get_terrain_set"), &TileData::get_terrain_set);
|
||||
ClassDB::bind_method(D_METHOD("set_peering_bit_terrain", "peering_bit", "terrain"), &TileData::set_peering_bit_terrain);
|
||||
ClassDB::bind_method(D_METHOD("get_peering_bit_terrain", "peering_bit"), &TileData::get_peering_bit_terrain);
|
||||
ClassDB::bind_method(D_METHOD("set_terrain", "terrain"), &TileData::set_terrain);
|
||||
ClassDB::bind_method(D_METHOD("get_terrain"), &TileData::get_terrain);
|
||||
ClassDB::bind_method(D_METHOD("set_terrain_peering_bit", "peering_bit", "terrain"), &TileData::set_terrain_peering_bit);
|
||||
ClassDB::bind_method(D_METHOD("get_terrain_peering_bit", "peering_bit"), &TileData::get_terrain_peering_bit);
|
||||
|
||||
// Navigation
|
||||
ClassDB::bind_method(D_METHOD("set_navigation_polygon", "layer_id", "navigation_polygon"), &TileData::set_navigation_polygon);
|
||||
|
@ -5560,6 +5706,7 @@ void TileData::_bind_methods() {
|
|||
|
||||
ADD_GROUP("Terrains", "");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "terrain_set"), "set_terrain_set", "get_terrain_set");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "terrain"), "set_terrain", "get_terrain");
|
||||
|
||||
ADD_GROUP("Miscellaneous", "");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "probability"), "set_probability", "get_probability");
|
||||
|
|
|
@ -265,6 +265,7 @@ public:
|
|||
|
||||
class TerrainsPattern {
|
||||
bool valid = false;
|
||||
int terrain = -1;
|
||||
int bits[TileSet::CELL_NEIGHBOR_MAX];
|
||||
bool is_valid_bit[TileSet::CELL_NEIGHBOR_MAX];
|
||||
|
||||
|
@ -277,11 +278,14 @@ public:
|
|||
bool operator<(const TerrainsPattern &p_terrains_pattern) const;
|
||||
bool operator==(const TerrainsPattern &p_terrains_pattern) const;
|
||||
|
||||
void set_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain);
|
||||
int get_terrain(TileSet::CellNeighbor p_peering_bit) const;
|
||||
void set_terrain(int p_terrain);
|
||||
int get_terrain() const;
|
||||
|
||||
void set_terrains_from_array(Array p_terrains);
|
||||
Array get_terrains_as_array() const;
|
||||
void set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain);
|
||||
int get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const;
|
||||
|
||||
void from_array(Array p_terrains);
|
||||
Array as_array() const;
|
||||
|
||||
TerrainsPattern(const TileSet *p_tile_set, int p_terrain_set);
|
||||
TerrainsPattern() {}
|
||||
|
@ -333,7 +337,8 @@ private:
|
|||
};
|
||||
Vector<TerrainSet> terrain_sets;
|
||||
|
||||
HashMap<TerrainMode, HashMap<CellNeighbor, Ref<ArrayMesh>>> terrain_bits_meshes;
|
||||
HashMap<TerrainMode, Ref<ArrayMesh>> terrain_meshes;
|
||||
HashMap<TerrainMode, HashMap<CellNeighbor, Ref<ArrayMesh>>> terrain_peering_bits_meshes;
|
||||
bool terrain_bits_meshes_dirty = true;
|
||||
|
||||
LocalVector<RBMap<TileSet::TerrainsPattern, RBSet<TileMapCell>>> per_terrain_pattern_tiles; // Cached data.
|
||||
|
@ -371,17 +376,20 @@ private:
|
|||
RBMap<Array, Array> alternative_level_proxies;
|
||||
|
||||
// Helpers
|
||||
Vector<Point2> _get_square_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
|
||||
Vector<Point2> _get_square_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
|
||||
Vector<Point2> _get_square_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
|
||||
Vector<Point2> _get_square_terrain_polygon(Vector2i p_size);
|
||||
Vector<Point2> _get_square_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
|
||||
Vector<Point2> _get_square_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
|
||||
Vector<Point2> _get_square_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
|
||||
|
||||
Vector<Point2> _get_isometric_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
|
||||
Vector<Point2> _get_isometric_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
|
||||
Vector<Point2> _get_isometric_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
|
||||
Vector<Point2> _get_isometric_terrain_polygon(Vector2i p_size);
|
||||
Vector<Point2> _get_isometric_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
|
||||
Vector<Point2> _get_isometric_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
|
||||
Vector<Point2> _get_isometric_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit);
|
||||
|
||||
Vector<Point2> _get_half_offset_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
|
||||
Vector<Point2> _get_half_offset_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
|
||||
Vector<Point2> _get_half_offset_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
|
||||
Vector<Point2> _get_half_offset_terrain_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
|
||||
Vector<Point2> _get_half_offset_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit);
|
||||
Vector<Point2> _get_half_offset_corner_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit);
|
||||
Vector<Point2> _get_half_offset_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
@ -454,8 +462,8 @@ public:
|
|||
String get_terrain_name(int p_terrain_set, int p_terrain_index) const;
|
||||
void set_terrain_color(int p_terrain_set, int p_terrain_index, Color p_color);
|
||||
Color get_terrain_color(int p_terrain_set, int p_terrain_index) const;
|
||||
bool is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const;
|
||||
bool is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const;
|
||||
bool is_valid_terrain_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const;
|
||||
bool is_valid_terrain_peering_bit(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const;
|
||||
|
||||
// Navigation
|
||||
int get_navigation_layers_count() const;
|
||||
|
@ -516,7 +524,8 @@ public:
|
|||
Vector<Vector2> get_tile_shape_polygon();
|
||||
void draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>());
|
||||
|
||||
Vector<Point2> get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit);
|
||||
Vector<Point2> get_terrain_polygon(int p_terrain_set);
|
||||
Vector<Point2> get_terrain_peering_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit);
|
||||
void draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, const TileData *p_tile_data);
|
||||
Vector<Vector<Ref<Texture2D>>> generate_terrains_icons(Size2i p_size);
|
||||
|
||||
|
@ -798,6 +807,7 @@ private:
|
|||
|
||||
// Terrain
|
||||
int terrain_set = -1;
|
||||
int terrain = -1;
|
||||
int terrain_peering_bits[16] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
|
||||
// Navigation
|
||||
|
@ -887,9 +897,11 @@ public:
|
|||
// Terrain
|
||||
void set_terrain_set(int p_terrain_id);
|
||||
int get_terrain_set() const;
|
||||
void set_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain_id);
|
||||
int get_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const;
|
||||
bool is_valid_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const;
|
||||
void set_terrain(int p_terrain_id);
|
||||
int get_terrain() const;
|
||||
void set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain_id);
|
||||
int get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const;
|
||||
bool is_valid_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const;
|
||||
|
||||
TileSet::TerrainsPattern get_terrains_pattern() const; // Not exposed.
|
||||
|
||||
|
|
Loading…
Reference in New Issue