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_SUPERTUX_GAME_OBJECT_HPP
18 #define HEADER_SUPERTUX_SUPERTUX_GAME_OBJECT_HPP
19 
20 #include <algorithm>
21 #include <string>
22 
23 #include "editor/object_settings.hpp"
24 #include "supertux/game_object_component.hpp"
25 #include "util/fade_helper.hpp"
26 #include "util/gettext.hpp"
27 #include "util/uid.hpp"
28 
29 class DrawingContext;
30 class GameObjectComponent;
31 class ObjectRemoveListener;
32 class ReaderMapping;
33 class Writer;
34 
35 /**
36     Base class for all the things that make up Levels' Sectors.
37 
38     Each sector of a level will hold a list of active GameObject while the
39     game is played.
40 
41     This class is responsible for:
42     - Updating and Drawing the object. This should happen in the update() and
43       draw() functions. Both are called once per frame.
44     - Providing a safe way to remove the object by calling the remove_me
45       functions.
46 */
47 class GameObject
48 {
49   friend class GameObjectManager;
50 
51 public:
52   GameObject();
53   GameObject(const std::string& name);
54   GameObject(const ReaderMapping& reader);
55   virtual ~GameObject();
56 
57   /** Called after all objects have been added to the Sector and the
58       Sector is fully constructed. If objects refer to other objects
59       by name, those connection can be resolved here. */
finish_construction()60   virtual void finish_construction() {}
61 
get_uid() const62   UID get_uid() const { return m_uid; }
63 
64   /** This function is called once per frame and allows the object to
65       update it's state. The dt_sec is the time that has passed since
66       the last frame in seconds and should be the base for all timed
67       calculations (don't use SDL_GetTicks directly as this will fail
68       in pause mode). This function is not called in the Editor. */
69   virtual void update(float dt_sec) = 0;
70 
71   /** The GameObject should draw itself onto the provided
72       DrawingContext if this function is called. */
73   virtual void draw(DrawingContext& context) = 0;
74 
75   /** This function saves the object. Editor will use that. */
76   virtual void save(Writer& writer);
get_class() const77   virtual std::string get_class() const { return "game-object"; }
get_display_name() const78   virtual std::string get_display_name() const { return _("Unknown object"); }
79 
80   /** If true only a single object of this type is allowed in a
81       given GameObjectManager */
is_singleton() const82   virtual bool is_singleton() const { return false; }
83 
84   /** Does this object have variable size
85       (secret area trigger, wind, etc.) */
has_variable_size() const86   virtual bool has_variable_size() const { return false; }
87 
88   /** Indicates if the object will be saved. If false, the object will
89       be skipped on saving and can't be cloned in the editor. */
is_saveable() const90   virtual bool is_saveable() const { return true; }
91 
92   /** Indicates if get_settings() is implemented. If true the editor
93       will display Tip and ObjectMenu. */
has_settings() const94   virtual bool has_settings() const { return is_saveable(); }
95   virtual ObjectSettings get_settings();
96 
after_editor_set()97   virtual void after_editor_set() {}
98 
99   /** When level is flipped vertically */
on_flip(float height)100   virtual void on_flip(float height) {}
101 
102   /** schedules this object to be removed at the end of the frame */
remove_me()103   virtual void remove_me() { m_scheduled_for_removal = true; }
104 
105   /** returns true if the object is not scheduled to be removed yet */
is_valid() const106   bool is_valid() const { return !m_scheduled_for_removal; }
107 
108   /** registers a remove listener which will be called if the object
109       gets removed/destroyed */
110   void add_remove_listener(ObjectRemoveListener* listener);
111 
112   /** unregisters a remove listener, so it will no longer be called if
113       the object gets removed/destroyed */
114   void del_remove_listener(ObjectRemoveListener* listener);
115 
set_name(const std::string & name)116   void set_name(const std::string& name) { m_name = name; }
get_name() const117   const std::string& get_name() const { return m_name; }
118 
get_icon_path() const119   virtual const std::string get_icon_path() const {
120     return "images/tiles/auxiliary/notile.png";
121   }
122 
123   /** stops all looping sounds */
stop_looping_sounds()124   virtual void stop_looping_sounds() {}
125 
126   /** continues all looping sounds */
play_looping_sounds()127   virtual void play_looping_sounds() {}
128 
129   template<typename T>
get_component()130   T* get_component() {
131     for(auto& component : m_components) {
132       if (T* result = dynamic_cast<T*>(component.get())) {
133         return result;
134       }
135     }
136     return nullptr;
137   }
138 
add_component(std::unique_ptr<GameObjectComponent> component)139   void add_component(std::unique_ptr<GameObjectComponent> component) {
140     m_components.emplace_back(std::move(component));
141   }
142 
remove_component(GameObjectComponent * component)143   void remove_component(GameObjectComponent* component) {
144     auto it = std::find_if(m_components.begin(), m_components.end(),
145                            [component](const std::unique_ptr<GameObjectComponent>& lhs){
146                              return lhs.get() == component;
147                            });
148     if (it != m_components.end()) {
149       m_components.erase(it);
150     }
151   }
152 
153   /** The editor requested the deletion of the object */
editor_delete()154   virtual void editor_delete() { remove_me(); }
155 
156   /** The user clicked on the object in the editor and selected it*/
editor_select()157   virtual void editor_select() {}
158 
159   /** The object got deselected */
editor_deselect()160   virtual void editor_deselect() {}
161 
162   /** Called each frame in the editor, used to keep linked objects
163       together (e.g. platform on a path) */
editor_update()164   virtual void editor_update() {}
165 
166 private:
set_uid(const UID & uid)167   void set_uid(const UID& uid) { m_uid = uid; }
168 
169 protected:
170   /** a name for the gameobject, this is mostly a hint for scripts and
171       for debugging, don't rely on names being set or being unique */
172   std::string m_name;
173 
174   /** Fade Helpers are for easing/fading script functions */
175   std::vector<std::unique_ptr<FadeHelper>> m_fade_helpers;
176 
177 private:
178   /** A unique id for the object to safely refer to it. This will be
179       set by the GameObjectManager. */
180   UID m_uid;
181 
182   /** this flag indicates if the object should be removed at the end of the frame */
183   bool m_scheduled_for_removal;
184 
185   std::vector<std::unique_ptr<GameObjectComponent> > m_components;
186 
187   std::vector<ObjectRemoveListener*> m_remove_listeners;
188 
189 private:
190   GameObject(const GameObject&) = delete;
191   GameObject& operator=(const GameObject&) = delete;
192 };
193 
194 #endif
195 
196 /* EOF */
197