123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770 |
- /*************************************************************************/
- /* tile_map.cpp */
- /*************************************************************************/
- /* This file is part of: */
- /* GODOT ENGINE */
- /* https://godotengine.org */
- /*************************************************************************/
- /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
- /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
- /* */
- /* Permission is hereby granted, free of charge, to any person obtaining */
- /* a copy of this software and associated documentation files (the */
- /* "Software"), to deal in the Software without restriction, including */
- /* without limitation the rights to use, copy, modify, merge, publish, */
- /* distribute, sublicense, and/or sell copies of the Software, and to */
- /* permit persons to whom the Software is furnished to do so, subject to */
- /* the following conditions: */
- /* */
- /* The above copyright notice and this permission notice shall be */
- /* included in all copies or substantial portions of the Software. */
- /* */
- /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
- /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
- /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
- /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
- /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
- /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
- /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
- /*************************************************************************/
- #include "tile_map.h"
- #include "core/io/marshalls.h"
- #include "core/math/geometry_2d.h"
- #include "core/os/os.h"
- void TileMapPattern::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
- ERR_FAIL_COND_MSG(p_coords.x < 0 || p_coords.y < 0, vformat("Cannot set cell with negative coords in a TileMapPattern. Wrong coords: %s", p_coords));
- size = size.max(p_coords + Vector2i(1, 1));
- pattern[p_coords] = TileMapCell(p_source_id, p_atlas_coords, p_alternative_tile);
- }
- bool TileMapPattern::has_cell(const Vector2i &p_coords) const {
- return pattern.has(p_coords);
- }
- void TileMapPattern::remove_cell(const Vector2i &p_coords, bool p_update_size) {
- ERR_FAIL_COND(!pattern.has(p_coords));
- pattern.erase(p_coords);
- if (p_update_size) {
- size = Vector2i();
- for (Map<Vector2i, TileMapCell>::Element *E = pattern.front(); E; E = E->next()) {
- size = size.max(E->key() + Vector2i(1, 1));
- }
- }
- }
- int TileMapPattern::get_cell_source_id(const Vector2i &p_coords) const {
- ERR_FAIL_COND_V(!pattern.has(p_coords), -1);
- return pattern[p_coords].source_id;
- }
- Vector2i TileMapPattern::get_cell_atlas_coords(const Vector2i &p_coords) const {
- ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetAtlasSource::INVALID_ATLAS_COORDS);
- return pattern[p_coords].get_atlas_coords();
- }
- int TileMapPattern::get_cell_alternative_tile(const Vector2i &p_coords) const {
- ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetAtlasSource::INVALID_TILE_ALTERNATIVE);
- return pattern[p_coords].alternative_tile;
- }
- TypedArray<Vector2i> TileMapPattern::get_used_cells() const {
- // Returns the cells used in the tilemap.
- TypedArray<Vector2i> a;
- a.resize(pattern.size());
- int i = 0;
- for (Map<Vector2i, TileMapCell>::Element *E = pattern.front(); E; E = E->next()) {
- Vector2i p(E->key().x, E->key().y);
- a[i++] = p;
- }
- return a;
- }
- Vector2i TileMapPattern::get_size() const {
- return size;
- }
- void TileMapPattern::set_size(const Vector2i &p_size) {
- for (Map<Vector2i, TileMapCell>::Element *E = pattern.front(); E; E = E->next()) {
- Vector2i coords = E->key();
- if (p_size.x <= coords.x || p_size.y <= coords.y) {
- ERR_FAIL_MSG(vformat("Cannot set pattern size to %s, it contains a tile at %s. Size can only be increased.", p_size, coords));
- };
- }
- size = p_size;
- }
- bool TileMapPattern::is_empty() const {
- return pattern.is_empty();
- };
- void TileMapPattern::clear() {
- size = Vector2i();
- pattern.clear();
- };
- void TileMapPattern::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMapPattern::set_cell, DEFVAL(-1), DEFVAL(TileSetAtlasSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetAtlasSource::INVALID_TILE_ALTERNATIVE));
- ClassDB::bind_method(D_METHOD("has_cell", "coords"), &TileMapPattern::has_cell);
- ClassDB::bind_method(D_METHOD("remove_cell", "coords"), &TileMapPattern::remove_cell);
- ClassDB::bind_method(D_METHOD("get_cell_source_id", "coords"), &TileMapPattern::get_cell_source_id);
- ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "coords"), &TileMapPattern::get_cell_atlas_coords);
- ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "coords"), &TileMapPattern::get_cell_alternative_tile);
- ClassDB::bind_method(D_METHOD("get_used_cells"), &TileMapPattern::get_used_cells);
- ClassDB::bind_method(D_METHOD("get_size"), &TileMapPattern::get_size);
- ClassDB::bind_method(D_METHOD("set_size", "size"), &TileMapPattern::set_size);
- ClassDB::bind_method(D_METHOD("is_empty"), &TileMapPattern::is_empty);
- }
- Vector2i TileMap::transform_coords_layout(Vector2i p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout) {
- // Transform to stacked layout.
- Vector2i output = p_coords;
- if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
- SWAP(output.x, output.y);
- }
- switch (p_from_layout) {
- case TileSet::TILE_LAYOUT_STACKED:
- break;
- case TileSet::TILE_LAYOUT_STACKED_OFFSET:
- if (output.y % 2) {
- output.x -= 1;
- }
- break;
- case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
- case TileSet::TILE_LAYOUT_STAIRS_DOWN:
- if ((p_from_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
- if (output.y < 0 && bool(output.y % 2)) {
- output = Vector2i(output.x + output.y / 2 - 1, output.y);
- } else {
- output = Vector2i(output.x + output.y / 2, output.y);
- }
- } else {
- if (output.x < 0 && bool(output.x % 2)) {
- output = Vector2i(output.x / 2 - 1, output.x + output.y * 2);
- } else {
- output = Vector2i(output.x / 2, output.x + output.y * 2);
- }
- }
- break;
- case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
- case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
- if ((p_from_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
- if ((output.x + output.y) < 0 && (output.x - output.y) % 2) {
- output = Vector2i((output.x + output.y) / 2 - 1, output.y - output.x);
- } else {
- output = Vector2i((output.x + output.y) / 2, -output.x + output.y);
- }
- } else {
- if ((output.x - output.y) < 0 && (output.x + output.y) % 2) {
- output = Vector2i((output.x - output.y) / 2 - 1, output.x + output.y);
- } else {
- output = Vector2i((output.x - output.y) / 2, output.x + output.y);
- }
- }
- break;
- }
- switch (p_to_layout) {
- case TileSet::TILE_LAYOUT_STACKED:
- break;
- case TileSet::TILE_LAYOUT_STACKED_OFFSET:
- if (output.y % 2) {
- output.x += 1;
- }
- break;
- case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
- case TileSet::TILE_LAYOUT_STAIRS_DOWN:
- if ((p_to_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
- if (output.y < 0 && (output.y % 2)) {
- output = Vector2i(output.x - output.y / 2 + 1, output.y);
- } else {
- output = Vector2i(output.x - output.y / 2, output.y);
- }
- } else {
- if (output.y % 2) {
- if (output.y < 0) {
- output = Vector2i(2 * output.x + 1, -output.x + output.y / 2 - 1);
- } else {
- output = Vector2i(2 * output.x + 1, -output.x + output.y / 2);
- }
- } else {
- output = Vector2i(2 * output.x, -output.x + output.y / 2);
- }
- }
- break;
- case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
- case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
- if ((p_to_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
- if (output.y % 2) {
- if (output.y > 0) {
- output = Vector2i(output.x - output.y / 2, output.x + output.y / 2 + 1);
- } else {
- output = Vector2i(output.x - output.y / 2 + 1, output.x + output.y / 2);
- }
- } else {
- output = Vector2i(output.x - output.y / 2, output.x + output.y / 2);
- }
- } else {
- if (output.y % 2) {
- if (output.y < 0) {
- output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2 - 1);
- } else {
- output = Vector2i(output.x + output.y / 2 + 1, -output.x + output.y / 2);
- }
- } else {
- output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2);
- }
- }
- break;
- }
- if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
- SWAP(output.x, output.y);
- }
- return output;
- }
- int TileMap::get_effective_quadrant_size() const {
- // When using YSort, the quadrant size is reduced to 1 to have one CanvasItem per quadrant
- if (tile_set.is_valid() && tile_set->is_y_sorting()) {
- return 1;
- } else {
- return quadrant_size;
- }
- }
- Vector2i TileMap::_coords_to_quadrant_coords(const Vector2i &p_coords) const {
- int quadrant_size = get_effective_quadrant_size();
- // Rounding down, instead of simply rounding towards zero (truncating)
- return Vector2i(
- p_coords.x > 0 ? p_coords.x / quadrant_size : (p_coords.x - (quadrant_size - 1)) / quadrant_size,
- p_coords.y > 0 ? p_coords.y / quadrant_size : (p_coords.y - (quadrant_size - 1)) / quadrant_size);
- }
- void TileMap::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- pending_update = true;
- _recreate_quadrants();
- } break;
- case NOTIFICATION_EXIT_TREE: {
- _clear_quadrants();
- } break;
- }
- // Transfers the notification to tileset plugins.
- if (tile_set.is_valid()) {
- for (int i = 0; i < tile_set->get_tile_set_atlas_plugins().size(); i++) {
- tile_set->get_tile_set_atlas_plugins()[i]->tilemap_notification(this, p_what);
- }
- }
- }
- Ref<TileSet> TileMap::get_tileset() const {
- return tile_set;
- }
- void TileMap::set_tileset(const Ref<TileSet> &p_tileset) {
- if (p_tileset == tile_set) {
- return;
- }
- // Set the tileset, registering to its changes.
- if (tile_set.is_valid()) {
- tile_set->disconnect("changed", callable_mp(this, &TileMap::_make_all_quadrants_dirty));
- tile_set->disconnect("changed", callable_mp(this, &TileMap::_tile_set_changed));
- }
- if (!p_tileset.is_valid()) {
- _clear_quadrants();
- }
- tile_set = p_tileset;
- if (tile_set.is_valid()) {
- tile_set->connect("changed", callable_mp(this, &TileMap::_make_all_quadrants_dirty), varray(true));
- tile_set->connect("changed", callable_mp(this, &TileMap::_tile_set_changed));
- _recreate_quadrants();
- }
- emit_signal("changed");
- }
- int TileMap::get_quadrant_size() const {
- return quadrant_size;
- }
- void TileMap::set_quadrant_size(int p_size) {
- ERR_FAIL_COND_MSG(p_size < 1, "TileMapQuadrant size cannot be smaller than 1.");
- quadrant_size = p_size;
- _recreate_quadrants();
- emit_signal("changed");
- }
- void TileMap::_fix_cell_transform(Transform2D &xform, const TileMapCell &p_cell, const Vector2 &p_offset, const Size2 &p_sc) {
- Size2 s = p_sc;
- Vector2 offset = p_offset;
- // Flip/transpose: update the tile transform.
- TileSetSource *source = *tile_set->get_source(p_cell.source_id);
- TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
- if (!atlas_source) {
- return;
- }
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(p_cell.get_atlas_coords(), p_cell.alternative_tile));
- if (tile_data->get_transpose()) {
- SWAP(xform.elements[0].x, xform.elements[0].y);
- SWAP(xform.elements[1].x, xform.elements[1].y);
- SWAP(offset.x, offset.y);
- SWAP(s.x, s.y);
- }
- if (tile_data->get_flip_h()) {
- xform.elements[0].x = -xform.elements[0].x;
- xform.elements[1].x = -xform.elements[1].x;
- offset.x = s.x - offset.x;
- }
- if (tile_data->get_flip_v()) {
- xform.elements[0].y = -xform.elements[0].y;
- xform.elements[1].y = -xform.elements[1].y;
- offset.y = s.y - offset.y;
- }
- xform.elements[2] += offset;
- }
- void TileMap::update_dirty_quadrants() {
- if (!pending_update) {
- return;
- }
- if (!is_inside_tree() || !tile_set.is_valid()) {
- pending_update = false;
- return;
- }
- // Update the coords cache.
- for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
- q->self()->map_to_world.clear();
- q->self()->world_to_map.clear();
- for (Set<Vector2i>::Element *E = q->self()->cells.front(); E; E = E->next()) {
- Vector2i pk = E->get();
- Vector2i pk_world_coords = map_to_world(pk);
- q->self()->map_to_world[pk] = pk_world_coords;
- q->self()->world_to_map[pk_world_coords] = pk;
- }
- }
- // Call the update_dirty_quadrant method on plugins.
- for (int i = 0; i < tile_set->get_tile_set_atlas_plugins().size(); i++) {
- tile_set->get_tile_set_atlas_plugins()[i]->update_dirty_quadrants(this, dirty_quadrant_list);
- }
- // Redraw the debug canvas_items.
- RenderingServer *rs = RenderingServer::get_singleton();
- for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
- rs->canvas_item_clear(q->self()->debug_canvas_item);
- Transform2D xform;
- xform.set_origin(map_to_world(q->self()->coords * get_effective_quadrant_size()));
- rs->canvas_item_set_transform(q->self()->debug_canvas_item, xform);
- for (int i = 0; i < tile_set->get_tile_set_atlas_plugins().size(); i++) {
- tile_set->get_tile_set_atlas_plugins()[i]->draw_quadrant_debug(this, q->self());
- }
- }
- // Clear the list
- while (dirty_quadrant_list.first()) {
- dirty_quadrant_list.remove(dirty_quadrant_list.first());
- }
- pending_update = false;
- _recompute_rect_cache();
- }
- void TileMap::_recompute_rect_cache() {
- // Compute the displayed area of the tilemap.
- #ifdef DEBUG_ENABLED
- if (!rect_cache_dirty) {
- return;
- }
- Rect2 r_total;
- for (Map<Vector2i, TileMapQuadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
- Rect2 r;
- r.position = map_to_world(E->key() * get_effective_quadrant_size());
- r.expand_to(map_to_world((E->key() + Vector2i(1, 0)) * get_effective_quadrant_size()));
- r.expand_to(map_to_world((E->key() + Vector2i(1, 1)) * get_effective_quadrant_size()));
- r.expand_to(map_to_world((E->key() + Vector2i(0, 1)) * get_effective_quadrant_size()));
- if (E == quadrant_map.front()) {
- r_total = r;
- } else {
- r_total = r_total.merge(r);
- }
- }
- rect_cache = r_total;
- item_rect_changed();
- rect_cache_dirty = false;
- #endif
- }
- Map<Vector2i, TileMapQuadrant>::Element *TileMap::_create_quadrant(const Vector2i &p_qk) {
- TileMapQuadrant q;
- q.coords = p_qk;
- rect_cache_dirty = true;
- // Create the debug canvas item.
- RenderingServer *rs = RenderingServer::get_singleton();
- q.debug_canvas_item = rs->canvas_item_create();
- rs->canvas_item_set_z_index(q.debug_canvas_item, RS::CANVAS_ITEM_Z_MAX - 1);
- rs->canvas_item_set_parent(q.debug_canvas_item, get_canvas_item());
- // Call the create_quadrant method on plugins
- if (tile_set.is_valid()) {
- for (int i = 0; i < tile_set->get_tile_set_atlas_plugins().size(); i++) {
- tile_set->get_tile_set_atlas_plugins()[i]->create_quadrant(this, &q);
- }
- }
- return quadrant_map.insert(p_qk, q);
- }
- void TileMap::_erase_quadrant(Map<Vector2i, TileMapQuadrant>::Element *Q) {
- // Remove a quadrant.
- TileMapQuadrant *q = &(Q->get());
- // Call the cleanup_quadrant method on plugins.
- if (tile_set.is_valid()) {
- for (int i = 0; i < tile_set->get_tile_set_atlas_plugins().size(); i++) {
- tile_set->get_tile_set_atlas_plugins()[i]->cleanup_quadrant(this, q);
- }
- }
- // Remove the quadrant from the dirty_list if it is there.
- if (q->dirty_list_element.in_list()) {
- dirty_quadrant_list.remove(&(q->dirty_list_element));
- }
- // Free the debug canvas item.
- RenderingServer *rs = RenderingServer::get_singleton();
- rs->free(q->debug_canvas_item);
- quadrant_map.erase(Q);
- rect_cache_dirty = true;
- }
- void TileMap::_make_all_quadrants_dirty(bool p_update) {
- // Make all quandrants dirty, then trigger an update later.
- for (Map<Vector2i, TileMapQuadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
- if (!E->value().dirty_list_element.in_list()) {
- dirty_quadrant_list.add(&E->value().dirty_list_element);
- }
- }
- if (pending_update) {
- return;
- }
- pending_update = true;
- if (!is_inside_tree()) {
- return;
- }
- if (p_update) {
- call_deferred("update_dirty_quadrants");
- }
- }
- void TileMap::_make_quadrant_dirty(Map<Vector2i, TileMapQuadrant>::Element *Q, bool p_update) {
- // Make the given quadrant dirty, then trigger an update later.
- TileMapQuadrant &q = Q->get();
- if (!q.dirty_list_element.in_list()) {
- dirty_quadrant_list.add(&q.dirty_list_element);
- }
- if (pending_update) {
- return;
- }
- pending_update = true;
- if (!is_inside_tree()) {
- return;
- }
- if (p_update) {
- call_deferred("update_dirty_quadrants");
- }
- }
- void TileMap::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
- // Set the current cell tile (using integer position).
- Vector2i pk(p_coords);
- Map<Vector2i, TileMapCell>::Element *E = tile_map.find(pk);
- int source_id = p_source_id;
- Vector2i atlas_coords = p_atlas_coords;
- int alternative_tile = p_alternative_tile;
- if ((source_id == -1 || atlas_coords == TileSetAtlasSource::INVALID_ATLAS_COORDS || alternative_tile == TileSetAtlasSource::INVALID_TILE_ALTERNATIVE) &&
- (source_id != -1 || atlas_coords != TileSetAtlasSource::INVALID_ATLAS_COORDS || alternative_tile != TileSetAtlasSource::INVALID_TILE_ALTERNATIVE)) {
- WARN_PRINT("Setting a cell a cell as empty requires both source_id, atlas_coord and alternative_tile to be set to their respective \"invalid\" values. Values were thus changes accordingly.");
- source_id = -1;
- atlas_coords = TileSetAtlasSource::INVALID_ATLAS_COORDS;
- alternative_tile = TileSetAtlasSource::INVALID_TILE_ALTERNATIVE;
- }
- if (!E && source_id == -1) {
- return; // Nothing to do, the tile is already empty.
- }
- // Get the quadrant
- Vector2i qk = _coords_to_quadrant_coords(pk);
- Map<Vector2i, TileMapQuadrant>::Element *Q = quadrant_map.find(qk);
- if (source_id == -1) {
- // Erase existing cell in the tile map.
- tile_map.erase(pk);
- // Erase existing cell in the quadrant.
- ERR_FAIL_COND(!Q);
- TileMapQuadrant &q = Q->get();
- q.cells.erase(pk);
- // Remove or make the quadrant dirty.
- if (q.cells.size() == 0) {
- _erase_quadrant(Q);
- } else {
- _make_quadrant_dirty(Q);
- }
- used_size_cache_dirty = true;
- } else {
- if (!E) {
- // Insert a new cell in the tile map.
- E = tile_map.insert(pk, TileMapCell());
- // Create a new quadrant if needed, then insert the cell if needed.
- if (!Q) {
- Q = _create_quadrant(qk);
- }
- TileMapQuadrant &q = Q->get();
- q.cells.insert(pk);
- } else {
- ERR_FAIL_COND(!Q); // TileMapQuadrant should exist...
- if (E->get().source_id == source_id && E->get().get_atlas_coords() == atlas_coords && E->get().alternative_tile == alternative_tile) {
- return; // Nothing changed.
- }
- }
- TileMapCell &c = E->get();
- c.source_id = source_id;
- c.set_atlas_coords(atlas_coords);
- c.alternative_tile = alternative_tile;
- _make_quadrant_dirty(Q);
- used_size_cache_dirty = true;
- }
- }
- int TileMap::get_cell_source_id(const Vector2i &p_coords) const {
- // Get a cell source id from position
- const Map<Vector2i, TileMapCell>::Element *E = tile_map.find(p_coords);
- if (!E) {
- return -1;
- }
- return E->get().source_id;
- }
- Vector2i TileMap::get_cell_atlas_coords(const Vector2i &p_coords) const {
- // Get a cell source id from position
- const Map<Vector2i, TileMapCell>::Element *E = tile_map.find(p_coords);
- if (!E) {
- return TileSetAtlasSource::INVALID_ATLAS_COORDS;
- }
- return E->get().get_atlas_coords();
- }
- int TileMap::get_cell_alternative_tile(const Vector2i &p_coords) const {
- // Get a cell source id from position
- const Map<Vector2i, TileMapCell>::Element *E = tile_map.find(p_coords);
- if (!E) {
- return TileSetAtlasSource::INVALID_TILE_ALTERNATIVE;
- }
- return E->get().alternative_tile;
- }
- TileMapPattern *TileMap::get_pattern(TypedArray<Vector2i> p_coords_array) {
- ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr);
- TileMapPattern *output = memnew(TileMapPattern);
- if (p_coords_array.is_empty()) {
- return output;
- }
- Vector2i min = Vector2i(p_coords_array[0]);
- for (int i = 1; i < p_coords_array.size(); i++) {
- min = min.min(p_coords_array[i]);
- }
- Vector<Vector2i> coords_in_pattern_array;
- coords_in_pattern_array.resize(p_coords_array.size());
- Vector2i ensure_positive_offset;
- for (int i = 0; i < p_coords_array.size(); i++) {
- Vector2i coords = p_coords_array[i];
- Vector2i coords_in_pattern = coords - min;
- if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE) {
- if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED) {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(min.y % 2) && bool(coords_in_pattern.y % 2)) {
- coords_in_pattern.x -= 1;
- if (coords_in_pattern.x < 0) {
- ensure_positive_offset.x = 1;
- }
- } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(min.x % 2) && bool(coords_in_pattern.x % 2)) {
- coords_in_pattern.y -= 1;
- if (coords_in_pattern.y < 0) {
- ensure_positive_offset.y = 1;
- }
- }
- } else if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED_OFFSET) {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(min.y % 2) && bool(coords_in_pattern.y % 2)) {
- coords_in_pattern.x += 1;
- } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(min.x % 2) && bool(coords_in_pattern.x % 2)) {
- coords_in_pattern.y += 1;
- }
- }
- }
- coords_in_pattern_array.write[i] = coords_in_pattern;
- }
- for (int i = 0; i < coords_in_pattern_array.size(); i++) {
- Vector2i coords = p_coords_array[i];
- Vector2i coords_in_pattern = coords_in_pattern_array[i];
- output->set_cell(coords_in_pattern + ensure_positive_offset, get_cell_source_id(coords), get_cell_atlas_coords(coords), get_cell_alternative_tile(coords));
- }
- return output;
- }
- Vector2i TileMap::map_pattern(Vector2i p_position_in_tilemap, Vector2i p_coords_in_pattern, const TileMapPattern *p_pattern) {
- ERR_FAIL_COND_V(!p_pattern->has_cell(p_coords_in_pattern), Vector2i());
- Vector2i output = p_position_in_tilemap + p_coords_in_pattern;
- if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE) {
- if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED) {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(p_position_in_tilemap.y % 2) && bool(p_coords_in_pattern.y % 2)) {
- output.x += 1;
- } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(p_position_in_tilemap.x % 2) && bool(p_coords_in_pattern.x % 2)) {
- output.y += 1;
- }
- } else if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED_OFFSET) {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(p_position_in_tilemap.y % 2) && bool(p_coords_in_pattern.y % 2)) {
- output.x -= 1;
- } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(p_position_in_tilemap.x % 2) && bool(p_coords_in_pattern.x % 2)) {
- output.y -= 1;
- }
- }
- }
- return output;
- }
- void TileMap::set_pattern(Vector2i p_position, const TileMapPattern *p_pattern) {
- ERR_FAIL_COND(!tile_set.is_valid());
- TypedArray<Vector2i> used_cells = p_pattern->get_used_cells();
- for (int i = 0; i < used_cells.size(); i++) {
- Vector2i coords = map_pattern(p_position, used_cells[i], p_pattern);
- set_cell(coords, p_pattern->get_cell_source_id(coords), p_pattern->get_cell_atlas_coords(coords), p_pattern->get_cell_alternative_tile(coords));
- }
- }
- TileMapCell TileMap::get_cell(const Vector2i &p_coords) const {
- if (!tile_map.has(p_coords)) {
- return TileMapCell();
- } else {
- return tile_map.find(p_coords)->get();
- }
- }
- Map<Vector2i, TileMapQuadrant> &TileMap::get_quadrant_map() {
- return quadrant_map;
- }
- void TileMap::fix_invalid_tiles() {
- ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot fix invalid tiles if Tileset is not open.");
- for (Map<Vector2i, TileMapCell>::Element *E = tile_map.front(); E; E = E->next()) {
- TileSetSource *source = *tile_set->get_source(E->get().source_id);
- if (!source || !source->has_tile(E->get().get_atlas_coords()) || !source->has_alternative_tile(E->get().get_atlas_coords(), E->get().alternative_tile)) {
- set_cell(E->key(), -1, TileSetAtlasSource::INVALID_ATLAS_COORDS, TileSetAtlasSource::INVALID_TILE_ALTERNATIVE);
- }
- }
- }
- void TileMap::_recreate_quadrants() {
- // Clear then recreate all quadrants.
- _clear_quadrants();
- for (Map<Vector2i, TileMapCell>::Element *E = tile_map.front(); E; E = E->next()) {
- Vector2i qk = _coords_to_quadrant_coords(Vector2i(E->key().x, E->key().y));
- Map<Vector2i, TileMapQuadrant>::Element *Q = quadrant_map.find(qk);
- if (!Q) {
- Q = _create_quadrant(qk);
- dirty_quadrant_list.add(&Q->get().dirty_list_element);
- }
- Vector2i pk = E->key();
- Q->get().cells.insert(pk);
- _make_quadrant_dirty(Q, false);
- }
- update_dirty_quadrants();
- }
- void TileMap::_clear_quadrants() {
- // Clear quadrants.
- while (quadrant_map.size()) {
- _erase_quadrant(quadrant_map.front());
- }
- // Clear the dirty quadrants list.
- while (dirty_quadrant_list.first()) {
- dirty_quadrant_list.remove(dirty_quadrant_list.first());
- }
- }
- void TileMap::clear() {
- // Remove all tiles.
- _clear_quadrants();
- tile_map.clear();
- used_size_cache_dirty = true;
- }
- void TileMap::_set_tile_data(const Vector<int> &p_data) {
- // Set data for a given tile from raw data.
- ERR_FAIL_COND(format > FORMAT_3);
- int c = p_data.size();
- const int *r = p_data.ptr();
- int offset = (format >= FORMAT_2) ? 3 : 2;
- clear();
- for (int i = 0; i < c; i += offset) {
- const uint8_t *ptr = (const uint8_t *)&r[i];
- uint8_t local[12];
- for (int j = 0; j < ((format >= FORMAT_2) ? 12 : 8); j++) {
- local[j] = ptr[j];
- }
- #ifdef BIG_ENDIAN_ENABLED
- SWAP(local[0], local[3]);
- SWAP(local[1], local[2]);
- SWAP(local[4], local[7]);
- SWAP(local[5], local[6]);
- //TODO: ask someone to check this...
- if (FORMAT >= FORMAT_2) {
- SWAP(local[8], local[11]);
- SWAP(local[9], local[10]);
- }
- #endif
- int16_t x = decode_uint16(&local[0]);
- int16_t y = decode_uint16(&local[2]);
- if (format == FORMAT_3) {
- uint16_t source_id = decode_uint16(&local[4]);
- uint16_t atlas_coords_x = decode_uint16(&local[6]);
- uint16_t atlas_coords_y = decode_uint32(&local[8]);
- uint16_t alternative_tile = decode_uint16(&local[10]);
- set_cell(Vector2i(x, y), source_id, Vector2i(atlas_coords_x, atlas_coords_y), alternative_tile);
- } else {
- uint32_t v = decode_uint32(&local[4]);
- v &= (1 << 29) - 1;
- // We generate an alternative tile number out of the the flags
- // An option should create the alternative in the tileset for compatibility
- bool flip_h = v & (1 << 29);
- bool flip_v = v & (1 << 30);
- bool transpose = v & (1 << 31);
- int16_t coord_x = 0;
- int16_t coord_y = 0;
- if (format == FORMAT_2) {
- coord_x = decode_uint16(&local[8]);
- coord_y = decode_uint16(&local[10]);
- }
- int compatibility_alternative_tile = ((int)flip_h) + ((int)flip_v << 1) + ((int)transpose << 2);
- if (tile_set.is_valid()) {
- v = tile_set->compatibility_get_source_for_tile_id(v);
- }
- set_cell(Vector2i(x, y), v, Vector2i(coord_x, coord_y), compatibility_alternative_tile);
- }
- }
- }
- Vector<int> TileMap::_get_tile_data() const {
- // Export tile data to raw format
- Vector<int> data;
- data.resize(tile_map.size() * 3);
- int *w = data.ptrw();
- // Save in highest format
- int idx = 0;
- for (const Map<Vector2i, TileMapCell>::Element *E = tile_map.front(); E; E = E->next()) {
- uint8_t *ptr = (uint8_t *)&w[idx];
- encode_uint16((int16_t)(E->key().x), &ptr[0]);
- encode_uint16((int16_t)(E->key().y), &ptr[2]);
- encode_uint16(E->get().source_id, &ptr[4]);
- encode_uint16(E->get().coord_x, &ptr[6]);
- encode_uint16(E->get().coord_y, &ptr[8]);
- encode_uint16(E->get().alternative_tile, &ptr[10]);
- idx += 3;
- }
- return data;
- }
- #ifdef TOOLS_ENABLED
- Rect2 TileMap::_edit_get_rect() const {
- // Return the visible rect of the tilemap
- if (pending_update) {
- const_cast<TileMap *>(this)->update_dirty_quadrants();
- } else {
- const_cast<TileMap *>(this)->_recompute_rect_cache();
- }
- return rect_cache;
- }
- #endif
- bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
- if (p_name == "format") {
- if (p_value.get_type() == Variant::INT) {
- format = (DataFormat)(p_value.operator int64_t()); // Set format used for loading
- return true;
- }
- } else if (p_name == "tile_data") {
- if (p_value.is_array()) {
- _set_tile_data(p_value);
- return true;
- }
- return false;
- }
- return false;
- }
- bool TileMap::_get(const StringName &p_name, Variant &r_ret) const {
- if (p_name == "format") {
- r_ret = FORMAT_3; // When saving, always save highest format
- return true;
- } else if (p_name == "tile_data") {
- r_ret = _get_tile_data();
- return true;
- }
- return false;
- }
- void TileMap::_get_property_list(List<PropertyInfo> *p_list) const {
- PropertyInfo p(Variant::INT, "format", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL);
- p_list->push_back(p);
- p = PropertyInfo(Variant::OBJECT, "tile_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL);
- p_list->push_back(p);
- }
- Vector2 TileMap::map_to_world(const Vector2i &p_pos) const {
- // SHOULD RETURN THE CENTER OF THE TILE
- ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2());
- Vector2 ret = p_pos;
- TileSet::TileShape tile_shape = tile_set->get_tile_shape();
- TileSet::TileOffsetAxis tile_offset_axis = tile_set->get_tile_offset_axis();
- if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
- // Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap.
- // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap
- if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- switch (tile_set->get_tile_layout()) {
- case TileSet::TILE_LAYOUT_STACKED:
- ret = Vector2(ret.x + (Math::posmod(ret.y, 2) == 0 ? 0.0 : 0.5), ret.y);
- break;
- case TileSet::TILE_LAYOUT_STACKED_OFFSET:
- ret = Vector2(ret.x + (Math::posmod(ret.y, 2) == 1 ? 0.0 : 0.5), ret.y);
- break;
- case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
- ret = Vector2(ret.x + ret.y / 2, ret.y);
- break;
- case TileSet::TILE_LAYOUT_STAIRS_DOWN:
- ret = Vector2(ret.x / 2, ret.y * 2 + ret.x);
- break;
- case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
- ret = Vector2((ret.x + ret.y) / 2, ret.y - ret.x);
- break;
- case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
- ret = Vector2((ret.x - ret.y) / 2, ret.y + ret.x);
- break;
- }
- } else { // TILE_OFFSET_AXIS_VERTICAL
- switch (tile_set->get_tile_layout()) {
- case TileSet::TILE_LAYOUT_STACKED:
- ret = Vector2(ret.x, ret.y + (Math::posmod(ret.x, 2) == 0 ? 0.0 : 0.5));
- break;
- case TileSet::TILE_LAYOUT_STACKED_OFFSET:
- ret = Vector2(ret.x, ret.y + (Math::posmod(ret.x, 2) == 1 ? 0.0 : 0.5));
- break;
- case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
- ret = Vector2(ret.x * 2 + ret.y, ret.y / 2);
- break;
- case TileSet::TILE_LAYOUT_STAIRS_DOWN:
- ret = Vector2(ret.x, ret.y + ret.x / 2);
- break;
- case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
- ret = Vector2(ret.x + ret.y, (ret.y - ret.x) / 2);
- break;
- case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
- ret = Vector2(ret.x - ret.y, (ret.y + ret.x) / 2);
- break;
- }
- }
- }
- // Multiply by the overlapping ratio
- double overlapping_ratio = 1.0;
- if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
- overlapping_ratio = 0.5;
- } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
- overlapping_ratio = 0.75;
- }
- ret.y *= overlapping_ratio;
- } else { // TILE_OFFSET_AXIS_VERTICAL
- if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
- overlapping_ratio = 0.5;
- } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
- overlapping_ratio = 0.75;
- }
- ret.x *= overlapping_ratio;
- }
- return (ret + Vector2(0.5, 0.5)) * tile_set->get_tile_size();
- }
- Vector2i TileMap::world_to_map(const Vector2 &p_pos) const {
- ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2i());
- Vector2 ret = p_pos;
- ret /= tile_set->get_tile_size();
- TileSet::TileShape tile_shape = tile_set->get_tile_shape();
- TileSet::TileOffsetAxis tile_offset_axis = tile_set->get_tile_offset_axis();
- TileSet::TileLayout tile_layout = tile_set->get_tile_layout();
- // Divide by the overlapping ratio
- double overlapping_ratio = 1.0;
- if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
- overlapping_ratio = 0.5;
- } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
- overlapping_ratio = 0.75;
- }
- ret.y /= overlapping_ratio;
- } else { // TILE_OFFSET_AXIS_VERTICAL
- if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
- overlapping_ratio = 0.5;
- } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
- overlapping_ratio = 0.75;
- }
- ret.x /= overlapping_ratio;
- }
- // For each half-offset shape, we check if we are in the corner of the tile, and thus should correct the world position accordingly.
- if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
- // Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap.
- // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap
- if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- // Smart floor of the position
- Vector2 raw_pos = ret;
- if (Math::posmod(Math::floor(ret.y), 2) ^ (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET)) {
- ret = Vector2(Math::floor(ret.x + 0.5) - 0.5, Math::floor(ret.y));
- } else {
- ret = ret.floor();
- }
- // Compute the tile offset, and if we might the output for a neighbour top tile
- Vector2 in_tile_pos = raw_pos - ret;
- bool in_top_left_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(-0.5, 1.0 / overlapping_ratio - 1)) <= 0;
- bool in_top_right_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(0.5, 1.0 / overlapping_ratio - 1)) > 0;
- switch (tile_layout) {
- case TileSet::TILE_LAYOUT_STACKED:
- ret = ret.floor();
- if (in_top_left_triangle) {
- ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 0 : -1, -1);
- } else if (in_top_right_triangle) {
- ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 1 : 0, -1);
- }
- break;
- case TileSet::TILE_LAYOUT_STACKED_OFFSET:
- ret = ret.floor();
- if (in_top_left_triangle) {
- ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? -1 : 0, -1);
- } else if (in_top_right_triangle) {
- ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 0 : 1, -1);
- }
- break;
- case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
- ret = Vector2(ret.x - ret.y / 2, ret.y).floor();
- if (in_top_left_triangle) {
- ret += Vector2i(0, -1);
- } else if (in_top_right_triangle) {
- ret += Vector2i(1, -1);
- }
- break;
- case TileSet::TILE_LAYOUT_STAIRS_DOWN:
- ret = Vector2(ret.x * 2, ret.y / 2 - ret.x).floor();
- if (in_top_left_triangle) {
- ret += Vector2i(-1, 0);
- } else if (in_top_right_triangle) {
- ret += Vector2i(1, -1);
- }
- break;
- case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
- ret = Vector2(ret.x - ret.y / 2, ret.y / 2 + ret.x).floor();
- if (in_top_left_triangle) {
- ret += Vector2i(0, -1);
- } else if (in_top_right_triangle) {
- ret += Vector2i(1, 0);
- }
- break;
- case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
- ret = Vector2(ret.x + ret.y / 2, ret.y / 2 - ret.x).floor();
- if (in_top_left_triangle) {
- ret += Vector2i(-1, 0);
- } else if (in_top_right_triangle) {
- ret += Vector2i(0, -1);
- }
- break;
- }
- } else { // TILE_OFFSET_AXIS_VERTICAL
- // Smart floor of the position
- Vector2 raw_pos = ret;
- if (Math::posmod(Math::floor(ret.x), 2) ^ (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET)) {
- ret = Vector2(Math::floor(ret.x), Math::floor(ret.y + 0.5) - 0.5);
- } else {
- ret = ret.floor();
- }
- // Compute the tile offset, and if we might the output for a neighbour top tile
- Vector2 in_tile_pos = raw_pos - ret;
- bool in_top_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, -0.5)) > 0;
- bool in_bottom_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, 0.5)) <= 0;
- switch (tile_layout) {
- case TileSet::TILE_LAYOUT_STACKED:
- ret = ret.floor();
- if (in_top_left_triangle) {
- ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 0 : -1);
- } else if (in_bottom_left_triangle) {
- ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 1 : 0);
- }
- break;
- case TileSet::TILE_LAYOUT_STACKED_OFFSET:
- ret = ret.floor();
- if (in_top_left_triangle) {
- ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? -1 : 0);
- } else if (in_bottom_left_triangle) {
- ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 0 : 1);
- }
- break;
- case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
- ret = Vector2(ret.x / 2 - ret.y, ret.y * 2).floor();
- if (in_top_left_triangle) {
- ret += Vector2i(0, -1);
- } else if (in_bottom_left_triangle) {
- ret += Vector2i(-1, 1);
- }
- break;
- case TileSet::TILE_LAYOUT_STAIRS_DOWN:
- ret = Vector2(ret.x, ret.y - ret.x / 2).floor();
- if (in_top_left_triangle) {
- ret += Vector2i(-1, 0);
- } else if (in_bottom_left_triangle) {
- ret += Vector2i(-1, 1);
- }
- break;
- case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
- ret = Vector2(ret.x / 2 - ret.y, ret.y + ret.x / 2).floor();
- if (in_top_left_triangle) {
- ret += Vector2i(0, -1);
- } else if (in_bottom_left_triangle) {
- ret += Vector2i(-1, 0);
- }
- break;
- case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
- ret = Vector2(ret.x / 2 + ret.y, ret.y - ret.x / 2).floor();
- if (in_top_left_triangle) {
- ret += Vector2i(-1, 0);
- } else if (in_bottom_left_triangle) {
- ret += Vector2i(0, 1);
- }
- break;
- }
- }
- } else {
- ret = (ret + Vector2(0.00005, 0.00005)).floor();
- }
- return Vector2i(ret);
- }
- bool TileMap::is_existing_neighbor(TileSet::CellNeighbor p_cell_neighbor) const {
- ERR_FAIL_COND_V(!tile_set.is_valid(), false);
- TileSet::TileShape shape = tile_set->get_tile_shape();
- if (shape == TileSet::TILE_SHAPE_SQUARE) {
- return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
- return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
- } else {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
- } else {
- return p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE ||
- p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
- }
- }
- }
- Vector2i TileMap::get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const {
- ERR_FAIL_COND_V(!tile_set.is_valid(), p_coords);
- TileSet::TileShape shape = tile_set->get_tile_shape();
- if (shape == TileSet::TILE_SHAPE_SQUARE) {
- switch (p_cell_neighbor) {
- case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
- return p_coords + Vector2i(1, 0);
- case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
- return p_coords + Vector2i(1, 1);
- case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
- return p_coords + Vector2i(0, 1);
- case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
- return p_coords + Vector2i(-1, 1);
- case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
- return p_coords + Vector2i(-1, 0);
- case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
- return p_coords + Vector2i(-1, -1);
- case TileSet::CELL_NEIGHBOR_TOP_SIDE:
- return p_coords + Vector2i(0, -1);
- case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
- return p_coords + Vector2i(1, -1);
- default:
- ERR_FAIL_V(p_coords);
- }
- } else { // Half-offset shapes (square and hexagon)
- switch (tile_set->get_tile_layout()) {
- case TileSet::TILE_LAYOUT_STACKED: {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- bool is_offset = p_coords.y % 2;
- if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
- return p_coords + Vector2i(1, 0);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
- return p_coords + Vector2i(is_offset ? 1 : 0, 1);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
- return p_coords + Vector2i(0, 2);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
- return p_coords + Vector2i(is_offset ? 0 : -1, 1);
- } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
- return p_coords + Vector2i(-1, 0);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
- return p_coords + Vector2i(is_offset ? 0 : -1, -1);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
- return p_coords + Vector2i(0, -2);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
- return p_coords + Vector2i(is_offset ? 1 : 0, -1);
- } else {
- ERR_FAIL_V(p_coords);
- }
- } else {
- bool is_offset = p_coords.x % 2;
- if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
- return p_coords + Vector2i(0, 1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
- return p_coords + Vector2i(1, is_offset ? 1 : 0);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
- return p_coords + Vector2i(2, 0);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
- return p_coords + Vector2i(1, is_offset ? 0 : -1);
- } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
- return p_coords + Vector2i(0, -1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
- return p_coords + Vector2i(-1, is_offset ? 0 : -1);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
- return p_coords + Vector2i(-2, 0);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
- return p_coords + Vector2i(-1, is_offset ? 1 : 0);
- } else {
- ERR_FAIL_V(p_coords);
- }
- }
- } break;
- case TileSet::TILE_LAYOUT_STACKED_OFFSET: {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- bool is_offset = p_coords.y % 2;
- if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
- return p_coords + Vector2i(1, 0);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
- return p_coords + Vector2i(is_offset ? 0 : 1, 1);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
- return p_coords + Vector2i(0, 2);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
- return p_coords + Vector2i(is_offset ? -1 : 0, 1);
- } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
- return p_coords + Vector2i(-1, 0);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
- return p_coords + Vector2i(is_offset ? -1 : 0, -1);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
- return p_coords + Vector2i(0, -2);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
- return p_coords + Vector2i(is_offset ? 0 : 1, -1);
- } else {
- ERR_FAIL_V(p_coords);
- }
- } else {
- bool is_offset = p_coords.x % 2;
- if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
- return p_coords + Vector2i(0, 1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
- return p_coords + Vector2i(1, is_offset ? 0 : 1);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
- return p_coords + Vector2i(2, 0);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
- return p_coords + Vector2i(1, is_offset ? -1 : 0);
- } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
- return p_coords + Vector2i(0, -1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
- return p_coords + Vector2i(-1, is_offset ? -1 : 0);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
- return p_coords + Vector2i(-2, 0);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
- return p_coords + Vector2i(-1, is_offset ? 0 : 1);
- } else {
- ERR_FAIL_V(p_coords);
- }
- }
- } break;
- case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
- case TileSet::TILE_LAYOUT_STAIRS_DOWN: {
- if ((tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
- return p_coords + Vector2i(1, 0);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
- return p_coords + Vector2i(0, 1);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
- return p_coords + Vector2i(-1, 2);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
- return p_coords + Vector2i(-1, 1);
- } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
- return p_coords + Vector2i(-1, 0);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
- return p_coords + Vector2i(0, -1);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
- return p_coords + Vector2i(1, -2);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
- return p_coords + Vector2i(1, -1);
- } else {
- ERR_FAIL_V(p_coords);
- }
- } else {
- if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
- return p_coords + Vector2i(0, 1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
- return p_coords + Vector2i(1, 0);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
- return p_coords + Vector2i(2, -1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
- return p_coords + Vector2i(1, -1);
- } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
- return p_coords + Vector2i(0, -1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
- return p_coords + Vector2i(-1, 0);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
- return p_coords + Vector2i(-2, 1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
- return p_coords + Vector2i(-1, 1);
- } else {
- ERR_FAIL_V(p_coords);
- }
- }
- } else {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
- return p_coords + Vector2i(2, -1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
- return p_coords + Vector2i(1, 0);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
- return p_coords + Vector2i(0, 1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
- return p_coords + Vector2i(-1, 1);
- } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
- return p_coords + Vector2i(-2, 1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
- return p_coords + Vector2i(-1, 0);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
- return p_coords + Vector2i(0, -1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
- return p_coords + Vector2i(1, -1);
- } else {
- ERR_FAIL_V(p_coords);
- }
- } else {
- if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
- return p_coords + Vector2i(-1, 2);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
- return p_coords + Vector2i(0, 1);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
- return p_coords + Vector2i(1, 0);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
- return p_coords + Vector2i(1, -1);
- } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
- return p_coords + Vector2i(1, -2);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
- return p_coords + Vector2i(0, -1);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
- return p_coords + Vector2i(-1, 0);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
- return p_coords + Vector2i(-1, 1);
- } else {
- ERR_FAIL_V(p_coords);
- }
- }
- }
- } break;
- case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
- case TileSet::TILE_LAYOUT_DIAMOND_DOWN: {
- if ((tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
- return p_coords + Vector2i(1, 1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
- return p_coords + Vector2i(0, 1);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
- return p_coords + Vector2i(-1, 1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
- return p_coords + Vector2i(-1, 0);
- } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
- return p_coords + Vector2i(-1, -1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
- return p_coords + Vector2i(0, -1);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
- return p_coords + Vector2i(1, -1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
- return p_coords + Vector2i(1, 0);
- } else {
- ERR_FAIL_V(p_coords);
- }
- } else {
- if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
- return p_coords + Vector2i(1, 1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
- return p_coords + Vector2i(1, 0);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
- return p_coords + Vector2i(1, -1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
- return p_coords + Vector2i(0, -1);
- } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
- return p_coords + Vector2i(-1, -1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
- return p_coords + Vector2i(-1, 0);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
- return p_coords + Vector2i(-1, 1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
- return p_coords + Vector2i(0, 1);
- } else {
- ERR_FAIL_V(p_coords);
- }
- }
- } else {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
- return p_coords + Vector2i(1, -1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
- return p_coords + Vector2i(1, 0);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
- return p_coords + Vector2i(1, 1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
- return p_coords + Vector2i(0, 1);
- } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
- return p_coords + Vector2i(-1, 1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
- return p_coords + Vector2i(-1, 0);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
- return p_coords + Vector2i(-1, -1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
- return p_coords + Vector2i(0, -1);
- } else {
- ERR_FAIL_V(p_coords);
- }
- } else {
- if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
- return p_coords + Vector2i(-1, 1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
- return p_coords + Vector2i(0, 1);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
- return p_coords + Vector2i(1, 1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
- return p_coords + Vector2i(1, 0);
- } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
- (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
- return p_coords + Vector2i(1, -1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
- return p_coords + Vector2i(0, -1);
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
- return p_coords + Vector2i(-1, -1);
- } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
- return p_coords + Vector2i(-1, 0);
- } else {
- ERR_FAIL_V(p_coords);
- }
- }
- }
- } break;
- default:
- ERR_FAIL_V(p_coords);
- }
- }
- }
- TypedArray<Vector2i> TileMap::get_used_cells() const {
- // Returns the cells used in the tilemap.
- TypedArray<Vector2i> a;
- a.resize(tile_map.size());
- int i = 0;
- for (Map<Vector2i, TileMapCell>::Element *E = tile_map.front(); E; E = E->next()) {
- Vector2i p(E->key().x, E->key().y);
- a[i++] = p;
- }
- return a;
- }
- Rect2 TileMap::get_used_rect() { // Not const because of cache
- // Return the rect of the currently used area
- if (used_size_cache_dirty) {
- if (tile_map.size() > 0) {
- used_size_cache = Rect2(tile_map.front()->key().x, tile_map.front()->key().y, 0, 0);
- for (Map<Vector2i, TileMapCell>::Element *E = tile_map.front(); E; E = E->next()) {
- used_size_cache.expand_to(Vector2(E->key().x, E->key().y));
- }
- used_size_cache.size += Vector2(1, 1);
- } else {
- used_size_cache = Rect2();
- }
- used_size_cache_dirty = false;
- }
- return used_size_cache;
- }
- // --- Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems ---
- void TileMap::set_light_mask(int p_light_mask) {
- // Occlusion: set light mask.
- CanvasItem::set_light_mask(p_light_mask);
- for (Map<Vector2i, TileMapQuadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
- for (List<RID>::Element *F = E->get().canvas_items.front(); F; F = F->next()) {
- RenderingServer::get_singleton()->canvas_item_set_light_mask(F->get(), get_light_mask());
- }
- }
- }
- void TileMap::set_material(const Ref<Material> &p_material) {
- // Set material for the whole tilemap.
- CanvasItem::set_material(p_material);
- // Update material for the whole tilemap.
- for (Map<Vector2i, TileMapQuadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
- TileMapQuadrant &q = E->get();
- for (List<RID>::Element *F = q.canvas_items.front(); F; F = F->next()) {
- RS::get_singleton()->canvas_item_set_use_parent_material(F->get(), get_use_parent_material() || get_material().is_valid());
- }
- }
- }
- void TileMap::set_use_parent_material(bool p_use_parent_material) {
- // Set use_parent_material for the whole tilemap.
- CanvasItem::set_use_parent_material(p_use_parent_material);
- // Update use_parent_material for the whole tilemap.
- for (Map<Vector2i, TileMapQuadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
- TileMapQuadrant &q = E->get();
- for (List<RID>::Element *F = q.canvas_items.front(); F; F = F->next()) {
- RS::get_singleton()->canvas_item_set_use_parent_material(F->get(), get_use_parent_material() || get_material().is_valid());
- }
- }
- }
- void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
- // Set a default texture filter for the whole tilemap
- CanvasItem::set_texture_filter(p_texture_filter);
- for (Map<Vector2i, TileMapQuadrant>::Element *F = quadrant_map.front(); F; F = F->next()) {
- TileMapQuadrant &q = F->get();
- for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) {
- RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(E->get(), RS::CanvasItemTextureFilter(p_texture_filter));
- _make_quadrant_dirty(F);
- }
- }
- }
- void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
- // Set a default texture repeat for the whole tilemap
- CanvasItem::set_texture_repeat(p_texture_repeat);
- for (Map<Vector2i, TileMapQuadrant>::Element *F = quadrant_map.front(); F; F = F->next()) {
- TileMapQuadrant &q = F->get();
- for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) {
- RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(E->get(), RS::CanvasItemTextureRepeat(p_texture_repeat));
- _make_quadrant_dirty(F);
- }
- }
- }
- TypedArray<Vector2i> TileMap::get_surrounding_tiles(Vector2i coords) {
- if (!tile_set.is_valid()) {
- return TypedArray<Vector2i>();
- }
- TypedArray<Vector2i> around;
- TileSet::TileShape shape = tile_set->get_tile_shape();
- if (shape == TileSet::TILE_SHAPE_SQUARE) {
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_LEFT_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_SIDE));
- } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE));
- } else {
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_LEFT_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE));
- } else {
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_SIDE));
- around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE));
- }
- }
- return around;
- }
- void TileMap::draw_cells_outline(Control *p_control, Set<Vector2i> p_cells, Color p_color, Transform2D p_transform) {
- if (!tile_set.is_valid()) {
- return;
- }
- // Create a set.
- Vector2i tile_size = tile_set->get_tile_size();
- Vector<Vector2> uvs;
- if (tile_set->get_tile_shape() == TileSet::TILE_SHAPE_SQUARE) {
- uvs.append(Vector2(1.0, 0.0));
- uvs.append(Vector2(1.0, 1.0));
- uvs.append(Vector2(0.0, 1.0));
- uvs.append(Vector2(0.0, 0.0));
- } else {
- float overlap = 0.0;
- switch (tile_set->get_tile_shape()) {
- case TileSet::TILE_SHAPE_ISOMETRIC:
- overlap = 0.5;
- break;
- case TileSet::TILE_SHAPE_HEXAGON:
- overlap = 0.25;
- break;
- case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
- overlap = 0.0;
- break;
- default:
- break;
- }
- uvs.append(Vector2(1.0, overlap));
- uvs.append(Vector2(1.0, 1.0 - overlap));
- uvs.append(Vector2(0.5, 1.0));
- uvs.append(Vector2(0.0, 1.0 - overlap));
- uvs.append(Vector2(0.0, overlap));
- uvs.append(Vector2(0.5, 0.0));
- if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
- for (int i = 0; i < uvs.size(); i++) {
- uvs.write[i] = Vector2(uvs[i].y, uvs[i].x);
- }
- }
- }
- for (Set<Vector2i>::Element *E = p_cells.front(); E; E = E->next()) {
- Vector2 top_left = map_to_world(E->get()) - tile_size / 2;
- TypedArray<Vector2i> surrounding_tiles = get_surrounding_tiles(E->get());
- for (int i = 0; i < surrounding_tiles.size(); i++) {
- if (!p_cells.has(surrounding_tiles[i])) {
- p_control->draw_line(p_transform.xform(top_left + uvs[i] * tile_size), p_transform.xform(top_left + uvs[(i + 1) % uvs.size()] * tile_size), p_color);
- }
- }
- }
- }
- void TileMap::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_tileset", "tileset"), &TileMap::set_tileset);
- ClassDB::bind_method(D_METHOD("get_tileset"), &TileMap::get_tileset);
- ClassDB::bind_method(D_METHOD("set_quadrant_size", "size"), &TileMap::set_quadrant_size);
- ClassDB::bind_method(D_METHOD("get_quadrant_size"), &TileMap::get_quadrant_size);
- ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMap::set_cell, DEFVAL(-1), DEFVAL(TileSetAtlasSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetAtlasSource::INVALID_TILE_ALTERNATIVE));
- ClassDB::bind_method(D_METHOD("get_cell_source_id", "coords"), &TileMap::get_cell_source_id);
- ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "coords"), &TileMap::get_cell_atlas_coords);
- ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "coords"), &TileMap::get_cell_alternative_tile);
- ClassDB::bind_method(D_METHOD("fix_invalid_tiles"), &TileMap::fix_invalid_tiles);
- ClassDB::bind_method(D_METHOD("get_surrounding_tiles", "coords"), &TileMap::get_surrounding_tiles);
- ClassDB::bind_method(D_METHOD("clear"), &TileMap::clear);
- ClassDB::bind_method(D_METHOD("get_used_cells"), &TileMap::get_used_cells);
- ClassDB::bind_method(D_METHOD("get_used_rect"), &TileMap::get_used_rect);
- ClassDB::bind_method(D_METHOD("map_to_world", "map_position"), &TileMap::map_to_world);
- ClassDB::bind_method(D_METHOD("world_to_map", "world_position"), &TileMap::world_to_map);
- ClassDB::bind_method(D_METHOD("get_neighbor_cell", "coords", "neighbor"), &TileMap::get_neighbor_cell);
- ClassDB::bind_method(D_METHOD("update_dirty_quadrants"), &TileMap::update_dirty_quadrants);
- ClassDB::bind_method(D_METHOD("_set_tile_data"), &TileMap::_set_tile_data);
- ClassDB::bind_method(D_METHOD("_get_tile_data"), &TileMap::_get_tile_data);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_set", PROPERTY_HINT_RESOURCE_TYPE, "TileSet"), "set_tileset", "get_tileset");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_quadrant_size", PROPERTY_HINT_RANGE, "1,128,1"), "set_quadrant_size", "get_quadrant_size");
- ADD_PROPERTY_DEFAULT("format", FORMAT_1);
- ADD_SIGNAL(MethodInfo("changed"));
- }
- void TileMap::_tile_set_changed() {
- emit_signal("changed");
- _make_all_quadrants_dirty(true);
- }
- TileMap::TileMap() {
- rect_cache_dirty = true;
- used_size_cache_dirty = true;
- pending_update = false;
- quadrant_size = 16;
- format = FORMAT_1; // Assume lowest possible format if none is present
- set_notify_transform(true);
- set_notify_local_transform(false);
- }
- TileMap::~TileMap() {
- if (tile_set.is_valid()) {
- tile_set->disconnect("changed", callable_mp(this, &TileMap::_tile_set_changed));
- }
- _clear_quadrants();
- }
|