diff options
Diffstat (limited to 'scene/2d/tile_map.h')
-rw-r--r-- | scene/2d/tile_map.h | 530 |
1 files changed, 279 insertions, 251 deletions
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 3bf4587921..3ac50fc7cc 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -31,197 +31,254 @@ #ifndef TILE_MAP_H #define TILE_MAP_H -#include "core/templates/self_list.h" -#include "core/templates/vset.h" -#include "scene/2d/navigation_2d.h" #include "scene/2d/node_2d.h" +#include "scene/gui/control.h" #include "scene/resources/tile_set.h" -class CollisionObject2D; +class TileSetAtlasSource; -class TileMap : public Node2D { - GDCLASS(TileMap, Node2D); - -public: - enum Mode { - MODE_SQUARE, - MODE_ISOMETRIC, - MODE_CUSTOM +union TileMapCell { + struct { + int32_t source_id : 16; + int16_t coord_x : 16; + int16_t coord_y : 16; + int32_t alternative_tile : 16; }; - enum HalfOffset { - HALF_OFFSET_X, - HALF_OFFSET_Y, - HALF_OFFSET_DISABLED, - HALF_OFFSET_NEGATIVE_X, - HALF_OFFSET_NEGATIVE_Y, - }; + uint64_t _u64t; + TileMapCell(int p_source_id = -1, Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) { + source_id = p_source_id; + set_atlas_coords(p_atlas_coords); + alternative_tile = p_alternative_tile; + } + + Vector2i get_atlas_coords() const { + return Vector2i(coord_x, coord_y); + } + + void set_atlas_coords(const Vector2i &r_coords) { + coord_x = r_coords.x; + coord_y = r_coords.y; + } + + bool operator<(const TileMapCell &p_other) const { + if (source_id == p_other.source_id) { + if (coord_x == p_other.coord_x) { + if (coord_y == p_other.coord_y) { + return alternative_tile < p_other.alternative_tile; + } else { + return coord_y < p_other.coord_y; + } + } else { + return coord_x < p_other.coord_x; + } + } else { + return source_id < p_other.source_id; + } + } - enum TileOrigin { - TILE_ORIGIN_TOP_LEFT, - TILE_ORIGIN_CENTER, - TILE_ORIGIN_BOTTOM_LEFT - }; + bool operator!=(const TileMapCell &p_other) const { + return !(source_id == p_other.source_id && coord_x == p_other.coord_x && coord_y == p_other.coord_y && alternative_tile == p_other.alternative_tile); + } +}; -private: - enum DataFormat { - FORMAT_1 = 0, - FORMAT_2 +struct TileMapQuadrant { + struct CoordsWorldComparator { + _ALWAYS_INLINE_ bool operator()(const Vector2i &p_a, const Vector2i &p_b) const { + // We sort the cells by their world coords, as it is needed by rendering. + if (p_a.y == p_b.y) { + return p_a.x > p_b.x; + } else { + return p_a.y < p_b.y; + } + } }; - Ref<TileSet> tile_set; - Size2i cell_size = Size2(64, 64); - int quadrant_size = 16; - Mode mode = MODE_SQUARE; - Transform2D custom_transform = Transform2D(64, 0, 0, 64, 0, 0); - HalfOffset half_offset = HALF_OFFSET_DISABLED; - bool use_parent = false; - CollisionObject2D *collision_parent = nullptr; - bool use_kinematic = false; - Navigation2D *navigation = nullptr; - - union PosKey { - struct { - int16_t x; - int16_t y; - }; - uint32_t key = 0; - - //using a more precise comparison so the regions can be sorted later - bool operator<(const PosKey &p_k) const { return (y == p_k.y) ? x < p_k.x : y < p_k.y; } - - bool operator==(const PosKey &p_k) const { return (y == p_k.y && x == p_k.x); } - - PosKey to_quadrant(const int &p_quadrant_size) const { - // rounding down, instead of simply rounding towards zero (truncating) - return PosKey( - x > 0 ? x / p_quadrant_size : (x - (p_quadrant_size - 1)) / p_quadrant_size, - y > 0 ? y / p_quadrant_size : (y - (p_quadrant_size - 1)) / p_quadrant_size); - } + // Dirty list element + SelfList<TileMapQuadrant> dirty_list_element; + + // Quadrant layer and coords. + int layer = -1; + Vector2i coords; + + // TileMapCells + Set<Vector2i> cells; + // We need those two maps to sort by world position for rendering + // This is kind of workaround, it would be better to sort the cells directly in the "cells" set instead. + Map<Vector2i, Vector2i> map_to_world; + Map<Vector2i, Vector2i, CoordsWorldComparator> world_to_map; + + // Debug. + RID debug_canvas_item; + + // Rendering. + List<RID> canvas_items; + List<RID> occluders; + + // Physics. + List<RID> bodies; + + // Navigation. + Map<Vector2i, Vector<RID>> navigation_regions; + + // Scenes. + Map<Vector2i, String> scenes; + + void operator=(const TileMapQuadrant &q) { + layer = q.layer; + coords = q.coords; + debug_canvas_item = q.debug_canvas_item; + canvas_items = q.canvas_items; + occluders = q.occluders; + bodies = q.bodies; + navigation_regions = q.navigation_regions; + } + + TileMapQuadrant(const TileMapQuadrant &q) : + dirty_list_element(this) { + layer = q.layer; + coords = q.coords; + debug_canvas_item = q.debug_canvas_item; + canvas_items = q.canvas_items; + occluders = q.occluders; + bodies = q.bodies; + navigation_regions = q.navigation_regions; + } + + TileMapQuadrant() : + dirty_list_element(this) { + } +}; - PosKey(int16_t p_x, int16_t p_y) { - x = p_x; - y = p_y; - } - PosKey() { - x = 0; - y = 0; - } - }; +class TileMapPattern : public Object { + GDCLASS(TileMapPattern, Object); - union Cell { - struct { - int32_t id : 24; - bool flip_h : 1; - bool flip_v : 1; - bool transpose : 1; - int16_t autotile_coord_x : 16; - int16_t autotile_coord_y : 16; - }; - - uint64_t _u64t = 0; - }; + Vector2i size; + Map<Vector2i, TileMapCell> pattern; - Map<PosKey, Cell> tile_map; - List<PosKey> dirty_bitmask; +protected: + static void _bind_methods(); - struct Quadrant { - Vector2 pos; - List<RID> canvas_items; - RID body; - uint32_t shape_owner_id = 0; +public: + void set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile = 0); + bool has_cell(const Vector2i &p_coords) const; + void remove_cell(const Vector2i &p_coords, bool p_update_size = true); + int get_cell_source_id(const Vector2i &p_coords) const; + Vector2i get_cell_atlas_coords(const Vector2i &p_coords) const; + int get_cell_alternative_tile(const Vector2i &p_coords) const; + + TypedArray<Vector2i> get_used_cells() const; - SelfList<Quadrant> dirty_list; + Vector2i get_size() const; + void set_size(const Vector2i &p_size); + bool is_empty() const; - struct NavPoly { - RID region; - Transform2D xform; - }; + void clear(); +}; - struct Occluder { - RID id; - Transform2D xform; - }; +class TileMap : public Node2D { + GDCLASS(TileMap, Node2D); - Map<PosKey, NavPoly> navpoly_ids; - Map<PosKey, Occluder> occluder_instances; +public: + enum VisibilityMode { + VISIBILITY_MODE_DEFAULT, + VISIBILITY_MODE_FORCE_SHOW, + VISIBILITY_MODE_FORCE_HIDE, + }; - VSet<PosKey> cells; +private: + friend class TileSetPlugin; - void operator=(const Quadrant &q) { - pos = q.pos; - canvas_items = q.canvas_items; - body = q.body; - shape_owner_id = q.shape_owner_id; - cells = q.cells; - navpoly_ids = q.navpoly_ids; - occluder_instances = q.occluder_instances; - } - Quadrant(const Quadrant &q) : - dirty_list(this) { - pos = q.pos; - canvas_items = q.canvas_items; - body = q.body; - shape_owner_id = q.shape_owner_id; - cells = q.cells; - occluder_instances = q.occluder_instances; - navpoly_ids = q.navpoly_ids; - } - Quadrant() : - dirty_list(this) {} + // A compatibility enum to specify how is the data if formatted. + enum DataFormat { + FORMAT_1 = 0, + FORMAT_2, + FORMAT_3 }; + mutable DataFormat format = FORMAT_1; // Assume lowest possible format if none is present; - Map<PosKey, Quadrant> quadrant_map; + static constexpr float FP_ADJUST = 0.00001; - SelfList<Quadrant>::List dirty_quadrant_list; + // Properties. + Ref<TileSet> tile_set; + int quadrant_size = 16; + VisibilityMode collision_visibility_mode = VISIBILITY_MODE_DEFAULT; + VisibilityMode navigation_visibility_mode = VISIBILITY_MODE_DEFAULT; + // Updates. bool pending_update = false; + // Rect. Rect2 rect_cache; bool rect_cache_dirty = true; - Rect2 used_size_cache; - bool used_size_cache_dirty = true; - bool quadrant_order_dirty = false; - bool use_y_sort = false; - bool compatibility_mode = false; - bool centered_textures = false; - bool clip_uv = false; - float fp_adjust = 0.00001; - float friction = 1.0; - float bounce = 0.0; - uint32_t collision_layer = 1; - uint32_t collision_mask = 1; - mutable DataFormat format = FORMAT_1; // Assume lowest possible format if none is present - - TileOrigin tile_origin = TILE_ORIGIN_TOP_LEFT; - - int occluder_light_mask = 1; - - void _fix_cell_transform(Transform2D &xform, const Cell &p_cell, const Vector2 &p_offset, const Size2 &p_sc); - - void _add_shape(int &shape_idx, const Quadrant &p_q, const Ref<Shape2D> &p_shape, const TileSet::ShapeData &p_shape_data, const Transform2D &p_xform, const Vector2 &p_metadata); - - Map<PosKey, Quadrant>::Element *_create_quadrant(const PosKey &p_qk); - void _erase_quadrant(Map<PosKey, Quadrant>::Element *Q); - void _make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q, bool update = true); - void _recreate_quadrants(); - void _clear_quadrants(); - void _update_quadrant_space(const RID &p_space); - void _update_quadrant_transform(); - void _recompute_rect_cache(); + Rect2i used_rect_cache; + bool used_rect_cache_dirty = true; + + // TileMap layers. + struct TileMapLayer { + String name; + bool enabled = true; + bool y_sort_enabled = false; + int y_sort_origin = 0; + int z_index = 0; + RID canvas_item; + Map<Vector2i, TileMapCell> tile_map; + Map<Vector2i, TileMapQuadrant> quadrant_map; + SelfList<TileMapQuadrant>::List dirty_quadrant_list; + }; + LocalVector<TileMapLayer> layers; + int selected_layer = -1; - void _update_all_items_material_state(); - _FORCE_INLINE_ void _update_item_material_state(const RID &p_canvas_item); + // Quadrants and internals management. + Vector2i _coords_to_quadrant_coords(int p_layer, const Vector2i &p_coords) const; - _FORCE_INLINE_ int _get_quadrant_size() const; + Map<Vector2i, TileMapQuadrant>::Element *_create_quadrant(int p_layer, const Vector2i &p_qk); - void _set_tile_data(const Vector<int> &p_data); - Vector<int> _get_tile_data() const; + void _make_quadrant_dirty(Map<Vector2i, TileMapQuadrant>::Element *Q); + void _make_all_quadrants_dirty(); + void _queue_update_dirty_quadrants(); - void _set_old_cell_size(int p_size) { set_cell_size(Size2(p_size, p_size)); } - int _get_old_cell_size() const { return cell_size.x; } + void _update_dirty_quadrants(); - _FORCE_INLINE_ Vector2 _map_to_world(int p_x, int p_y, bool p_ignore_ofs = false) const; + void _recreate_internals(); + + void _erase_quadrant(Map<Vector2i, TileMapQuadrant>::Element *Q); + void _clear_layer_internals(int p_layer); + void _clear_internals(); + + // Rect caching. + void _recompute_rect_cache(); + + // Per-system methods. + bool _rendering_quadrant_order_dirty = false; + void _rendering_notification(int p_what); + void _rendering_update_layer(int p_layer); + void _rendering_cleanup_layer(int p_layer); + void _rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list); + void _rendering_create_quadrant(TileMapQuadrant *p_quadrant); + void _rendering_cleanup_quadrant(TileMapQuadrant *p_quadrant); + void _rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant); + + void _physics_notification(int p_what); + void _physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list); + void _physics_create_quadrant(TileMapQuadrant *p_quadrant); + void _physics_cleanup_quadrant(TileMapQuadrant *p_quadrant); + void _physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant); + + void _navigation_notification(int p_what); + void _navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list); + void _navigation_cleanup_quadrant(TileMapQuadrant *p_quadrant); + void _navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant); + + void _scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list); + void _scenes_cleanup_quadrant(TileMapQuadrant *p_quadrant); + void _scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant); + + // Set and get tiles from data arrays. + void _set_tile_data(int p_layer, const Vector<int> &p_data); + Vector<int> _get_tile_data(int p_layer) const; + + void _tile_set_changed(); protected: bool _set(const StringName &p_name, const Variant &p_value); @@ -231,9 +288,9 @@ protected: void _notification(int p_what); static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; - public: + static Vector2i transform_coords_layout(Vector2i p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout); + enum { INVALID_CELL = -1 }; @@ -245,114 +302,85 @@ public: void set_tileset(const Ref<TileSet> &p_tileset); Ref<TileSet> get_tileset() const; - void set_cell_size(Size2 p_size); - Size2 get_cell_size() const; - void set_quadrant_size(int p_size); int get_quadrant_size() const; - void set_cell(int p_x, int p_y, int p_tile, bool p_flip_x = false, bool p_flip_y = false, bool p_transpose = false, Vector2 p_autotile_coord = Vector2()); - int get_cell(int p_x, int p_y) const; - bool is_cell_x_flipped(int p_x, int p_y) const; - bool is_cell_y_flipped(int p_x, int p_y) const; - bool is_cell_transposed(int p_x, int p_y) const; - void set_cell_autotile_coord(int p_x, int p_y, const Vector2 &p_coord); - Vector2 get_cell_autotile_coord(int p_x, int p_y) const; - - void _set_celld(const Vector2 &p_pos, const Dictionary &p_data); - void set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x = false, bool p_flip_y = false, bool p_transpose = false); - int get_cellv(const Vector2 &p_pos) const; - - void make_bitmask_area_dirty(const Vector2 &p_pos); - void update_bitmask_area(const Vector2 &p_pos); - void update_bitmask_region(const Vector2 &p_start = Vector2(), const Vector2 &p_end = Vector2()); - void update_cell_bitmask(int p_x, int p_y); - void update_dirty_bitmask(); - - void update_dirty_quadrants(); - - void set_collision_layer(uint32_t p_layer); - uint32_t get_collision_layer() const; - - void set_collision_mask(uint32_t p_mask); - uint32_t get_collision_mask() const; - - void set_collision_layer_bit(int p_bit, bool p_value); - bool get_collision_layer_bit(int p_bit) const; - - void set_collision_mask_bit(int p_bit, bool p_value); - bool get_collision_mask_bit(int p_bit) const; - - void set_collision_use_kinematic(bool p_use_kinematic); - bool get_collision_use_kinematic() const; - - void set_collision_use_parent(bool p_use_parent); - bool get_collision_use_parent() const; - - void set_collision_friction(float p_friction); - float get_collision_friction() const; - - void set_collision_bounce(float p_bounce); - float get_collision_bounce() const; - - void set_mode(Mode p_mode); - Mode get_mode() const; - - void set_half_offset(HalfOffset p_half_offset); - HalfOffset get_half_offset() const; - - void set_tile_origin(TileOrigin p_tile_origin); - TileOrigin get_tile_origin() const; - - void set_custom_transform(const Transform2D &p_xform); - Transform2D get_custom_transform() const; - - Transform2D get_cell_transform() const; - Vector2 get_cell_draw_offset() const; - - Vector2 map_to_world(const Vector2 &p_pos, bool p_ignore_ofs = false) const; - Vector2 world_to_map(const Vector2 &p_pos) const; - - void set_y_sort_enabled(bool p_enable); - bool is_y_sort_enabled() const; - - void set_compatibility_mode(bool p_enable); - bool is_compatibility_mode_enabled() const; - - void set_centered_textures(bool p_enable); - bool is_centered_textures_enabled() const; - - TypedArray<Vector2i> get_used_cells() const; - TypedArray<Vector2i> get_used_cells_by_index(int p_index) const; + static void draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0)); + + // Layers management. + int get_layers_count() const; + void add_layer(int p_to_pos); + void move_layer(int p_layer, int p_to_pos); + void remove_layer(int p_layer); + void set_layer_name(int p_layer, String p_name); + String get_layer_name(int p_layer) const; + void set_layer_enabled(int p_layer, bool p_visible); + bool is_layer_enabled(int p_layer) const; + void set_layer_y_sort_enabled(int p_layer, bool p_enabled); + bool is_layer_y_sort_enabled(int p_layer) const; + void set_layer_y_sort_origin(int p_layer, int p_y_sort_origin); + int get_layer_y_sort_origin(int p_layer) const; + void set_layer_z_index(int p_layer, int p_z_index); + int get_layer_z_index(int p_layer) const; + void set_selected_layer(int p_layer_id); // For editor use. + int get_selected_layer() const; + + void set_collision_visibility_mode(VisibilityMode p_show_collision); + VisibilityMode get_collision_visibility_mode(); + + void set_navigation_visibility_mode(VisibilityMode p_show_navigation); + VisibilityMode get_navigation_visibility_mode(); + + void set_cell(int p_layer, const Vector2i &p_coords, int p_source_id = -1, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE); + int get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; + Vector2i get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; + int get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; + + TileMapPattern *get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array); + Vector2i map_pattern(Vector2i p_position_in_tilemap, Vector2i p_coords_in_pattern, const TileMapPattern *p_pattern); + void set_pattern(int p_layer, Vector2i p_position, const TileMapPattern *p_pattern); + + // Not exposed to users + TileMapCell get_cell(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; + Map<Vector2i, TileMapQuadrant> *get_quadrant_map(int p_layer); + int get_effective_quadrant_size(int p_layer) const; + //--- + + virtual void set_y_sort_enabled(bool p_enable) override; + + Vector2 map_to_world(const Vector2i &p_pos) const; + Vector2i world_to_map(const Vector2 &p_pos) const; + + bool is_existing_neighbor(TileSet::CellNeighbor p_cell_neighbor) const; + Vector2i get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const; + + TypedArray<Vector2i> get_used_cells(int p_layer) const; Rect2 get_used_rect(); // Not const because of cache - void set_occluder_light_mask(int p_mask); - int get_occluder_light_mask() const; - + // Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems virtual void set_light_mask(int p_light_mask) override; - virtual void set_material(const Ref<Material> &p_material) override; - virtual void set_use_parent_material(bool p_use_parent_material) override; - - void set_clip_uv(bool p_enable); - bool get_clip_uv() const; - - String get_configuration_warning() const override; - virtual void set_texture_filter(CanvasItem::TextureFilter p_texture_filter) override; - virtual void set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) override; + // Fixing a nclearing methods. void fix_invalid_tiles(); + + void clear_layer(int p_layer); void clear(); + // Helpers + TypedArray<Vector2i> get_surrounding_tiles(Vector2i coords); + void draw_cells_outline(Control *p_control, Set<Vector2i> p_cells, Color p_color, Transform2D p_transform = Transform2D()); + + // Configuration warnings. + TypedArray<String> get_configuration_warnings() const override; + TileMap(); ~TileMap(); }; -VARIANT_ENUM_CAST(TileMap::Mode); -VARIANT_ENUM_CAST(TileMap::HalfOffset); -VARIANT_ENUM_CAST(TileMap::TileOrigin); +VARIANT_ENUM_CAST(TileMap::VisibilityMode); #endif // TILE_MAP_H |