1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Scene/BsGameObject.h"
7#include "Math/BsBounds.h"
8
9namespace bs
10{
11 /** @addtogroup Scene
12 * @{
13 */
14
15 /** Flags that control behavior of a Component. */
16 enum class ComponentFlag
17 {
18 /**
19 * Ensures that scene manager cannot pause or stop component callbacks from executing. Off by default.
20 * Note that this flag must be specified on component creation, in its constructor and any later changes
21 * to the flag could be ignored.
22 */
23 AlwaysRun = 1
24 };
25
26 typedef Flags<ComponentFlag> ComponentFlags;
27 BS_FLAGS_OPERATORS(ComponentFlag)
28
29 /**
30 * Components represent primary logic elements in the scene. They are attached to scene objects.
31 *
32 * You should implement some or all of update/fixedUpdate/onCreated/onInitialized/onEnabled/onDisabled/
33 * onTransformChanged/onDestroyed methods to implement the relevant component logic. Avoid putting logic in constructors
34 * or destructors.
35 *
36 * Components can be in different states. These states control which of the events listed above trigger:
37 * - Running - Scene manager is sending out events.
38 * - Paused - Scene manager is sending out all events except per-frame update().
39 * - Stopped - Scene manager is not sending out events except for onCreated/onDestroyed.
40 *
41 * These states can be changed globally though SceneManager and affect all components. Individual components can
42 * override these states in two ways:
43 * - Set the ComponentFlag::AlwaysRun to true and the component will always stay in Running state, regardless of
44 * state set in SceneManager. This flag should be set in constructor and not change during component lifetime.
45 * - If the component's parent SceneObject is inactive (SceneObject::setActive(false)), or any of his parents are
46 * inactive, then the component is considered to be in Stopped state, regardless whether the ComponentFlag::AlwaysRun
47 * flag is set or not.
48 **/
49 class BS_CORE_EXPORT Component : public GameObject
50 {
51 public:
52 /** Returns the SceneObject this Component is assigned to. */
53 const HSceneObject& sceneObject() const { return mParent; }
54
55 /** @copydoc sceneObject */
56 const HSceneObject& SO() const { return sceneObject(); }
57
58 /** Returns a handle to this object. */
59 const HComponent& getHandle() const { return mThisHandle; }
60
61 /** Called once per frame. Only called if the component is in Running state. */
62 virtual void update() { }
63
64 /**
65 * Called at fixed time intervals (e.g. 60 times per frame). Generally any physics-related functionality should
66 * go in this method in order to ensure stability of calculations. Only called if the component is in Running
67 * state.
68 */
69 virtual void fixedUpdate() { }
70
71 /**
72 * Calculates bounds of the visible contents represented by this component (for example a mesh for Renderable).
73 *
74 * @param[in] bounds Bounds of the contents in world space coordinates.
75 * @return True if the component has bounds with non-zero volume, otherwise false.
76 */
77 virtual bool calculateBounds(Bounds& bounds);
78
79 /**
80 * Checks if this and the provided component represent the same type.
81 *
82 * @note
83 * RTTI type cannot be checked directly since components can be further specialized internally for scripting
84 * purposes.
85 */
86 virtual bool typeEquals(const Component& other);
87
88 /**
89 * Removes the component from parent SceneObject and deletes it. All the references to this component will be
90 * marked as destroyed and you will get an exception if you try to use them.
91 *
92 * @param[in] immediate If true the destruction will be performed immediately, otherwise it will be delayed
93 * until the end of the current frame (preferred option).
94 */
95 void destroy(bool immediate = false);
96
97 /** @name Internal
98 * @{
99 */
100
101 /**
102 * Construct any resources the component needs before use. Called when the parent scene object is instantiated.
103 * A non-instantiated component shouldn't be used for any other purpose than serialization.
104 */
105 virtual void _instantiate() {}
106
107 /** Sets new flags that determine when is onTransformChanged called. */
108 void setNotifyFlags(TransformChangedFlags flags) { mNotifyFlags = flags; }
109
110 /** Gets the currently assigned notify flags. See _setNotifyFlags(). */
111 TransformChangedFlags _getNotifyFlags() const { return mNotifyFlags; }
112
113 /** @} */
114 protected:
115 friend class SceneManager;
116 friend class SceneObject;
117 friend class SceneObjectRTTI;
118
119 Component(HSceneObject parent);
120 virtual ~Component() = default;
121
122 /** Called once when the component has been created. Called regardless of the state the component is in. */
123 virtual void onCreated() {}
124
125 /**
126 * Called once when the component first leaves the Stopped state. This includes component creation if requirements
127 * for leaving Stopped state are met, in which case it is called after onCreated.
128 */
129 virtual void onInitialized() {}
130
131 /** Called once just before the component is destroyed. Called regardless of the state the component is in. */
132 virtual void onDestroyed() {}
133
134 /**
135 * Called every time a component is placed into the Stopped state. This includes component destruction if component
136 * wasn't already in Stopped state during destruction. When called during destruction it is called before
137 * onDestroyed.
138 */
139 virtual void onDisabled() {}
140
141 /**
142 * Called every time a component leaves the Stopped state. This includes component creation if requirements
143 * for leaving the Stopped state are met. When called during creation it is called after onInitialized.
144 */
145 virtual void onEnabled() {}
146
147 /**
148 * Called when the component's parent scene object has changed. Not called if the component is in Stopped state.
149 * Also only called if necessary notify flags are set via _setNotifyFlags().
150 */
151 virtual void onTransformChanged(TransformChangedFlags flags) { }
152
153 /** Checks whether the component wants to received the specified transform changed message. */
154 bool supportsNotify(TransformChangedFlags flags) const { return (mNotifyFlags & flags) != 0; }
155
156 /** Enables or disabled a flag controlling component's behaviour. */
157 void setFlag(ComponentFlag flag, bool enabled) { if (enabled) mFlags.set(flag); else mFlags.unset(flag); }
158
159 /** Checks if the component has a certain flag enabled. */
160 bool hasFlag(ComponentFlag flag) const { return mFlags.isSet(flag); }
161
162 /** Sets an index that uniquely identifies a component with the SceneManager. */
163 void setSceneManagerId(UINT32 id) { mSceneManagerId = id; }
164
165 /** Returns an index that unique identifies a component with the SceneManager. */
166 UINT32 getSceneManagerId() const { return mSceneManagerId; }
167
168 /**
169 * Destroys this component.
170 *
171 * @param[in] handle Game object handle this this object.
172 * @param[in] immediate If true, the object will be deallocated and become unusable right away. Otherwise the
173 * deallocation will be delayed to the end of frame (preferred method).
174 *
175 * @note Unlike destroy(), does not remove the component from its parent.
176 */
177 void destroyInternal(GameObjectHandleBase& handle, bool immediate) override;
178 private:
179 Component(const Component& other) { }
180
181 protected:
182 HComponent mThisHandle;
183 TransformChangedFlags mNotifyFlags = TCF_None;
184 ComponentFlags mFlags;
185 UINT32 mSceneManagerId = 0;
186
187 private:
188 HSceneObject mParent;
189
190 /************************************************************************/
191 /* RTTI */
192 /************************************************************************/
193 public:
194 friend class ComponentRTTI;
195 static RTTITypeBase* getRTTIStatic();
196 RTTITypeBase* getRTTI() const override;
197
198 protected:
199 Component() = default; // Serialization only
200 };
201
202 /** @} */
203}