/*************************************************************************/ /* tile_map.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #ifndef TILE_MAP_H #define TILE_MAP_H #include "core/templates/self_list.h" #include "core/templates/vset.h" #include "scene/2d/node_2d.h" #include "scene/resources/tile_set.h" class CollisionObject2D; class TileMap : public Node2D { GDCLASS(TileMap, Node2D); public: enum Mode { MODE_SQUARE, MODE_ISOMETRIC, MODE_CUSTOM }; enum HalfOffset { HALF_OFFSET_X, HALF_OFFSET_Y, HALF_OFFSET_DISABLED, HALF_OFFSET_NEGATIVE_X, HALF_OFFSET_NEGATIVE_Y, }; enum TileOrigin { TILE_ORIGIN_TOP_LEFT, TILE_ORIGIN_CENTER, TILE_ORIGIN_BOTTOM_LEFT }; private: enum DataFormat { FORMAT_1 = 0, FORMAT_2 }; Ref 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; bool bake_navigation = false; 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); } PosKey(int16_t p_x, int16_t p_y) { x = p_x; y = p_y; } PosKey() { x = 0; y = 0; } }; 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; }; Map tile_map; List dirty_bitmask; struct Quadrant { Vector2 pos; List canvas_items; RID body; uint32_t shape_owner_id = 0; SelfList dirty_list; struct NavPoly { RID region; Transform2D xform; }; struct Occluder { RID id; Transform2D xform; }; Map navpoly_ids; Map occluder_instances; VSet cells; 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) {} }; Map quadrant_map; SelfList::List dirty_quadrant_list; bool pending_update = false; 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 &p_shape, const TileSet::ShapeData &p_shape_data, const Transform2D &p_xform, const Vector2 &p_metadata); Map::Element *_create_quadrant(const PosKey &p_qk); void _erase_quadrant(Map::Element *Q); void _make_quadrant_dirty(Map::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(); void _update_all_items_material_state(); _FORCE_INLINE_ void _update_item_material_state(const RID &p_canvas_item); _FORCE_INLINE_ int _get_quadrant_size() const; void _set_tile_data(const Vector &p_data); Vector _get_tile_data() const; 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; } _FORCE_INLINE_ Vector2 _map_to_world(int p_x, int p_y, bool p_ignore_ofs = false) const; protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List *p_list) const; void _notification(int p_what); static void _bind_methods(); virtual void _validate_property(PropertyInfo &property) const override; public: enum { INVALID_CELL = -1 }; #ifdef TOOLS_ENABLED virtual Rect2 _edit_get_rect() const override; #endif void set_tileset(const Ref &p_tileset); Ref 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_bake_navigation(bool p_bake_navigation); bool is_baking_navigation(); 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 get_used_cells() const; TypedArray get_used_cells_by_index(int p_index) const; Rect2 get_used_rect(); // Not const because of cache void set_occluder_light_mask(int p_mask); int get_occluder_light_mask() const; virtual void set_light_mask(int p_light_mask) override; virtual void set_material(const Ref &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; TypedArray get_configuration_warnings() const override; virtual void set_texture_filter(CanvasItem::TextureFilter p_texture_filter) override; virtual void set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) override; void fix_invalid_tiles(); void clear(); TileMap(); ~TileMap(); }; VARIANT_ENUM_CAST(TileMap::Mode); VARIANT_ENUM_CAST(TileMap::HalfOffset); VARIANT_ENUM_CAST(TileMap::TileOrigin); #endif // TILE_MAP_H