1 // SuperTux 2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de> 3 // 4 // This program is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17 #ifndef HEADER_SUPERTUX_OBJECT_TILEMAP_HPP 18 #define HEADER_SUPERTUX_OBJECT_TILEMAP_HPP 19 20 #include <algorithm> 21 #include <unordered_set> 22 23 #include "math/rect.hpp" 24 #include "math/rectf.hpp" 25 #include "math/size.hpp" 26 #include "object/path_object.hpp" 27 #include "object/path_walker.hpp" 28 #include "squirrel/exposed_object.hpp" 29 #include "scripting/tilemap.hpp" 30 #include "supertux/autotile.hpp" 31 #include "supertux/game_object.hpp" 32 #include "video/color.hpp" 33 #include "video/flip.hpp" 34 #include "video/drawing_target.hpp" 35 36 class DrawingContext; 37 class CollisionObject; 38 class CollisionGroundMovementManager; 39 class Tile; 40 class TileSet; 41 42 /** This class is responsible for drawing the level tiles */ 43 class TileMap final : 44 public GameObject, 45 public ExposedObject<TileMap, scripting::TileMap>, 46 public PathObject 47 { 48 public: 49 TileMap(const TileSet *tileset); 50 TileMap(const TileSet *tileset, const ReaderMapping& reader); 51 ~TileMap() override; 52 53 virtual void finish_construction() override; 54 get_class() const55 virtual std::string get_class() const override { return "tilemap"; } get_icon_path() const56 virtual const std::string get_icon_path() const override { return "images/engine/editor/tilemap.png"; } get_display_name() const57 virtual std::string get_display_name() const override { return _("Tilemap"); } 58 59 virtual ObjectSettings get_settings() override; 60 virtual void after_editor_set() override; 61 62 virtual void update(float dt_sec) override; 63 virtual void draw(DrawingContext& context) override; 64 65 virtual void editor_update() override; 66 67 virtual void on_flip(float height) override; 68 69 /** Move tilemap until at given node, then stop */ 70 void goto_node(int node_no); 71 72 /** Start moving tilemap */ 73 void start_moving(); 74 75 /** Stop tilemap at next node */ 76 void stop_moving(); 77 78 void set(int width, int height, const std::vector<unsigned int>& vec, 79 int z_pos, bool solid); 80 81 /** resizes the tilemap to a new width and height (tries to not 82 destroy the existing map) */ 83 void resize(int newwidth, int newheight, int fill_id = 0, 84 int xoffset = 0, int yoffset = 0); 85 void resize(const Size& newsize, const Size& resize_offset); 86 get_width() const87 int get_width() const { return m_width; } get_height() const88 int get_height() const { return m_height; } get_size() const89 Size get_size() const { return Size(m_width, m_height); } 90 set_offset(const Vector & offset_)91 void set_offset(const Vector &offset_) { m_offset = offset_; } get_offset() const92 Vector get_offset() const { return m_offset; } 93 set_ground_movement_manager(const std::shared_ptr<CollisionGroundMovementManager> & movement_manager)94 void set_ground_movement_manager(const std::shared_ptr<CollisionGroundMovementManager>& movement_manager) 95 { 96 m_ground_movement_manager = movement_manager; 97 } 98 99 void move_by(const Vector& pos); 100 101 /** Get the movement of this tilemap. The collision detection code 102 may need a non-negative y-movement. Passing `false' as the 103 `actual' argument will provide that. Used exclusively in 104 src/supertux/sector.cpp. */ get_movement(bool actual) const105 Vector get_movement(bool actual) const 106 { 107 if (actual) { 108 return m_movement; 109 } else { 110 return Vector(m_movement.x, std::max(0.0f, m_movement.y)); 111 } 112 } 113 114 /** Returns the position of the upper-left corner of tile (x, y) in 115 the sector. */ get_tile_position(int x,int y) const116 Vector get_tile_position(int x, int y) const 117 { return m_offset + Vector(static_cast<float>(x), static_cast<float>(y)) * 32.0f; } 118 get_bbox() const119 Rectf get_bbox() const { 120 return Rectf(get_tile_position(0, 0), 121 get_tile_position(m_width, m_height)); 122 } 123 get_tile_bbox(int x,int y) const124 Rectf get_tile_bbox(int x, int y) const { 125 return Rectf(get_tile_position(x, y), 126 get_tile_position(x + 1, y + 1)); 127 } 128 129 /** Returns the half-open rectangle of (x, y) tile indices that 130 overlap the given rectangle in the sector. */ 131 Rect get_tiles_overlapping(const Rectf &rect) const; 132 133 /** Called by the collision mechanism to indicate that this tilemap has been hit on 134 the top, i.e. has hit a moving object on the bottom of its collision rectangle. */ 135 void hits_object_bottom(CollisionObject& object); 136 void notify_object_removal(CollisionObject* other); 137 get_layer() const138 int get_layer() const { return m_z_pos; } set_layer(int layer_)139 void set_layer(int layer_) { m_z_pos = layer_; } 140 is_solid() const141 bool is_solid() const { return m_real_solid && m_effective_solid; } 142 143 /** Changes Tilemap's solidity, i.e. whether to consider it when 144 doing collision detection. */ 145 void set_solid(bool solid = true); 146 147 bool is_outside_bounds(const Vector& pos) const; 148 const Tile& get_tile(int x, int y) const; 149 const Tile& get_tile_at(const Vector& pos) const; 150 uint32_t get_tile_id(int x, int y) const; 151 uint32_t get_tile_id_at(const Vector& pos) const; 152 153 void change(int x, int y, uint32_t newtile); 154 155 void change_at(const Vector& pos, uint32_t newtile); 156 157 /** changes all tiles with the given ID */ 158 void change_all(uint32_t oldtile, uint32_t newtile); 159 160 /** Puts the correct autotile block at the given position */ 161 void autotile(int x, int y, uint32_t tile); 162 163 enum class AutotileCornerOperation { 164 ADD_TOP_LEFT, 165 ADD_TOP_RIGHT, 166 ADD_BOTTOM_LEFT, 167 ADD_BOTTOM_RIGHT, 168 REMOVE_TOP_LEFT, 169 REMOVE_TOP_RIGHT, 170 REMOVE_BOTTOM_LEFT, 171 REMOVE_BOTTOM_RIGHT, 172 }; 173 174 /** Puts the correct autotile blocks at the tiles around the given corner */ 175 void autotile_corner(int x, int y, uint32_t tile, AutotileCornerOperation op); 176 177 /** Erases in autotile mode */ 178 void autotile_erase(const Vector& pos, const Vector& corner_pos); 179 180 /** Returns the Autotileset associated with the given tile */ 181 AutotileSet* get_autotileset(uint32_t tile) const; 182 set_flip(Flip flip)183 void set_flip(Flip flip) { m_flip = flip; } get_flip() const184 Flip get_flip() const { return m_flip; } 185 186 /** Start fading the tilemap to opacity given by @c alpha. 187 Destination opacity will be reached after @c seconds seconds. 188 Also influences solidity. */ 189 void fade(float alpha, float seconds = 0); 190 191 /** Start fading the tilemap to tint given by RGBA. 192 Destination opacity will be reached after @c seconds seconds. Doesn't influence solidity. */ 193 void tint_fade(const Color& new_tint, float seconds = 0); 194 195 /** Instantly switch tilemap's opacity to @c alpha. Also influences solidity. */ 196 void set_alpha(float alpha); 197 198 /** Return tilemap's opacity. Note that while the tilemap is fading 199 in or out, this will return the current alpha value, not the 200 target alpha. */ 201 float get_alpha() const; 202 203 void set_tileset(const TileSet* new_tileset); 204 get_tiles() const205 const std::vector<uint32_t>& get_tiles() const { return m_tiles; } 206 207 private: 208 void update_effective_solid(); 209 void float_channel(float target, float ¤t, float remaining_time, float dt_sec); 210 211 bool is_corner(uint32_t tile); 212 213 void apply_offset_x(int fill_id, int xoffset); 214 void apply_offset_y(int fill_id, int yoffset); 215 216 public: 217 bool m_editor_active; 218 219 private: 220 const TileSet* m_tileset; 221 222 typedef std::vector<uint32_t> Tiles; 223 Tiles m_tiles; 224 225 /* read solid: In *general*, is this a solid layer? effective solid: 226 is the layer *currently* solid? A generally solid layer may be 227 not solid when its alpha is low. See `is_solid' above. */ 228 bool m_real_solid; 229 bool m_effective_solid; 230 231 float m_speed_x; 232 float m_speed_y; 233 int m_width; 234 int m_height; 235 int m_z_pos; 236 Vector m_offset; 237 Vector m_movement; /**< The movement that happened last frame */ 238 239 /** Objects that were touching the top of a solid tile at the last frame */ 240 std::unordered_set<CollisionObject*> m_objects_hit_bottom; 241 242 std::shared_ptr<CollisionGroundMovementManager> m_ground_movement_manager; 243 244 Flip m_flip; 245 float m_alpha; /**< requested tilemap opacity */ 246 float m_current_alpha; /**< current tilemap opacity */ 247 float m_remaining_fade_time; /**< seconds until requested tilemap opacity is reached */ 248 249 /** The tint can have its own alpha channel, but this alpha channel doesn't affect 250 the solidity of the tilemap. This alpha channel makes the tilemap only less or 251 more translucent.*/ 252 Color m_tint; /**< requested tilemap tint */ 253 Color m_current_tint; /**< current tilemap tint */ 254 float m_remaining_tint_fade_time; /**< seconds until requested tilemap tint is reached */ 255 256 /** Set to LIGHTMAP to draw to lightmap */ 257 DrawingTarget m_draw_target; 258 259 int m_new_size_x; 260 int m_new_size_y; 261 int m_new_offset_x; 262 int m_new_offset_y; 263 bool m_add_path; 264 265 int m_starting_node; 266 267 private: 268 TileMap(const TileMap&) = delete; 269 TileMap& operator=(const TileMap&) = delete; 270 }; 271 272 #endif 273 274 /* EOF */ 275