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 &current, 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