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