2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* tile_map.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:16:55 +00:00
/* https://godotengine.org */
2014-02-10 01:10:30 +00:00
/*************************************************************************/
2021-01-01 19:13:46 +00:00
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 01:10:30 +00:00
/* */
/* 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. */
/*************************************************************************/
2018-01-04 23:50:27 +00:00
2014-02-10 01:10:30 +00:00
# include "tile_map.h"
2017-12-10 15:40:31 +00:00
2018-09-11 16:13:45 +00:00
# include "core/io/marshalls.h"
2021-05-07 13:41:39 +00:00
# include "core/math/geometry_2d.h"
2018-09-11 16:13:45 +00:00
# include "core/os/os.h"
2015-12-12 13:45:31 +00:00
2021-05-07 13:41:39 +00:00
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 ) ;
2015-03-09 05:34:56 +00:00
}
2021-05-07 13:41:39 +00:00
bool TileMapPattern : : has_cell ( const Vector2i & p_coords ) const {
return pattern . has ( p_coords ) ;
}
2019-02-05 23:45:40 +00:00
2021-05-07 13:41:39 +00:00
void TileMapPattern : : remove_cell ( const Vector2i & p_coords , bool p_update_size ) {
ERR_FAIL_COND ( ! pattern . has ( p_coords ) ) ;
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
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 ) ) ;
}
}
}
2019-02-05 23:45:40 +00:00
2021-05-07 13:41:39 +00:00
int TileMapPattern : : get_cell_source_id ( const Vector2i & p_coords ) const {
2021-07-06 12:43:03 +00:00
ERR_FAIL_COND_V ( ! pattern . has ( p_coords ) , TileSet : : INVALID_SOURCE ) ;
2015-03-09 05:34:56 +00:00
2021-05-07 13:41:39 +00:00
return pattern [ p_coords ] . source_id ;
}
2019-02-05 23:45:40 +00:00
2021-05-07 13:41:39 +00:00
Vector2i TileMapPattern : : get_cell_atlas_coords ( const Vector2i & p_coords ) const {
2021-05-18 13:40:52 +00:00
ERR_FAIL_COND_V ( ! pattern . has ( p_coords ) , TileSetSource : : INVALID_ATLAS_COORDS ) ;
2015-03-09 05:34:56 +00:00
2021-05-07 13:41:39 +00:00
return pattern [ p_coords ] . get_atlas_coords ( ) ;
}
2019-02-05 23:45:40 +00:00
2021-05-07 13:41:39 +00:00
int TileMapPattern : : get_cell_alternative_tile ( const Vector2i & p_coords ) const {
2021-05-18 13:40:52 +00:00
ERR_FAIL_COND_V ( ! pattern . has ( p_coords ) , TileSetSource : : INVALID_TILE_ALTERNATIVE ) ;
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
return pattern [ p_coords ] . alternative_tile ;
}
2019-02-05 23:45:40 +00:00
2021-05-07 13:41:39 +00:00
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 ;
2014-02-10 01:10:30 +00:00
}
2021-05-07 13:41:39 +00:00
return a ;
2014-02-10 01:10:30 +00:00
}
2021-05-07 13:41:39 +00:00
Vector2i TileMapPattern : : get_size ( ) const {
return size ;
2014-02-10 01:10:30 +00:00
}
2021-05-07 13:41:39 +00:00
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 ) ) ;
} ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
size = p_size ;
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
bool TileMapPattern : : is_empty ( ) const {
return pattern . is_empty ( ) ;
} ;
2019-02-05 23:45:40 +00:00
2021-05-07 13:41:39 +00:00
void TileMapPattern : : clear ( ) {
size = Vector2i ( ) ;
pattern . clear ( ) ;
} ;
2019-02-05 23:45:40 +00:00
2021-05-07 13:41:39 +00:00
void TileMapPattern : : _bind_methods ( ) {
2021-07-06 12:43:03 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_cell " , " coords " , " source_id " , " atlas_coords " , " alternative_tile " ) , & TileMapPattern : : set_cell , DEFVAL ( TileSet : : INVALID_SOURCE ) , DEFVAL ( TileSetSource : : INVALID_ATLAS_COORDS ) , DEFVAL ( TileSetSource : : INVALID_TILE_ALTERNATIVE ) ) ;
2021-05-07 13:41:39 +00:00
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 ) ;
2015-03-09 05:34:56 +00:00
2021-05-07 13:41:39 +00:00
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 ;
2015-03-09 05:34:56 +00:00
}
2021-05-07 13:41:39 +00:00
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 ;
}
2015-03-09 05:34:56 +00:00
2021-05-07 13:41:39 +00:00
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 ;
2014-02-10 01:10:30 +00:00
}
2021-05-07 13:41:39 +00:00
if ( p_offset_axis = = TileSet : : TILE_OFFSET_AXIS_VERTICAL ) {
SWAP ( output . x , output . y ) ;
2018-03-11 11:24:50 +00:00
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
return output ;
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
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 ;
2018-03-11 11:24:50 +00:00
} else {
2021-05-07 13:41:39 +00:00
return quadrant_size ;
2018-03-11 11:24:50 +00:00
}
2021-05-07 13:41:39 +00:00
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
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 ) ;
}
}
2014-02-10 01:10:30 +00:00
}
Ref < TileSet > TileMap : : get_tileset ( ) const {
return tile_set ;
}
2021-05-07 13:41:39 +00:00
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 ) ) ;
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
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 ( ) ;
}
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " changed " ) ) ;
2014-02-10 01:10:30 +00:00
}
2017-12-10 15:40:31 +00:00
2021-05-07 13:41:39 +00:00
int TileMap : : get_quadrant_size ( ) const {
return quadrant_size ;
2014-02-10 01:10:30 +00:00
}
2017-12-10 15:40:31 +00:00
2014-02-10 01:10:30 +00:00
void TileMap : : set_quadrant_size ( int p_size ) {
2021-05-07 13:41:39 +00:00
ERR_FAIL_COND_MSG ( p_size < 1 , " TileMapQuadrant size cannot be smaller than 1. " ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
quadrant_size = p_size ;
2014-02-10 01:10:30 +00:00
_recreate_quadrants ( ) ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " changed " ) ) ;
2014-02-10 01:10:30 +00:00
}
2021-05-24 10:33:22 +00:00
void TileMap : : set_collision_visibility_mode ( TileMap : : VisibilityMode p_show_collision ) {
show_collision = p_show_collision ;
_recreate_quadrants ( ) ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " changed " ) ) ;
2021-05-24 10:33:22 +00:00
}
2019-05-15 02:14:27 +00:00
2021-05-24 10:33:22 +00:00
TileMap : : VisibilityMode TileMap : : get_collision_visibility_mode ( ) {
return show_collision ;
}
2019-05-15 02:14:27 +00:00
2021-05-24 10:33:22 +00:00
void TileMap : : set_navigation_visibility_mode ( TileMap : : VisibilityMode p_show_navigation ) {
show_navigation = p_show_navigation ;
_recreate_quadrants ( ) ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " changed " ) ) ;
2021-05-24 10:33:22 +00:00
}
2019-07-01 20:43:52 +00:00
2021-05-24 10:33:22 +00:00
TileMap : : VisibilityMode TileMap : : get_navigation_visibility_mode ( ) {
return show_navigation ;
2015-03-09 05:34:56 +00:00
}
2020-09-23 19:49:50 +00:00
void TileMap : : set_y_sort_enabled ( bool p_enable ) {
Node2D : : set_y_sort_enabled ( p_enable ) ;
_recreate_quadrants ( ) ;
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " changed " ) ) ;
2020-09-23 19:49:50 +00:00
}
2018-07-22 13:26:14 +00:00
void TileMap : : update_dirty_quadrants ( ) {
2020-05-14 14:41:43 +00:00
if ( ! pending_update ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-01-01 17:31:29 +00:00
if ( ! is_inside_tree ( ) | | ! tile_set . is_valid ( ) ) {
pending_update = false ;
2014-02-10 01:10:30 +00:00
return ;
2017-01-01 17:31:29 +00:00
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
// 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 ;
}
2015-09-20 16:03:46 +00:00
}
2021-05-07 13:41:39 +00:00
// 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 ) ;
2018-03-25 16:22:36 +00:00
}
2021-05-07 13:41:39 +00:00
// 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 ( ) ) ;
2014-02-10 01:10:30 +00:00
}
2021-05-07 13:41:39 +00:00
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
// Clear the list
while ( dirty_quadrant_list . first ( ) ) {
2017-03-05 15:44:50 +00:00
dirty_quadrant_list . remove ( dirty_quadrant_list . first ( ) ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
pending_update = false ;
2014-02-10 01:10:30 +00:00
_recompute_rect_cache ( ) ;
}
void TileMap : : _recompute_rect_cache ( ) {
2021-05-07 13:41:39 +00:00
// Compute the displayed area of the tilemap.
2014-02-10 01:10:30 +00:00
# ifdef DEBUG_ENABLED
2020-05-14 14:41:43 +00:00
if ( ! rect_cache_dirty ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
Rect2 r_total ;
2021-05-07 13:41:39 +00:00
for ( Map < Vector2i , TileMapQuadrant > : : Element * E = quadrant_map . front ( ) ; E ; E = E - > next ( ) ) {
2014-10-03 03:10:51 +00:00
Rect2 r ;
2021-05-07 13:41:39 +00:00
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 ( ) ) ) ;
2020-05-14 14:41:43 +00:00
if ( E = = quadrant_map . front ( ) ) {
2017-03-05 15:44:50 +00:00
r_total = r ;
2020-05-14 14:41:43 +00:00
} else {
2017-03-05 15:44:50 +00:00
r_total = r_total . merge ( r ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2014-10-03 11:58:41 +00:00
2018-07-29 21:09:59 +00:00
rect_cache = r_total ;
2014-02-10 01:10:30 +00:00
item_rect_changed ( ) ;
2017-03-05 15:44:50 +00:00
rect_cache_dirty = false ;
2014-02-10 01:10:30 +00:00
# endif
}
2021-05-07 13:41:39 +00:00
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 ( ) ) ;
2019-02-05 23:45:40 +00:00
2021-05-07 13:41:39 +00:00
// 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 ) ;
}
2019-02-05 23:45:40 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
return quadrant_map . insert ( p_qk , q ) ;
2014-02-10 01:10:30 +00:00
}
2021-05-07 13:41:39 +00:00
void TileMap : : _erase_quadrant ( Map < Vector2i , TileMapQuadrant > : : Element * Q ) {
// Remove a quadrant.
TileMapQuadrant * q = & ( Q - > get ( ) ) ;
2019-02-05 23:45:40 +00:00
2021-05-07 13:41:39 +00:00
// 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 ) ;
}
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
// 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 ) ) ;
2015-03-09 05:34:56 +00:00
}
2021-05-07 13:41:39 +00:00
// Free the debug canvas item.
RenderingServer * rs = RenderingServer : : get_singleton ( ) ;
rs - > free ( q - > debug_canvas_item ) ;
2015-03-09 05:34:56 +00:00
2014-02-10 01:10:30 +00:00
quadrant_map . erase ( Q ) ;
2017-03-05 15:44:50 +00:00
rect_cache_dirty = true ;
2014-02-10 01:10:30 +00:00
}
2021-05-07 13:41:39 +00:00
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 ) ;
}
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( pending_update ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-03-05 15:44:50 +00:00
pending_update = true ;
2020-05-14 14:41:43 +00:00
if ( ! is_inside_tree ( ) ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2021-05-07 13:41:39 +00:00
if ( p_update ) {
2021-07-17 21:22:52 +00:00
call_deferred ( SNAME ( " update_dirty_quadrants " ) ) ;
2018-06-26 01:24:12 +00:00
}
2014-02-10 01:10:30 +00:00
}
2021-05-07 13:41:39 +00:00
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 ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
if ( pending_update ) {
2014-02-10 01:10:30 +00:00
return ;
}
2021-05-07 13:41:39 +00:00
pending_update = true ;
if ( ! is_inside_tree ( ) ) {
return ;
2014-02-10 01:10:30 +00:00
}
2021-05-07 13:41:39 +00:00
if ( p_update ) {
2021-07-17 21:22:52 +00:00
call_deferred ( SNAME ( " update_dirty_quadrants " ) ) ;
2021-05-07 13:41:39 +00:00
}
2014-02-10 01:10:30 +00:00
}
2021-05-07 13:41:39 +00:00
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 ) ;
2016-02-06 12:27:26 +00:00
2021-05-07 13:41:39 +00:00
int source_id = p_source_id ;
Vector2i atlas_coords = p_atlas_coords ;
int alternative_tile = p_alternative_tile ;
2017-10-22 01:42:23 +00:00
2021-07-06 12:43:03 +00:00
if ( ( source_id = = TileSet : : INVALID_SOURCE | | atlas_coords = = TileSetSource : : INVALID_ATLAS_COORDS | | alternative_tile = = TileSetSource : : INVALID_TILE_ALTERNATIVE ) & &
( source_id ! = TileSet : : INVALID_SOURCE | | atlas_coords ! = TileSetSource : : INVALID_ATLAS_COORDS | | alternative_tile ! = TileSetSource : : INVALID_TILE_ALTERNATIVE ) ) {
2021-05-07 13:41:39 +00:00
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. " ) ;
2021-07-06 12:43:03 +00:00
source_id = TileSet : : INVALID_SOURCE ;
2021-05-18 13:40:52 +00:00
atlas_coords = TileSetSource : : INVALID_ATLAS_COORDS ;
alternative_tile = TileSetSource : : INVALID_TILE_ALTERNATIVE ;
2017-10-22 01:42:23 +00:00
}
2021-07-06 12:43:03 +00:00
if ( ! E & & source_id = = TileSet : : INVALID_SOURCE ) {
2021-05-07 13:41:39 +00:00
return ; // Nothing to do, the tile is already empty.
2017-12-06 00:14:33 +00:00
}
2017-12-01 00:50:09 +00:00
2021-05-07 13:41:39 +00:00
// Get the quadrant
Vector2i qk = _coords_to_quadrant_coords ( pk ) ;
2018-12-20 17:17:52 +00:00
2021-05-07 13:41:39 +00:00
Map < Vector2i , TileMapQuadrant > : : Element * Q = quadrant_map . find ( qk ) ;
2018-12-23 13:06:53 +00:00
2021-07-06 12:43:03 +00:00
if ( source_id = = TileSet : : INVALID_SOURCE ) {
2021-05-07 13:41:39 +00:00
// Erase existing cell in the tile map.
tile_map . erase ( pk ) ;
2017-10-22 01:42:23 +00:00
2021-05-07 13:41:39 +00:00
// Erase existing cell in the quadrant.
ERR_FAIL_COND ( ! Q ) ;
TileMapQuadrant & q = Q - > get ( ) ;
2017-10-22 01:42:23 +00:00
2021-05-07 13:41:39 +00:00
q . cells . erase ( pk ) ;
2020-12-31 14:47:37 +00:00
2021-05-07 13:41:39 +00:00
// Remove or make the quadrant dirty.
if ( q . cells . size ( ) = = 0 ) {
_erase_quadrant ( Q ) ;
} else {
_make_quadrant_dirty ( Q ) ;
2018-02-24 05:56:48 +00:00
}
2021-05-07 13:41:39 +00:00
used_size_cache_dirty = true ;
} else {
if ( ! E ) {
// Insert a new cell in the tile map.
E = tile_map . insert ( pk , TileMapCell ( ) ) ;
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
// 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 ) ;
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
} else {
ERR_FAIL_COND ( ! Q ) ; // TileMapQuadrant should exist...
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
if ( E - > get ( ) . source_id = = source_id & & E - > get ( ) . get_atlas_coords ( ) = = atlas_coords & & E - > get ( ) . alternative_tile = = alternative_tile ) {
return ; // Nothing changed.
}
}
2020-05-14 12:29:06 +00:00
2021-05-07 13:41:39 +00:00
TileMapCell & c = E - > get ( ) ;
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
c . source_id = source_id ;
c . set_atlas_coords ( atlas_coords ) ;
c . alternative_tile = alternative_tile ;
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
_make_quadrant_dirty ( Q ) ;
used_size_cache_dirty = true ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2021-07-06 12:43:03 +00:00
int TileMap : : get_cell_source_id ( const Vector2i & p_coords , bool p_use_proxies ) const {
2021-05-07 13:41:39 +00:00
// Get a cell source id from position
const Map < Vector2i , TileMapCell > : : Element * E = tile_map . find ( p_coords ) ;
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( ! E ) {
2021-07-06 12:43:03 +00:00
return TileSet : : INVALID_SOURCE ;
}
if ( p_use_proxies & & tile_set . is_valid ( ) ) {
Array proxyed = tile_set - > map_tile_proxy ( E - > get ( ) . source_id , E - > get ( ) . get_atlas_coords ( ) , E - > get ( ) . alternative_tile ) ;
return proxyed [ 0 ] ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
return E - > get ( ) . source_id ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2021-07-06 12:43:03 +00:00
Vector2i TileMap : : get_cell_atlas_coords ( const Vector2i & p_coords , bool p_use_proxies ) const {
2021-05-07 13:41:39 +00:00
// Get a cell source id from position
const Map < Vector2i , TileMapCell > : : Element * E = tile_map . find ( p_coords ) ;
2015-01-19 13:07:25 +00:00
2020-05-14 14:41:43 +00:00
if ( ! E ) {
2021-05-18 13:40:52 +00:00
return TileSetSource : : INVALID_ATLAS_COORDS ;
2020-05-14 14:41:43 +00:00
}
2015-01-19 13:07:25 +00:00
2021-07-06 12:43:03 +00:00
if ( p_use_proxies & & tile_set . is_valid ( ) ) {
Array proxyed = tile_set - > map_tile_proxy ( E - > get ( ) . source_id , E - > get ( ) . get_atlas_coords ( ) , E - > get ( ) . alternative_tile ) ;
return proxyed [ 1 ] ;
}
2021-05-07 13:41:39 +00:00
return E - > get ( ) . get_atlas_coords ( ) ;
2015-01-19 13:07:25 +00:00
}
2014-02-10 01:10:30 +00:00
2021-07-06 12:43:03 +00:00
int TileMap : : get_cell_alternative_tile ( const Vector2i & p_coords , bool p_use_proxies ) const {
2021-05-07 13:41:39 +00:00
// Get a cell source id from position
const Map < Vector2i , TileMapCell > : : Element * E = tile_map . find ( p_coords ) ;
2017-10-22 01:42:23 +00:00
2020-05-14 14:41:43 +00:00
if ( ! E ) {
2021-05-18 13:40:52 +00:00
return TileSetSource : : INVALID_TILE_ALTERNATIVE ;
2020-05-14 14:41:43 +00:00
}
2018-06-01 21:12:25 +00:00
2021-07-06 12:43:03 +00:00
if ( p_use_proxies & & tile_set . is_valid ( ) ) {
Array proxyed = tile_set - > map_tile_proxy ( E - > get ( ) . source_id , E - > get ( ) . get_atlas_coords ( ) , E - > get ( ) . alternative_tile ) ;
return proxyed [ 2 ] ;
}
2021-05-07 13:41:39 +00:00
return E - > get ( ) . alternative_tile ;
2017-10-22 01:42:23 +00:00
}
2021-05-07 13:41:39 +00:00
TileMapPattern * TileMap : : get_pattern ( TypedArray < Vector2i > p_coords_array ) {
ERR_FAIL_COND_V ( ! tile_set . is_valid ( ) , nullptr ) ;
2017-10-22 01:42:23 +00:00
2021-05-07 13:41:39 +00:00
TileMapPattern * output = memnew ( TileMapPattern ) ;
if ( p_coords_array . is_empty ( ) ) {
return output ;
2020-05-14 14:41:43 +00:00
}
2017-10-22 01:42:23 +00:00
2021-05-07 13:41:39 +00:00
Vector2i min = Vector2i ( p_coords_array [ 0 ] ) ;
for ( int i = 1 ; i < p_coords_array . size ( ) ; i + + ) {
min = min . min ( p_coords_array [ i ] ) ;
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
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 ;
}
}
2014-02-10 01:10:30 +00:00
}
2021-05-07 13:41:39 +00:00
coords_in_pattern_array . write [ i ] = coords_in_pattern ;
2014-02-10 01:10:30 +00:00
}
2021-05-07 13:41:39 +00:00
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 ) ) ;
2014-02-10 01:10:30 +00:00
}
2021-05-07 13:41:39 +00:00
return output ;
2017-08-15 21:33:19 +00:00
}
2021-05-07 13:41:39 +00:00
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 ( ) ) ;
2017-08-15 21:33:19 +00:00
2021-05-07 13:41:39 +00:00
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 ;
}
2017-08-15 21:33:19 +00:00
}
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
return output ;
2014-02-10 01:10:30 +00:00
}
2021-05-07 13:41:39 +00:00
void TileMap : : set_pattern ( Vector2i p_position , const TileMapPattern * p_pattern ) {
ERR_FAIL_COND ( ! tile_set . is_valid ( ) ) ;
2017-12-09 16:44:26 +00:00
2021-05-07 13:41:39 +00:00
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 ) ) ;
2014-02-10 01:10:30 +00:00
}
}
2021-07-06 12:43:03 +00:00
TileMapCell TileMap : : get_cell ( const Vector2i & p_coords , bool p_use_proxies ) const {
2021-05-07 13:41:39 +00:00
if ( ! tile_map . has ( p_coords ) ) {
return TileMapCell ( ) ;
2019-07-08 09:35:52 +00:00
} else {
2021-07-06 12:43:03 +00:00
TileMapCell c = tile_map . find ( p_coords ) - > get ( ) ;
if ( p_use_proxies & & tile_set . is_valid ( ) ) {
Array proxyed = tile_set - > map_tile_proxy ( c . source_id , c . get_atlas_coords ( ) , c . alternative_tile ) ;
c . source_id = proxyed [ 0 ] ;
c . set_atlas_coords ( proxyed [ 1 ] ) ;
c . alternative_tile = proxyed [ 2 ] ;
}
return c ;
2019-07-08 09:35:52 +00:00
}
2018-07-29 21:09:59 +00:00
}
2021-05-07 13:41:39 +00:00
Map < Vector2i , TileMapQuadrant > & TileMap : : get_quadrant_map ( ) {
return quadrant_map ;
2014-05-14 04:22:15 +00:00
}
2021-05-07 13:41:39 +00:00
void TileMap : : fix_invalid_tiles ( ) {
ERR_FAIL_COND_MSG ( tile_set . is_null ( ) , " Cannot fix invalid tiles if Tileset is not open. " ) ;
2021-06-14 06:58:55 +00:00
Set < Vector2i > coords ;
2021-05-07 13:41:39 +00:00
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 ) ) {
2021-06-14 06:58:55 +00:00
coords . insert ( E - > key ( ) ) ;
2019-02-05 23:45:40 +00:00
}
2015-05-03 19:47:21 +00:00
}
2021-06-14 06:58:55 +00:00
for ( Set < Vector2i > : : Element * E = coords . front ( ) ; E ; E = E - > next ( ) ) {
2021-07-06 12:43:03 +00:00
set_cell ( E - > get ( ) , TileSet : : INVALID_SOURCE , TileSetSource : : INVALID_ATLAS_COORDS , TileSetSource : : INVALID_TILE_ALTERNATIVE ) ;
2021-06-14 06:58:55 +00:00
}
2015-05-03 19:47:21 +00:00
}
2021-05-07 13:41:39 +00:00
void TileMap : : _recreate_quadrants ( ) {
// Clear then recreate all quadrants.
2019-02-05 23:45:40 +00:00
_clear_quadrants ( ) ;
2021-05-07 13:41:39 +00:00
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 ) ) ;
2019-02-05 23:45:40 +00:00
2021-05-07 13:41:39 +00:00
Map < Vector2i , TileMapQuadrant > : : Element * Q = quadrant_map . find ( qk ) ;
if ( ! Q ) {
Q = _create_quadrant ( qk ) ;
dirty_quadrant_list . add ( & Q - > get ( ) . dirty_list_element ) ;
2019-02-05 23:45:40 +00:00
}
2014-06-30 01:41:02 +00:00
2021-05-07 13:41:39 +00:00
Vector2i pk = E - > key ( ) ;
Q - > get ( ) . cells . insert ( pk ) ;
2014-06-30 01:41:02 +00:00
2021-05-07 13:41:39 +00:00
_make_quadrant_dirty ( Q , false ) ;
2014-06-30 01:41:02 +00:00
}
2020-05-14 12:29:06 +00:00
2021-05-07 13:41:39 +00:00
update_dirty_quadrants ( ) ;
2014-06-30 01:41:02 +00:00
}
2021-05-07 13:41:39 +00:00
void TileMap : : _clear_quadrants ( ) {
// Clear quadrants.
while ( quadrant_map . size ( ) ) {
_erase_quadrant ( quadrant_map . front ( ) ) ;
2021-03-08 08:47:18 +00:00
}
2021-05-07 13:41:39 +00:00
// Clear the dirty quadrants list.
while ( dirty_quadrant_list . first ( ) ) {
dirty_quadrant_list . remove ( dirty_quadrant_list . first ( ) ) ;
}
2014-05-14 04:22:15 +00:00
}
2021-05-07 13:41:39 +00:00
void TileMap : : clear ( ) {
// Remove all tiles.
_clear_quadrants ( ) ;
tile_map . clear ( ) ;
used_size_cache_dirty = true ;
2015-05-03 19:47:21 +00:00
}
2021-05-07 13:41:39 +00:00
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 ) ;
2017-04-05 18:51:31 +00:00
2021-05-07 13:41:39 +00:00
int c = p_data . size ( ) ;
const int * r = p_data . ptr ( ) ;
2017-04-05 18:51:31 +00:00
2021-05-07 13:41:39 +00:00
int offset = ( format > = FORMAT_2 ) ? 3 : 2 ;
2014-10-03 03:10:51 +00:00
2021-05-07 13:41:39 +00:00
clear ( ) ;
2021-05-24 15:30:37 +00:00
# ifdef DISABLE_DEPRECATED
ERR_FAIL_COND_MSG ( format ! = FORMAT_3 , vformat ( " Cannot handle deprecated TileMap data format version %d. This Godot version was compiled with no support for deprecated data. " , format ) ) ;
# endif
2021-05-07 13:41:39 +00:00
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 ] ;
}
2014-10-03 03:10:51 +00:00
2021-05-07 13:41:39 +00:00
# ifdef BIG_ENDIAN_ENABLED
2014-10-03 03:10:51 +00:00
2021-05-07 13:41:39 +00:00
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
2021-07-06 12:43:03 +00:00
// Extracts position in TileMap.
2021-05-07 13:41:39 +00:00
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 ] ) ;
2021-06-30 10:03:22 +00:00
uint16_t atlas_coords_y = decode_uint16 ( & local [ 8 ] ) ;
2021-05-07 13:41:39 +00:00
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 {
2021-05-24 15:30:37 +00:00
# ifndef DISABLE_DEPRECATED
2021-07-06 12:43:03 +00:00
// Previous decated format.
2021-05-07 13:41:39 +00:00
uint32_t v = decode_uint32 ( & local [ 4 ] ) ;
2021-07-06 12:43:03 +00:00
// Extract the transform flags that used to be in the tilemap.
2021-05-07 13:41:39 +00:00
bool flip_h = v & ( 1 < < 29 ) ;
bool flip_v = v & ( 1 < < 30 ) ;
bool transpose = v & ( 1 < < 31 ) ;
2021-06-30 10:03:22 +00:00
v & = ( 1 < < 29 ) - 1 ;
2021-07-06 12:43:03 +00:00
// Extract autotile/atlas coords.
2021-05-07 13:41:39 +00:00
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 ] ) ;
}
2015-03-09 05:34:56 +00:00
2021-05-07 13:41:39 +00:00
if ( tile_set . is_valid ( ) ) {
2021-06-30 10:03:22 +00:00
Array a = tile_set - > compatibility_tilemap_map ( v , Vector2i ( coord_x , coord_y ) , flip_h , flip_v , transpose ) ;
if ( a . size ( ) = = 3 ) {
set_cell ( Vector2i ( x , y ) , a [ 0 ] , a [ 1 ] , a [ 2 ] ) ;
} else {
ERR_PRINT ( vformat ( " No valid tile in Tileset for: tile:%s coords:%s flip_h:%s flip_v:%s transpose:%s " , v , Vector2i ( coord_x , coord_y ) , flip_h , flip_v , transpose ) ) ;
}
} else {
int compatibility_alternative_tile = ( ( int ) flip_h ) + ( ( int ) flip_v < < 1 ) + ( ( int ) transpose < < 2 ) ;
set_cell ( Vector2i ( x , y ) , v , Vector2i ( coord_x , coord_y ) , compatibility_alternative_tile ) ;
2021-05-07 13:41:39 +00:00
}
2021-05-24 15:30:37 +00:00
# endif
2021-05-07 13:41:39 +00:00
}
2014-10-03 03:10:51 +00:00
}
}
2021-05-07 13:41:39 +00:00
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 ( ) ;
2014-10-03 03:10:51 +00:00
2021-05-07 13:41:39 +00:00
// Save in highest format
2014-10-03 03:10:51 +00:00
2021-05-07 13:41:39 +00:00
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 ;
2014-10-03 03:10:51 +00:00
}
2021-05-07 13:41:39 +00:00
return data ;
2014-10-03 03:10:51 +00:00
}
2021-05-07 13:41:39 +00:00
# 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 ( ) ;
2014-10-03 03:10:51 +00:00
}
2021-05-07 13:41:39 +00:00
return rect_cache ;
2014-10-03 03:10:51 +00:00
}
2021-05-07 13:41:39 +00:00
# endif
2017-10-22 01:42:23 +00:00
bool TileMap : : _set ( const StringName & p_name , const Variant & p_value ) {
if ( p_name = = " format " ) {
if ( p_value . get_type ( ) = = Variant : : INT ) {
2019-08-08 06:30:55 +00:00
format = ( DataFormat ) ( p_value . operator int64_t ( ) ) ; // Set format used for loading
2017-10-22 01:42:23 +00:00
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 " ) {
2021-05-07 13:41:39 +00:00
r_ret = FORMAT_3 ; // When saving, always save highest format
2017-10-22 01:42:23 +00:00
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 {
2018-01-11 22:35:12 +00:00
PropertyInfo p ( Variant : : INT , " format " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL ) ;
2017-10-22 01:42:23 +00:00
p_list - > push_back ( p ) ;
2018-01-11 22:35:12 +00:00
p = PropertyInfo ( Variant : : OBJECT , " tile_data " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL ) ;
2017-10-22 01:42:23 +00:00
p_list - > push_back ( p ) ;
}
2020-06-30 06:34:15 +00:00
Vector2 TileMap : : map_to_world ( const Vector2i & p_pos ) const {
2021-05-07 13:41:39 +00:00
// 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 ;
2019-02-05 23:45:40 +00:00
}
2021-05-07 13:41:39 +00:00
return ( ret + Vector2 ( 0.5 , 0.5 ) ) * tile_set - > get_tile_size ( ) ;
2014-10-03 03:10:51 +00:00
}
2017-10-22 01:42:23 +00:00
2021-05-07 13:41:39 +00:00
Vector2i TileMap : : world_to_map ( const Vector2 & p_pos ) const {
2020-06-30 06:34:15 +00:00
ERR_FAIL_COND_V ( ! tile_set . is_valid ( ) , Vector2i ( ) ) ;
2014-10-03 03:10:51 +00:00
2021-05-07 13:41:39 +00:00
Vector2 ret = p_pos ;
ret / = tile_set - > get_tile_size ( ) ;
2021-05-02 21:34:51 +00:00
2021-05-07 13:41:39 +00:00
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 ( ) ;
2014-10-03 03:10:51 +00:00
}
2021-05-07 13:41:39 +00:00
// 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 ;
2019-03-23 23:59:24 +00:00
}
2021-05-07 13:41:39 +00:00
} 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 ( ) ;
2014-10-03 03:10:51 +00:00
}
2021-05-07 13:41:39 +00:00
// 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 ;
2019-03-23 23:59:24 +00:00
}
2019-04-09 15:08:36 +00:00
}
2021-05-07 13:41:39 +00:00
} else {
ret = ( ret + Vector2 ( 0.00005 , 0.00005 ) ) . floor ( ) ;
2014-10-03 03:10:51 +00:00
}
2020-06-30 06:34:15 +00:00
return Vector2i ( ret ) ;
2014-10-03 03:10:51 +00:00
}
2021-05-07 13:41:39 +00:00
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 ;
}
}
2015-03-09 05:34:56 +00:00
}
2021-05-07 13:41:39 +00:00
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 ) ;
}
2015-03-09 05:34:56 +00:00
2021-05-07 13:41:39 +00:00
} 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 ) ;
}
2019-07-01 20:43:52 +00:00
2021-05-07 13:41:39 +00:00
} 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 ) ;
}
2019-07-01 20:43:52 +00:00
2021-05-07 13:41:39 +00:00
} 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 ) ;
}
2019-07-01 20:43:52 +00:00
2021-05-07 13:41:39 +00:00
} 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 ) ;
}
}
2019-07-01 20:43:52 +00:00
}
2020-04-20 22:06:00 +00:00
TypedArray < Vector2i > TileMap : : get_used_cells ( ) const {
2021-05-07 13:41:39 +00:00
// Returns the cells used in the tilemap.
2020-04-20 22:06:00 +00:00
TypedArray < Vector2i > a ;
2015-04-18 17:00:15 +00:00
a . resize ( tile_map . size ( ) ) ;
2017-03-05 15:44:50 +00:00
int i = 0 ;
2021-05-07 13:41:39 +00:00
for ( Map < Vector2i , TileMapCell > : : Element * E = tile_map . front ( ) ; E ; E = E - > next ( ) ) {
2020-04-20 22:06:00 +00:00
Vector2i p ( E - > key ( ) . x , E - > key ( ) . y ) ;
2017-03-05 15:44:50 +00:00
a [ i + + ] = p ;
2015-04-18 17:00:15 +00:00
}
return a ;
}
2014-05-14 04:22:15 +00:00
2017-02-20 21:02:03 +00:00
Rect2 TileMap : : get_used_rect ( ) { // Not const because of cache
2021-05-07 13:41:39 +00:00
// Return the rect of the currently used area
2017-02-20 21:02:03 +00:00
if ( used_size_cache_dirty ) {
2017-03-05 15:44:50 +00:00
if ( tile_map . size ( ) > 0 ) {
2017-02-20 21:02:03 +00:00
used_size_cache = Rect2 ( tile_map . front ( ) - > key ( ) . x , tile_map . front ( ) - > key ( ) . y , 0 , 0 ) ;
2021-05-07 13:41:39 +00:00
for ( Map < Vector2i , TileMapCell > : : Element * E = tile_map . front ( ) ; E ; E = E - > next ( ) ) {
2017-02-20 21:02:03 +00:00
used_size_cache . expand_to ( Vector2 ( E - > key ( ) . x , E - > key ( ) . y ) ) ;
}
2017-03-05 15:44:50 +00:00
used_size_cache . size + = Vector2 ( 1 , 1 ) ;
2017-02-20 21:02:03 +00:00
} else {
used_size_cache = Rect2 ( ) ;
}
used_size_cache_dirty = false ;
}
return used_size_cache ;
}
2021-05-07 13:41:39 +00:00
// --- Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems ---
2015-12-12 13:45:31 +00:00
2015-12-29 17:47:13 +00:00
void TileMap : : set_light_mask ( int p_light_mask ) {
2021-05-07 13:41:39 +00:00
// Occlusion: set light mask.
2015-12-29 17:47:13 +00:00
CanvasItem : : set_light_mask ( p_light_mask ) ;
2021-05-07 13:41:39 +00:00
for ( Map < Vector2i , TileMapQuadrant > : : Element * E = quadrant_map . front ( ) ; E ; E = E - > next ( ) ) {
2017-03-05 15:44:50 +00:00
for ( List < RID > : : Element * F = E - > get ( ) . canvas_items . front ( ) ; F ; F = F - > next ( ) ) {
2020-03-27 18:21:27 +00:00
RenderingServer : : get_singleton ( ) - > canvas_item_set_light_mask ( F - > get ( ) , get_light_mask ( ) ) ;
2015-12-29 17:47:13 +00:00
}
}
}
2015-12-12 13:45:31 +00:00
2021-05-07 13:41:39 +00:00
void TileMap : : set_material ( const Ref < Material > & p_material ) {
// Set material for the whole tilemap.
CanvasItem : : set_material ( p_material ) ;
2017-11-10 12:21:33 +00:00
2021-05-07 13:41:39 +00:00
// 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 ( ) ) ;
}
}
2017-11-10 12:21:33 +00:00
}
2021-05-07 13:41:39 +00:00
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 ( ) ) ;
}
}
2017-11-10 12:21:33 +00:00
}
2020-02-19 21:26:24 +00:00
void TileMap : : set_texture_filter ( TextureFilter p_texture_filter ) {
2021-05-07 13:41:39 +00:00
// Set a default texture filter for the whole tilemap
2020-02-19 21:26:24 +00:00
CanvasItem : : set_texture_filter ( p_texture_filter ) ;
2021-05-07 13:41:39 +00:00
for ( Map < Vector2i , TileMapQuadrant > : : Element * F = quadrant_map . front ( ) ; F ; F = F - > next ( ) ) {
TileMapQuadrant & q = F - > get ( ) ;
2020-02-19 21:26:24 +00:00
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 ) {
2021-05-07 13:41:39 +00:00
// Set a default texture repeat for the whole tilemap
2020-02-19 21:26:24 +00:00
CanvasItem : : set_texture_repeat ( p_texture_repeat ) ;
2021-05-07 13:41:39 +00:00
for ( Map < Vector2i , TileMapQuadrant > : : Element * F = quadrant_map . front ( ) ; F ; F = F - > next ( ) ) {
TileMapQuadrant & q = F - > get ( ) ;
2020-02-19 21:26:24 +00:00
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 ) ;
}
}
}
2021-05-07 13:41:39 +00:00
TypedArray < Vector2i > TileMap : : get_surrounding_tiles ( Vector2i coords ) {
if ( ! tile_set . is_valid ( ) ) {
return TypedArray < Vector2i > ( ) ;
}
2019-02-05 23:45:40 +00:00
2021-05-07 13:41:39 +00:00
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 ) ) ;
}
2019-02-05 23:45:40 +00:00
}
2021-05-07 13:41:39 +00:00
return around ;
2019-02-05 23:45:40 +00:00
}
2021-05-07 13:41:39 +00:00
void TileMap : : draw_cells_outline ( Control * p_control , Set < Vector2i > p_cells , Color p_color , Transform2D p_transform ) {
if ( ! tile_set . is_valid ( ) ) {
return ;
}
2014-10-03 03:10:51 +00:00
2021-05-07 13:41:39 +00:00
// Create a set.
Vector2i tile_size = tile_set - > get_tile_size ( ) ;
Vector < Vector2 > uvs ;
2014-10-03 03:10:51 +00:00
2021-05-07 13:41:39 +00:00
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 ) ;
}
}
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
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 ) ;
}
}
}
}
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
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 ) ;
2014-10-03 03:10:51 +00:00
2017-03-05 15:44:50 +00:00
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 ) ;
2014-02-10 01:10:30 +00:00
2021-05-24 10:33:22 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_collision_visibility_mode " , " show_collision " ) , & TileMap : : set_collision_visibility_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_collision_visibility_mode " ) , & TileMap : : get_collision_visibility_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " set_navigation_visibility_mode " , " show_navigation " ) , & TileMap : : set_navigation_visibility_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_navigation_visibility_mode " ) , & TileMap : : get_navigation_visibility_mode ) ;
2021-07-06 12:43:03 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_cell " , " coords " , " source_id " , " atlas_coords " , " alternative_tile " ) , & TileMap : : set_cell , DEFVAL ( TileSet : : INVALID_SOURCE ) , DEFVAL ( TileSetSource : : INVALID_ATLAS_COORDS ) , DEFVAL ( TileSetSource : : INVALID_TILE_ALTERNATIVE ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_cell_source_id " , " coords " , " use_proxies " ) , & TileMap : : get_cell_source_id ) ;
ClassDB : : bind_method ( D_METHOD ( " get_cell_atlas_coords " , " coords " , " use_proxies " ) , & TileMap : : get_cell_atlas_coords ) ;
ClassDB : : bind_method ( D_METHOD ( " get_cell_alternative_tile " , " coords " , " use_proxies " ) , & TileMap : : get_cell_alternative_tile ) ;
2018-12-20 17:43:44 +00:00
2018-02-24 05:56:48 +00:00
ClassDB : : bind_method ( D_METHOD ( " fix_invalid_tiles " ) , & TileMap : : fix_invalid_tiles ) ;
2021-05-07 13:41:39 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_surrounding_tiles " , " coords " ) , & TileMap : : get_surrounding_tiles ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " clear " ) , & TileMap : : clear ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_used_cells " ) , & TileMap : : get_used_cells ) ;
ClassDB : : bind_method ( D_METHOD ( " get_used_rect " ) , & TileMap : : get_used_rect ) ;
2015-04-18 17:00:15 +00:00
2021-05-07 13:41:39 +00:00
ClassDB : : bind_method ( D_METHOD ( " map_to_world " , " map_position " ) , & TileMap : : map_to_world ) ;
2017-09-10 13:37:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " world_to_map " , " world_position " ) , & TileMap : : world_to_map ) ;
2014-10-03 03:10:51 +00:00
2021-05-07 13:41:39 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_neighbor_cell " , " coords " , " neighbor " ) , & TileMap : : get_neighbor_cell ) ;
2014-02-10 01:10:30 +00:00
2021-05-07 13:41:39 +00:00
ClassDB : : bind_method ( D_METHOD ( " update_dirty_quadrants " ) , & TileMap : : update_dirty_quadrants ) ;
2017-12-06 00:14:33 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _set_tile_data " ) , & TileMap : : _set_tile_data ) ;
ClassDB : : bind_method ( D_METHOD ( " _get_tile_data " ) , & TileMap : : _get_tile_data ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
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 " ) ;
2021-05-24 10:33:22 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " show_collision " , PROPERTY_HINT_ENUM , " Default,Force Show,Force Hide " ) , " set_collision_visibility_mode " , " get_collision_visibility_mode " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " show_navigation " , PROPERTY_HINT_ENUM , " Default,Force Show,Force Hide " ) , " set_navigation_visibility_mode " , " get_navigation_visibility_mode " ) ;
2021-03-08 08:47:18 +00:00
2019-08-08 06:30:55 +00:00
ADD_PROPERTY_DEFAULT ( " format " , FORMAT_1 ) ;
2021-05-07 13:41:39 +00:00
ADD_SIGNAL ( MethodInfo ( " changed " ) ) ;
2021-05-24 10:33:22 +00:00
BIND_ENUM_CONSTANT ( VISIBILITY_MODE_DEFAULT ) ;
BIND_ENUM_CONSTANT ( VISIBILITY_MODE_FORCE_HIDE ) ;
BIND_ENUM_CONSTANT ( VISIBILITY_MODE_FORCE_SHOW ) ;
2021-05-07 13:41:39 +00:00
}
2017-08-20 15:45:01 +00:00
2021-05-07 13:41:39 +00:00
void TileMap : : _tile_set_changed ( ) {
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " changed " ) ) ;
2021-05-07 13:41:39 +00:00
_make_all_quadrants_dirty ( true ) ;
2014-02-10 01:10:30 +00:00
}
TileMap : : TileMap ( ) {
2017-01-12 23:35:46 +00:00
set_notify_transform ( true ) ;
2019-02-05 23:45:40 +00:00
set_notify_local_transform ( false ) ;
2014-02-10 01:10:30 +00:00
}
TileMap : : ~ TileMap ( ) {
2021-05-07 13:41:39 +00:00
if ( tile_set . is_valid ( ) ) {
tile_set - > disconnect ( " changed " , callable_mp ( this , & TileMap : : _tile_set_changed ) ) ;
}
_clear_quadrants ( ) ;
2014-02-10 01:10:30 +00:00
}