VoltAir
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Groups Pages
Engine.h
1 /*
2  * Copyright (C) 2014 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ENGINE_H
18 #define ENGINE_H
19 
20 #include <QList>
21 #include <QObject>
22 #include <QQuickItem>
23 #include <QSet>
24 #include <functional>
26 #include "utils/ContactListener.h"
27 #include "utils/DestructionListener.h"
28 
29 class Camera;
30 class Environment;
31 class InputArea;
32 class Level;
33 class LevelInfo;
34 class LiquidFunDebugDraw;
35 class QQuickItem;
36 class QQuickView;
37 class SoundManager;
38 class TextureManager;
39 class TerrainMaterials;
40 class b2World;
41 
84 class Engine : public QObject {
85  Q_OBJECT
86 public:
87 
93  enum Phase {
94 
102 
111 
118 
119 
127 
128 
138 
144  };
145 
149  static const float UPDATE_FREQUENCY;
150 
154  static const float TIME_STEP_S;
155 
159  static const float TIME_STEP_MS;
160 
164  static const int VELOCITY_ITERATIONS;
165 
169  static const int POSITION_ITERATIONS;
170 
174  static const int PARTICLE_ITERATIONS;
175 
176  virtual ~Engine();
177 
187  void init();
188 
192  bool isInitialized() const { return mIsInitialized; }
193 
198  Q_INVOKABLE bool isPaused() const { return mPausedRefCount != 0; }
199 
203  b2World* getWorld() const;
204 
208  long long getWorldStepCount() const { return mWorldStepCount; }
209 
210 
214  QQmlEngine* getQmlEngine() const;
215 
219  QQuickItem* getRoot() const;
220 
224  Camera* getCamera() const { return mCamera; }
225 
229  Renderer* getRenderer() const { return mRenderer.get(); }
230 
234  Q_INVOKABLE SoundManager* getSoundManager() const { return mSoundManager.get(); }
235 
239  TextureManager* getTextureManager() const { return mTextureManager.get(); }
240 
244  TerrainMaterials* getTerrainMaterials() const { return mTerrainMaterials.get(); }
245 
246 
250  ContactListener* getContactListener() const { return mContactListener.get(); }
251 
257  Phase getPhase() const { return mPhase; }
258 
264  void addChildItem(QQuickItem* item);
265 
269  Q_INVOKABLE Level* getLevel() const { return mLevel; }
270  // TODO: Consider refactoring into separate Analytics / Tracker class.
277  Q_INVOKABLE void setTrackerScreenName(const QString& screenName, bool sendScreenView = true);
284  Q_INVOKABLE void sendTrackerEvent(const QString& category, const QString& action);
292  Q_INVOKABLE void sendTrackerEvent(const QString& category, const QString& action,
293  const QString& label);
302  Q_INVOKABLE void sendTrackerEvent(const QString& category, const QString& action,
303  const QString& label, long value);
311  Q_INVOKABLE void sendTrackerEvent(const QString& category, const QString& action, long value);
312 
328  template <typename T>
329  void forEach(const std::function<void(T*)>& func) const {
330  static QList<T*> sItemCache;
331 
332  // Check if we have a valid cache of these items
333  if (!mValidCacheSet.contains(&T::staticMetaObject)) {
334  sItemCache.clear();
335  createItemCache(getRoot(), &sItemCache);
336  mValidCacheSet.insert(&T::staticMetaObject);
337  }
338 
339  for (T* t : sItemCache) {
340  func(t);
341  }
342  }
343 
352  template <typename T>
353  void invalidateSceneGraphObjectCache() { mValidCacheSet.remove(&T::staticMetaObject); }
354 
360  void invalidateSceneGraphObjectCaches() { mValidCacheSet.clear(); }
361 
362  // TODO: Provide an invalidate function that is given a const QMetaObject*.
363  // It could be used to intelligently traverse the altered sub-tree of the scene graph and only
364  // invalidate the affected caches. However, the problem is the object's meta object changes
365  // between calls and is not equal in reference to the static meta object.
366 
376  template <typename T>
377  void forEach(QObject* root, const std::function<void(T*)>& func) const {
378  T* t = qobject_cast<T*>(root);
379  if (t) {
380  func(t);
381  }
382  for (QObject* child : root->children()) {
383  forEach(child, func);
384  }
385  }
386 
394  void loadLevel(LevelInfo* levelInfo);
395 
400  void deleteCurrentLevel();
401 
402  // TODO: Split this into two methods: create and getInstance()
407  static Engine* getInstance(bool createIfNecessary = true);
408 
409 public slots:
410 
414  void pause();
415 
419  void resume();
420 
424  void onPlayLevelRequested();
425 
429  void onQuitRequested();
430 
434  void onSignedIntoCloudChanged(bool signedIntoCloud);
435 
439  void onCloudDataLoaded(int statusCode, const QString& data);
440 
444  void onOpeningCinematicCompleted(const QString& menuBGMTrack);
445 
458  void onDeviceCreate();
459 
463  void onDeviceStart();
464 
468  void onDeviceResume();
469 
473  void onDevicePause();
474 
478  void onDeviceStop();
479 
483  void onDeviceDestroy();
484 
489 signals:
496  void levelChanged(const QString& levelName, int completionThreshold, int activationThreshold);
497 
502  void signedIntoCloudChanged(bool signedIntoCloud);
503 
509  void cloudDataLoaded(int statusCode, const QString& data);
510 
514  void beforeUpdate();
515 
519  void afterUpdate();
520 
521  // Signals for forwarding device lifecyle events.
522  // See NOTE from device lifecycle slots above.
523 
534  void deviceCreate();
535 
536 
540  void deviceStart();
541 
545  void deviceResume();
546 
550  void devicePause();
551 
555  void deviceStop();
556 
568  void deviceDestroy();
569 
570 private slots:
571  void update();
572  void onBeforeSynchronizing();
573  void onBeforeRendering();
574  void onAfterRendering();
575  void onLoadCompleted(bool success);
576 
577 private:
578  // Level needs access to setCurrentLevel and queueWorldForDeletion.
579  friend class Level;
580 
584  Engine(QObject* parent = nullptr);
585 
590  void setCurrentLevel(Level* level);
595  void queueWorldForDeletion(b2World* world);
596 
597  void startLoad();
598  void performLevelChange();
599  void setPhase(Phase phase);
600 
601  template <typename T>
602  void createItemCache(QObject* item, QList<T*>* itemCache) const {
603  T* t = qobject_cast<T*>(item);
604  if (t) {
605  itemCache->push_back(t);
606  }
607  for (QObject* child : item->children()) {
608  createItemCache(child, itemCache);
609  }
610  }
611 
612  void showViewer();
613  void hideViewer();
614  // This function updates the camera transformations, which has the desired side-effect of
615  // forcing the render thread to execute every time it's called. It is almost always called
616  // before leaving update().
617  void updateCamera();
618  void sceneRender();
619  void debugRender();
620  void synchronizeForRendering();
621 
622  bool mIsInitialized = false;
623  // The game starts paused.
624  int mPausedRefCount = 1;
625  long long mWorldStepCount = 0;
626  Phase mPhase = LOGICS_PHASE;
627  Camera* mCamera = nullptr;
628  QQuickItem* mDebugHudItem = nullptr;
629  InputArea* mInputArea = nullptr;
630  bool mLevelReady = false;
631  Level* mLevel = nullptr;
632  bool mHasNextLevel = false;
633  int mSyncsSinceNextLevelRequest = 0;
634  QString mNextLevelName;
635  QQuickItem* mLevelLoader = nullptr;
636  volatile bool mViewerReady = false;
637  std::unique_ptr<QQuickView> mViewer;
638  std::unique_ptr<ContactListener> mContactListener;
639  std::unique_ptr<DestructionListener> mDestructionListener;
640  std::unique_ptr<Renderer> mRenderer;
641  std::unique_ptr<RenderList> mRenderList;
642  std::unique_ptr<TextureManager> mTextureManager;
643  std::unique_ptr<TerrainMaterials> mTerrainMaterials;
644  std::unique_ptr<LiquidFunDebugDraw> mDebugDraw;
645  std::unique_ptr<SoundManager> mSoundManager;
646  // Temporary state to ensure the level gets deleted after the level stops rendering.
647  std::unique_ptr<b2World> mWorldToDelete;
648  mutable QSet<const QMetaObject*> mValidCacheSet;
649  LevelInfo* mInFlightLevelInfo;
650 
651  static Engine* sInstance;
652 };
653 Q_DECLARE_METATYPE(Engine*)
654 
655 #endif // ENGINE_H
Implementation of b2Draw which renders objects (body fixtures, particles, etc.) using DebugRenderer...
Definition: LiquidFunDebugDraw.h:35
b2World * getWorld() const
Returns the Box2D world object.
void clear()
void onDevicePause()
Respond to Android onPause().
static const int PARTICLE_ITERATIONS
LiquidFun particle solve iterations, controlling world substepping.
Definition: Engine.h:174
void resume()
Respond to game resume.
ContactListener * getContactListener() const
Returns ContactListener, the Engine's implementation of the b2ContactListener.
Definition: Engine.h:250
Engine is executing the Body::updateBeforePhysics() calls.
Definition: Engine.h:110
static const float TIME_STEP_S
The fixed simulation time step between frames, in seconds.
Definition: Engine.h:154
void deviceStart()
Emitted at end of onDeviceStart().
Class managing GL state switches and draw calls.
Definition: Renderer.h:50
void deviceDestroy()
Signal for when the device has reached the end of its application lifecycle.
void push_back(const T &value)
void cloudDataLoaded(int statusCode, const QString &data)
Emitted when the cloud data is loaded.
Class which loads and caches Textures.
Definition: TextureManager.h:37
Q_INVOKABLE Level * getLevel() const
Returns the current Level being displayed and executed.
Definition: Engine.h:269
Q_INVOKABLE SoundManager * getSoundManager() const
Returns the SoundManager object.
Definition: Engine.h:234
const QObjectList & children() const
static Engine * getInstance(bool createIfNecessary=true)
Returns the global singleton instance of Engine.
Engine is adjusting the camera relative to the state of the world.
Definition: Engine.h:137
Phase getPhase() const
Return the phase of execution.
Definition: Engine.h:257
bool isInitialized() const
Returns true if the Engine has been initialized.
Definition: Engine.h:192
iterator insert(const T &value)
void onDeviceResume()
Respond to Android onResume().
The singleton object responsible for game execution.
Definition: Engine.h:84
void invalidateSceneGraphObjectCaches()
Invalidates the caches of all scene graph objects, regardless of type.
Definition: Engine.h:360
TextureManager * getTextureManager() const
Returns the TextureManager object.
Definition: Engine.h:239
TerrainMaterials * getTerrainMaterials() const
Returns the TerrainMaterials object.
Definition: Engine.h:244
void invalidateSceneGraphObjectCache()
Invalidates the cache of scene graph objects of the specified type.
Definition: Engine.h:353
Metadata for a Level.
Definition: LevelInfo.h:31
Ui module for gaining basic input event (i.e. keyboard) support on non-Android devices.
Definition: InputArea.h:46
void loadLevel(LevelInfo *levelInfo)
Emits the signal to load level/start game.
Controls the sound effects and background music (BGM) audio tracks needed to be played during the gam...
Definition: SoundManager.h:39
long long getWorldStepCount() const
Returns the number of physics steps since last level loaded.
Definition: Engine.h:208
void onDeviceStop()
Respond to Android onStop().
void onSignedIntoCloudChanged(bool signedIntoCloud)
Respond to state of cloud sign-in changed.
void pause()
Respond to game pause.
Handler for notifications of ContactEvents from the b2World.
Definition: ContactListener.h:29
void onOpeningCinematicCompleted(const QString &menuBGMTrack)
Respond to opening cinematic finishing.
void beforeUpdate()
Emitted at the start of the update() call.
void addChildItem(QQuickItem *item)
Add a child item to the QQuickItem scene graph.
void forEach(QObject *root, const std::function< void(T *)> &func) const
Recursively traverses scene graph and call func on each QObject of type T, starting at the given root...
Definition: Engine.h:377
Camera * getCamera() const
Returns the Camera object.
Definition: Engine.h:224
void signedIntoCloudChanged(bool signedIntoCloud)
Emitted when cloud sign-in has changed.
Q_INVOKABLE void setTrackerScreenName(const QString &screenName, bool sendScreenView=true)
Sets the Google Analytics screen name and optionally sends a screen view hit.
void deviceStop()
Emitted at end of onDeviceStop().
void levelChanged(const QString &levelName, int completionThreshold, int activationThreshold)
Emitted when a new level is finished loading a level.
Representation of an in-game level.
Definition: Level.h:48
QQuickItem * getRoot() const
Returns the root item, as defined in the main QML file.
void onCloudDataLoaded(int statusCode, const QString &data)
Respond to cloud data being loaded.
Engine is rendering.
Definition: Engine.h:143
Q_INVOKABLE void sendTrackerEvent(const QString &category, const QString &action)
Sends an event hit to Google Analytics.
bool contains(const T &value) const
void onQuitRequested()
Respond to quit request.
void onPlayLevelRequested()
Respond to request to play the current level.
Renderer * getRenderer() const
Returns the Renderer object, the game-specific renderer.
Definition: Engine.h:229
bool remove(const T &value)
static const int VELOCITY_ITERATIONS
LiquidFun velocity iterations, controlling world substepping.
Definition: Engine.h:164
Engine is executing the Logic::update() calls.
Definition: Engine.h:101
void deviceResume()
Emitted at end of onDeviceResume().
File containing forward declarations for renderer types and smart pointers.
void onDeviceStart()
Respond to Android onStart().
void init()
Initialize the Engine.
void devicePause()
Emitted at end of onDevicePause().
static const float TIME_STEP_MS
The fixed simulation time step between frames, in milliseconds.
Definition: Engine.h:159
void deviceCreate()
Emitted at end of onDeviceCreate().
Grouping of related LevelInfos together into an logical, ordered list.
Definition: Environment.h:37
void clear()
QQuickItem which represents the Camera into the game world.
Definition: Camera.h:42
QObject * parent() const
void deleteCurrentLevel()
Mark the current level for deletion and remove it from the scene graph to avoid continuing rendering ...
QQmlEngine * getQmlEngine() const
Returns the QQmlEngine being used by the Engine.
void onDeviceCreate()
Respond to Android onCreate().
Q_INVOKABLE bool isPaused() const
Returns true if engine is paused, e.g. when the in-game menu is open.
Definition: Engine.h:198
Engine is executing the Body::updateAfterPhysics() calls.
Definition: Engine.h:126
Engine is executing the Box2D/LiquidFun physics.
Definition: Engine.h:117
static const float UPDATE_FREQUENCY
The target frame rate.
Definition: Engine.h:149
void forEach(const std::function< void(T *)> &func) const
Recursively traverses scene graph and call func on each QObject of type T.
Definition: Engine.h:329
void onDeviceDestroy()
Respond to Android onDestroy().
Phase
The phases of Engine execution.
Definition: Engine.h:93
static const int POSITION_ITERATIONS
LiquidFun position iterations, controlling world substepping.
Definition: Engine.h:169
Class managing a collection of TerrainMaterialDefs.
Definition: TerrainMaterials.h:31
void afterUpdate()
Emitted at the end of the update() call.