11 Miscellaneous and Advanced Concepts

In this chapter we will present you with some additional topics that didn't fit into the main part of the book. First we'll have a look at teaching your programs to communicate with the user in different languages. Then we will see how to establish communication channels between processes. Next it will be explained how to make your applications multithreaded to leverage the growing numbers of computing cores in modern machines. The next section of this chapter will explain how to use hardware sensors present on many devices, especially in the mobile section of the market to make your game on mobile devices a richer experience. Then we will have a look at how you can track a device with the help of GPS and how you can connect multiple devices via Bluetooth or NFC. Handling media data is also an important topic. Thus, we will try to show you the of using multimedia with in the following sections of the chapter. Finally, we will look into debugging and testing. This will cover how to print simple debug messages as well as how GDB or CDB are integrated into and made usable through this IDE. In the end Qt Test will be introduced to show you how you can realize unit tests with Qt. By the end of this chapter you will have a broader perspective of technologies available as a part of Qt. You will be able to use a wider range of tools and technologies in your games making them better and richer in features.

Utility frameworks In this section we will show you a couple of frameworks or other solutions you can use to make your games more versatile. This includes showing messages to the users in their own language, multithreading and multiprocess communication, as well as a framework for using multimedia such as video and sound in your games.

[ 1 ] Miscellaneous and Advanced Concepts Internationalization Qt is an application programming framework used all over the world. Just as it can handle many text encodings, it also supports many languages. With Qt you can easily teach your application to communicate to the user using his native language. The font engine used by Qt can render fonts that use a variety of different writing systems and all standard text widgets can accept input in any language, and Qt's text drawing routines try to take into consideration text rendering rules present in particular languages. Still, you as the application have to perform some additional work to make sure your application is correctly internationalized and localized.

Since QString is based on Unicode, it can hold and express text in virtually any language in the world. Thus it is important that you use QString for every user-visible text in your program. However, other text data that the user can't see (for example, object names, debug messages, text format definitions) can still be held using the traditional const char * and char types.

Marking text for translation Each user-visible text should be translated into the language that the user expects. Text substitution is performed using the QCoreApplication::translate() method. Usually, you don't need to call it yourself. The regular approach is to surround all your bare string literals in calls to QObject::tr() that will then call translate() for you. Thus everywhere where you'd normally use QStringLiteral, you can instead use tr():

QLabel *label = new QLabel; label->setText(tr("This is my internationalized label text"));

Apart from translating the text within, this call serves another purpose—it marks the text that is to be extracted by a special harvesting tool that will assemble message catalogs for your project. It is important that tr() marks only the string literals and not variables. The following code will not work:

const char* labelTexts[] = { "Name", "Age", "Address" };

for(int i=0; i<3; ++i) { QLabel *label = new QLabel; label->setText(tr(txt[i])); doSomethingWith(label, i); }

[ 2 ] Chapter 11

This is because txt[i] is a variable that cannot be translated. You would have to wrap items in labelTexts in calls to tr() but ++ forbids that. To overcome this problem Qt offers QT_TR_NOOP and QT_TRANSLATE_NOOP macros that mark texts for translation without translating anything. Then the effective code becomes as shown:

const char* labelTexts[] = { QT_TR_NOOP("Name"), QT_TR_NOOP("Age"), QT_TR_NOOP("Address") };

for(int i=0; i<3; ++i) { QLabel *label = new QLabel; label->setText(tr(txt[i])); doSomethingWith(label, i); }

The difference betweenQT_TR_NOOP and QT_TRANSLATE_NOOP is that when using the latter you can provide a so called context of the translation, which is by default the class name where the translation occurs. This context allows identifying similar messages that were defined in different places. There is also QT_TRANSLATE_NOOP3, which has an additional argument where the author can provide a comment to the message being translated— for example, when translating a copy, the author can leave some information for the translator whether the word means a verb (to copy something) or a noun (a copy of something).

Producing translations Once the is complete, the next step is to extract all messages and produce message catalogs. This is done by declaring translations in the project file. To declare translations, you need to fill the TRANSLATIONS variable with paths to catalogs that need to be maintained by the project:

TRANSLATIONS += translations/myapp_en.ts \ translations/myapp_fr.ts \ translations/myapp_pl.ts

The convention is to name the files with your application name followed by an underscore and international symbol of the language (for example, en for English, fr for French, pl for Polish, and so on) and a .ts file extension. If a language is used in more than one country, you can follow the language name with a country symbol forming the full language variant (for example, en_us or en_au).

[ 3 ] Miscellaneous and Advanced Concepts

When the list is ready, you should run the lupdate tool on the project file. You can either do this manually or from Qt Creator by opening the Tools menu, going to External and then Linguist and finally choosing Update translations (lupdate). This will produce files declared in the TRANSLATIONS variable that contain all the messages from your project. Whenever you change your source code you can run lupdate again to update message catalogs without overwriting already present translations.

The next step is to give those files to people who can act as translators for the application. Qt contains a dedicated tool called Linguist that can help with the task. You can see it in the following screenshot:

The Linguist tool is very easy to use so we will not discuss it in detail here.

Two important things to note are to set language details for the catalog as you start working with a file by opening the Edit menu and choosing Translation File Settings. The other important thing to remember is to mark your translations as "done" if you want them to be used. This is done with the Ctrl + Return keyboard shortcut (or by choosing Done and Next from Translation menu) so that a green tick appears next to the source text in the list of strings.

[ 4 ] Chapter 11

When translations are ready, you can call the lrelease tool (either from Qt Creator or from Qt Linguist) to produce compressed message catalogs (with .qm file extension).

Applying translation The final step is to enable translation process for your application. This is done by creating an instance of QTranslator, loading a message catalog into it, and passing the translator object pointer to the QCoreApplication::installTranslator() method. From now on all calls to QObject::tr() will result in substituting original texts with their translated versions. If translation for any message cannot be found, the translator uses the original text as a fallback.

Time for action – translating a list of strings application Create a new Qt Widgets Application in Creator. Choose to create a MainWindow form and widget class for it. After the skeleton code is created, open mainwindow.ui and drag a Combo Box widget to the form. Apply a horizontal layout so that the combo box snaps into place. Click on the combo box, find its objectName property in the property editor and note it down—it should be called comboBox. Save the form and open the mainwindow.cpp file. Position the cursor just below the include lines and add a code that creates a static array of string literals (make sure to wrap all literals into the QT_TRANSLATE_NOOP macros):

static const char *countries[] = { QT_TRANSLATE_NOOP("MainWindow", "Canada"), QT_TRANSLATE_NOOP("MainWindow", "Germany"), QT_TRANSLATE_NOOP("MainWindow", "Norway"), QT_TRANSLATE_NOOP("MainWindow", "Poland"), QT_TRANSLATE_NOOP("MainWindow", "United Kingdom") };

Now go to the class constructor and add the following code to it:

for(int i=0; i<5; ++i) { ui->comboBox->addItem(tr(countries[i])); } setWindowTitle(tr("Country Selection"));

Essentially we add all country names to the combo box at the same time trying to translate them by wrapping them into calls to tr(). Finally, we set the window title to Country Selection.

[ 5 ] Miscellaneous and Advanced Concepts

Now open main.cpp and modify the main() function to install a translator on the application based on the user's system locale:

int main(int argc, char **argv) { QApplication app(argc, argv); QTranslator translator; translator.load(QLocale::system(), "countryselection", "_"); app.installTranslator(&translator); MainWindow w; w.show();

return app.exec(); }

Next, open the project file (the one having a .pro suffix) and add an entry to it that defines translation catalogs:

TRANSLATIONS = countryselection_en.ts countryselection_pl.ts

You can also add a translation file for your native language if it is other than English or Polish which is my native language. Save the project file.

Installing translators is done in two steps. First, we should load a message catalog using the load() call. It gets three arguments—the language environment definition (locale) such as the default system locale retrieved by QLocale::system(), then the base filename and finally the language name prefix. The filename of the catalog to be loaded is composed by concatenating the base filename, the prefix, the user interface language name retrieved from the locale object, and a suffix. The latter, if not given, will default to .qm. We have to name our translation files using the same pattern so that when they are converted to message catalogs, QTranslator::load will be able to find them.

The second installation step involves calling installTranslator on the application object, passing it a pointer to the translator object that is to be added to a list of objects responsible for showing our user interfaces in the proper language. Remember to make sure the translator object lives as long as you want it to perform translations. Do not create the object on stack unless you are in the main() function. Now open Creator's Tools menu, choose External then Linguist and finally Update Translations (lupdate). You will see lupdate crawl your source files and report the number of message entries found.

[ 6 ] Chapter 11

Now launch Qt Linguist and open countryselection_pl.ts file (or an equivalent for your language). In the Translations box click the Canada entry and lower in the window you will find a box where you can enter the translation. Type in Kanada since that's Canada translated to Polish. Repeat for other countries, typing in Niemcy, Norwegia, Polska, and Zjednoczone Królestwo accordingly. Finally, translate Country Selection as "Wybór kraju". Of course if you are working with a language other than Polish, provide appropriate translations. If the same message in one language can have more than one meaning represented by different messages in another language as we described it earlier, to make the translator's work easier, the programmer can set a second argument to tr(), which is a text visible for the translator in Linguist as Programmer comments field near the message to be translated.

When you are done, save the file, exit Qt Linguist, and go back to Qt Creator. From External menu choose Linguist and then Release Translations (lrelease). This transforms translations files into message catalogs (with .qm file extension). Copy them to the build directory of your project if they are not already there.

If you run your program now, you should see all text translated to your language if the message catalog for it exists. One more thing you can do is provide a way to force loading a given translation on demand.

For that we will modify the main function to accept a -lang parameter that sets the locale for the program. Modify the main() function to look as follows:

int main(int argc, char **argv) { QApplication app(argc, argv); QStringList args = QCoreApplication::arguments(); int idx = args.indexOf(QStringLiteral("-lang")); if(idx >=0 && idx < args.count()) { QLocale::setDefault(QLocale(args.at(idx+1))); } QTranslator translator; translator.load(QLocale(), "countryselection", "_"); app.installTranslator(&translator); MainWindow w; w.show();

return app.exec(); }

[ 7 ] Miscellaneous and Advanced Concepts

The first part of modifications asks the application object for all command line parameters and tries to find -lang in it. It then takes the argument that follows and passes it to QLocale constructor (which creates an object holding country and language information) and sets that as the default locale for the application. Then we modify the call to QTranslator::load() to use the default locale instead of the system locale. If default locale is not set (for example, there is no -lang parameter followed by language identifier), the default locale falls back to system locale effectively giving us the same behavior we had before.

To test this modification, open the Projects pane in Creator, click open Run Settings for the active kit and in the Arguments field enter-lang pl. Next time you run the project, you should see all messages translated to Polish.

What just happened? Each user-visible string is wrapped in a tr() function call. If a translator is installed on the application object, a call to tr() results in calling QTranslator::translate() for each installed translator which performs a lookup in its message catalog. If a match is found, the translation is returned and the search stops. Otherwise a null string is returned and the next translator is tried. If no match is found in any of the catalogs, the original (untranslated) message is used.

QTranslator::translate() is a virtual method thus by subclassing QTranslator and reimplementingtranslate() you can provide a custom translation mechanism for your application.

Translating user-visible content in QML All internationalization functionality we described so far applies also to QML. All the mentioned C++ functions have their equivalents in QML. The following table shows the corresponding mappings:

C++ QML tr() qsTr() translate() qsTranslate() QT_TR_NOOP() QT_TR_NOOP()

All other aspects remain the same—you use the lupdate and lrelease tools for producing catalogs and Qt Linguist for doing the translations. And you still need to install a QTranslator object on the application.

[ 8 ] Chapter 11 The inter-process communication More than often there is a need that one program needs to co-operate with another program running on the same machine. Sometimes one of them is providing services to the other, another time they are exchanging data or maybe one process is providing a monitoring interface that another process can attach to and read some statistics. Qt handles many standard ways of communication between processes thus allowing to talk with programs not only based on Qt. In this chapter, we will take a look at some of the IPC mechanisms commonly used, namely shared memory and local sockets.

The shared memory Usually each process has its own memory space reserved for it by the kernel and the process has exclusive access to each allocated block. The shared memory IPC mechanism works by creating a memory block in the operating system kernel that can be attached to more than one process so that one process can modify some memory area and another process can read the data stored within. It is very important to remember that only this particular block of memory is shared between processes. An implication of this is that it does not make sense to store pointers or any complex structures (such as class instances) in a shared memory block. You should always treat shared memory as an opaque block of bytes—similar to a file on the disk. To create a shared memory block we need to ask the system to create it for us. Qt handles shared memory via the QSharedMemory class that represents a single shared memory block. Before we can create the block, we have to decide what key we are going to use to identify this particular block (as there can be many shared memory blocks in the system) so that other processes can attach to it by using the same key. This is done either by passing the key to the constructor of QSharedMemory or by using the dedicated setKey() call and passing a string containing the key.

Keys used by QSharedMemory differ from the representation used by the platform Qt is running on. To be able to talk with a non-Qt application, you have to use setNativeKey() instead.

Then you can create() a new block (passing the size of the block that is to be created) or attach() to an existing one. Optionally, you can tell QSharedMemory whether you want ReadOnly access to the block or a ReadWrite access. Both these methods return a Boolean value telling us whether the operation was successful or not. To access the shared block you can call data(), which returns a pointer to the shared block (or null if the previous operation had failed). Now you can start using the shared block by reading from it or writing to it. Since more than one process can try to access the block at the same time it is important to protect it from concurrent access. Qt provides a way to do this by using the lock() and unlock() methods.

[ 9 ] Miscellaneous and Advanced Concepts

Once you are done with using the block, call detach() on it to release it from the current process. Once all processes using the block call detach(), the block is destroyed and can no longer be accessed.

As an exercise we will create a stub of a game engine that reports game statistics through shared memory. For that we will create two programs—the engine itself that will create a shared memory block and modify it according to what happens in the engine and a client program that will attach to the block and read it.

Time for action – the game stats monitor – game engine Our game engine will really be more of a mockup rather than a real engine. Create a Qt GUI Application project and get rid of the widget Creator created for you as we will not need it. Now add a new header file to the project and call it gamestats.h. It will contain the definition of a data structure that we are going to expose through shared memory.

Like we mentioned earlier, the shared block is really an opaque sequence of bytes therefore an ideal Qt class to handle it is QByteArray. Let's create a GameStats class that encapsulates a byte array:

class GameStats { private: QByteArray m_data;

Then let's add two constructors that make the byte array operate on first 8 bytes of a pointer. The pointer accepted is a const or non-const void pointer:

public: explicit GameStats(void *ptr) { if(ptr) m_data.setRawData((const char*)ptr, 8); } explicit GameStats(const void *ptr = 0) { if(ptr) m_data.setRawData(static_cast(ptr), 8); } The byte array does not own the pointer. It means that you have to make sure the pointer remains valid as long as the byte array exists and it also means the byte array will not delete the pointer upon its own destruction.

[ 10 ] Chapter 11

Now we will add methods that allow us to modify the underlying data by storing two integer properties—the number of players currently in the game and the number of seconds since the game was started. As the data type for those attributes we are going to use quint32, which is a type guaranteed by Qt to be 32-bits long unsigned int. This makes us certain that the total number of bytes used by those two attributes is 4+4=8:

void setPlayerCount(quint32 cnt) { m_data.replace(0, 4, &cnt, 4); } void setUptime(quint32 secs) { m_data.replace(4, 4, &secs, 4); }

We use the replace() method of QByteArray that accepts the offset from the beginning and number of bytes to replace followed by a pointer to the data that is going to be written into the array and the size of that data. You can see that the player count is written as the first four bytes of the array and the uptime as the next four bytes.

Finally, we also need a way to fetch the data from the array. We can use memcpy() to help us:

quint32 playerCount() const { quint32 result; memcpy(&result, m_data.constData(), 4); return result; } quint32 uptime() const { quint32 result; memcpy(&result, m_data.constData()+4, 4); return result; } };

Now let's go back to main.cpp. First thing to be done is that we need to include the file we just created. Then we can start implementing our "game engine".

What we will really do is that we will provide a slider widget for adjusting the number of players in the game and we will have a timer going that will be counting seconds since the application was started and updating the shared memory.

[ 11 ] Miscellaneous and Advanced Concepts

Right above main(), add code that creates a class derived from QSlider. Make QSharedMemory instance its private member and also declare a GameStats object in the same section. We also declare aQElapsedTimer object that will tell us how long the application has been running:

class GameServer : public QSlider { private: QSharedMemory m_shm; GameStats m_stats; QElapsedTimer m_timer; };

Now add a constructor that will create the shared segment and feed it to the stats object:

GameServer(QWidget *parent = 0) : QSlider(parent) { m_shm.setKey("gameStats"); if(!m_shm.create(8)) return; m_stats = GameStats(m_shm.data()); m_timer.start(); startTimer(1000); };

First we set gameStats as the key for the shared memory segment and try to create 8 bytes of shared memory. If that fails, we do nothing more. Otherwise we initialize the GameStats object and start the measuring time since start of the server. Finally, we call startTimer(1000), which starts an internal timer that will trigger an event every 1,000 milliseconds. The timer will call a protected timerEvent method about every second. Let's implement that event handler and update our shared memory segment there:

void timerEvent(QTimerEvent *) { if(!m_shm.lock()) return; // failed to obtain lock m_stats.setPlayerCount(value()); m_stats.setUptime(m_timer.elapsed()/1000); m_shm.unlock(); }

We are locking the shared memory block, then updating values and releasing the lock.

The engine is ready and can be instantiated in main():

int main(int argc, char *argv[]) { QApplication app(argc, argv); GameServer engine; engine.show(); return app.exec(); }

[ 12 ] Chapter 11 What just happened? We implemented a really simple mechanism for periodically pushing two values to the outside world using shared memory. Now, we need the other end of the inter-process communication system—an application that can read those values and do something meaningful with them.

Time for action – game stats monitor – client application Start by creating a new project and choosing Qt Console Application as its type. Add the gamestats.h file to the project and include it in main.cpp.

This time we won't need an application object so delete the code in main() and start filling it with new code. First let's create a QTextStream instance that outputs text to standard output so that we can use it similar to std::cout:

QTextStream qout(stdout);

Now let's try to attach to a shared memory segment called gameStats:

QSharedMemory shm("gameStats"); if(!shm.attach(QSharedMemory::ReadOnly)) { qout << shm.errorString() << endl; return -1; }

If attaching fails, we output the error message and quit the program. Now let's read the stats:

shm.lock(); GameStats stats(shm.constData()); qout << "Players online:" << stats.playerCount() << endl; qout << "Engine up time:" << stats.uptime() << "seconds" << endl; qout << endl; shm.unlock();

First we lock the shared block so that nobody can modify it behind our back. Then we feed the shared data to the GameStats class and use its methods to output the game statistics to qout. Then we can unlock the segment so that others can use it. What remains is to release the shared block and exit the program reporting success:

shm.detach(); return 0;

To test our monitor run the "game engine" application and after some time execute the newly created monitor tool. Modify the slider value and execute the tool again to see the changed result.

[ 13 ] Miscellaneous and Advanced Concepts What just happened? The client application attaches to an existing shared memory block by passing a key shared with the server. From that moment on the block of memory is visible from both applications. However, it is not safe when one process reads the shared segment and another modifies it at the same time as memory can be modified in the middle of the reading process giving the reader a mix of old and new data. To prevent such situations, any access to the memory has to be serialized. Each read and each write to the block is prepended with obtaining an exclusive lock on the segment. It is important to release the lock as soon as you don't need it as holding the lock for long may result in performance degradation of other processes trying to obtain access to the shared segment.

Local sockets Shared memory is most useful when there is a group (usually more than two) processes that need to use the same data and the data is not either very complex nor very large. But there are other situations where processes might want to exchange a lot of data over a long period of time. An example of such situation is an external game console sending requests to a game engine and receiving some data it needs in response. For such use cases an ideal solution is to use a local socket (implemented in Qt with QLocalServer and QLocalSocket), which is usually a special file in the file system that acts as a pipe between two or more processes where one process streams data into one end of the pipe and another process reads data from the other end. From the developer's perspective local sockets are very similar to network sockets that use protocols such as TCP or UDP (we will learn more about them in Chapter 7, Networking).

A system equivalent of a local socket is a named pipe or a Unix domain socket depending on the operating system. Thus you can use your operating system's calls to communicate with a Qt application that makes use of QLocalSocket.

Local socket communication uses the client-server pattern. One process creates a server socket and listens to incoming connections. Other processes (clients) connect to that server socket and can perform streaming two-way communication.

To use local sockets, you have to enable the QtNetwork module for your project by adding a QT+=network line to the project file.

[ 14 ] Chapter 11

To set up a server you need to use an instance of the QLocalServer class. To start the server you will call the listen() method and pass it a file path that is to be created as your socket. At this point, if someone connects to the socket, a newConnection() signal will be emitted. You can catch it and call nextPendingConnection() to obtain a socket handler for communication with the client.

Handling the client end is also easy—you create an instance of QLocalSocket and call connectToServer(), passing it the file path to the server socket. When the connection is succesfull, the socket will emit a connected() signal.

From now on the two sides behave the same way as both use QLocalSocket for communication. Since the latter is derived from QIODevice, you can use read() and write() to perform operations on the socket. Connection is terminated upon calling close() in which case the socket will emit a disconnected() signal. As local sockets are very similar to TCP sockets, you can refer to Chapter 7, Networking, for a more complete description of socket communication.

Communication in QML QML does not support constructs such as local sockets or shared memory out of the box. If you want to use them you have to provide your own QML wrappers for them. However, QML does have an IPC mechanism in a form of web sockets. It's an HTML standard for instantiating sockets from within a JavaScript environment and using it to connect over TCP to external servers. It has been adapted to work in QML as well.

To use web sockets you need to import the right module in your document:

import QtWebSockets 1.0

Then you can start declaring socket servers:

WebSocketServer { id: socketServer listen: true onClientConnected: { webSocket.onTextMessageReceived.connect(function(message) { console.log("Server received message: ", message) webSocket.send("Server says 'Hello!'") }) } }

[ 15 ] Miscellaneous and Advanced Concepts

The server object has an API similar to QTcpServer. It exposes host and port properties that define where the server socket is created. By default the socket is bound to localhost and the port is chosen automatically. When a client connects to the server, the onClientConnected handler is invoked and passed a socket through which the server communicates with the client. In the preceding example, we connect a function to textMessageReceived signal which prints the message to the console and sends a textual response back to the client.

A client socket can be created by declaring WebSocket instance:

WebSocket { id: socket url: socketServer.url onStatusChanged: if(status == WebSocket.Open) { sendTextMessage("Hello!") } onTextMessageReceived: { console.log("Client received message: ", message) } }

The socket is connected to a remote server defined by theurl property (in this example we query the earlier created socket server for its URL). When the connection is established we use sendTextMessage to transmit data to the server. The response is intercepted in the onTextMessageReceived handler and printed to the console just like before. You can use web sockets to fetch data from remote locations or to trigger actions in a web service. You can also establish a communication channel to a process running on the same machine just like you would when using local sockets.

Equivalent API for C++ is also available through classes called QWebSocket and QWebSocketServer.

Multithreading Nowadays, a more popular approach than multiprocessing is multithreading, which allows having simultaneous execution flows within a single process. Qt provides its own abstraction to threading which covers all the implementation details that are platform dependent, and is especially important for systems not supporting C++11 (which makes threading part of the programming language). Even for that support the concept of threads presented in C++11 using Qt threads (in a form of QThread class) yields some benefits such as the use of and proper event handling.

[ 16 ] Chapter 11

Simple threading The most use of threads in Qt boils down to subclassing QThread and reimplementing its run() method. After calling start() on an instance of such class, a new thread is created and the contents of run() is executed within that thread. After the function returns, the thread ends its life:

class Thread : public QThread { public: Thread(QObject *parent = 0) : QThread(parent) {} void run() { while(true) { qDebug() << "This message prints forever"; } } };

Threading in Qt is governed by the same rules as with every other technology, including that access to a resource shared by more than one thread needs to be synchronized to avoid race conditions. Qt offers a number of mechanisms for thread synchronization, the simplest one being QMutex that implements a classic mutex primitive with lock() and unlock() operations which ensures that only one thread can execute in a critical section. Let's look at manipulating a protected data structure where one thread reads and the other modifies the structure:

struct { QString value; int counter; QMutex mutex; } data;

class Thread : public QThread { public: enum Mode { Reader, Writer } Thread(Mode mode, QObject *parent = 0) : QThread(parent), m_mode(mode){} void run() { switch(m_mode) { case Reader: runReader(); break; case Writer: runWriter(); break; } } private: Mode m_mode; };

[ 17 ] Miscellaneous and Advanced Concepts

Here we define a class that can act as a reader or a writer depending on the parameter passed to the constructor which influences which function is going to be called from the run() method:

void Thread::runWriter() { while(true) { data.mutex.lock(); data.value = QDateTime::currentDateTime().toString(Qt::ISODate); data.counter++; data.mutex.unlock(); } }

Code of the writer is trivial, we have an endless loop that locks the mutex and modifies the data structure based on some criteria. The reader is implemented in a similar way—lock, read, unlock, repeat:

void Thread::runReader() { while(true) { data.mutex.lock(); qDebug() << "Current value:" << data.value; qDebug() << "Current counter:" << data.counter; data.mutex.unlock(); } }

Finally, a simple program to test the code:

int main(int argc, char **argv) { QCoreApplication app(argc, argv); Thread reader(Thread::Reader); Thread writer(Thread::Writer); data.counter = 0; reader.start(); writer.start(); QTimer::singleShot(10000, &app, SLOT(quit())); return app.exec(); }

Here we use QTimer::singleShot to end the program after 10 seconds.

[ 18 ] Chapter 11

Now suppose we want to modify the code to end the program after the counter reaches "1,000". We can do that by using the finished() signal emitted by aQThread object when the thread it represents finishes execution. Connecting that signal to the quit() slot of the application object should do the trick:

QObject::connect(&reader, SIGNAL(finished()), &app, SLOT(quit()));

What remains is to end the reader thread when it detects the counter reached the right value:

void Thread::runReader() { while(true) { data.mutex.lock(); qDebug() << "Current value:" << data.value; qDebug() << "Current counter:" << data.counter; int counterValue = data.counter(); data.mutex.unlock(); if(counterValue >=1000) return; } }

This code works but it is very ugly because we have to make sure we release the mutex before returning from run(), otherwise the mutex will remain permanently locked. Therefore we have to store the value in a temporary variable and check its value after the mutx is released. There are two ways to make the code better—one is to provide a stop condition for the while loop (for example, while(!shouldQuit) { … }), the other is to use something called a mutex locker which takes care of locking and unlocking the mutex for us. It makes use of RAII (Resource Acquisition Is Initialization) design pattern which can be summarized by a short rule that a resource can be acquired when an object is initialized and released when the object is destroyed. This simplifies our reader code to:

void Thread::runReader() { while(true) { QMutexLocker(&data.mutex); qDebug() << "Current value:" << data.value; qDebug() << "Current counter:" << data.counter; if(data.counter() >= 1000) return; } }

QMutexLocker makes sure the mutex gets locked upon creating the locker and released upon leaving the scope of life of the locker.

[ 19 ] Miscellaneous and Advanced Concepts

Signals and slots with threads So far we have been dealing with signals and slot connections that are handled by the same thread. However, the situation is different when the sender and the receiver "lives" in different threads. What does that mean? QObject "lives" in (or formally speaking has thread affinity of) a thread which is responsible for handling the object's events. By default an object has affinity of the thread which created the object. Later on we will learn to change that affinity but for now let's focus on the default case. If a signal is emitted and a slot is connected to that signal it is important to invoke the slot in the context of the thread that owns the receiving object. This is to make sure that the two threads don't try to access the same object at the same time and also to ensure coherency of the receiving object. To accomplish this, Qt delivers cross-thread signals using the event system. Therefore, to execute slots for an object living in a worker thread the thread has to be running an event loop. This is done by calling QThread::exec() which is an equivalent of QCoreApplication::exec()—it makes the thread enter an event loop and handle all incoming events, including cross-thread signal-slot invocations. The loop is exited upon calling QThread::quit().

There is one major pitfall concerning thread affinity—the QThread object itself. The object represents a worker thread but it is not the worker thread itself—since the instance of QThread was created before the thread is started, it means it has a thread affinity with the thread that created the object and not the one that is created upon calling start(). This implies that slots of the object are executed in the context of the original thread and not the worker thread! Only the run() method and functions called directly from within it are executed in a worker thread. Also only objects created from run() have the thread affinity with this worker thread.

The high-level threading Reimplementing QThread::run() is the simplest approach to make some code run in a separate thread but it has a number of drawbacks. The greatest drawback is the problem described in the previous paragraph that the QThread object is only a "handle" to a thread and it does not live in the thread it represents. This makes it difficult to do proper encapsulation. Fortunately, there is a more versatile approach. We can create a bare QThread instance, run its event loop and then change thread affinity of some other object to the worker thread so that it is responsible for processing its events. The latter is done by calling moveToThread() on an object and passing a pointer to an existing QThread instance that is to become the owner of the object. It is important that you can only "push" an object into a thread—the thread itself cannot steal ("pull") an object from another thread. Here is an example code that uses a worker thread to asynchronously scale down images delivered by some virtual imageSource object and sends received thumbnails to another object:

[ 20 ] Chapter 11

class Handler : public QObject { Q_OBJECT public: Handler() : QObject() {} public slots: void processImage(const QImage &img) { QImage result = img.scaled(96, 96); emit ready(result); } signals: void ready(QImage); };

QThread t; Handler *h = new Handler; h->moveToThread(&t); connect(&imageSource, SIGNAL(imageAvailable(QImage)),

h, SLOT(processImage(QImage))); connect(h, SIGNAL(ready(QImage)), &imageDest, SLOT(useImage(QImage))); t.start();

Threading using QThread is good for long-lived situations where objects provide services to other objects upon request. For simple scenarios such as fire-and-forget (that is, you execute some code that does what it is meant to and doesn't return any result) where you simply need to run some function in a separate thread, there is an easier approach. You can tell Qt to run a function in a separate thread using the following code:

#include

void saveMyData(MyData data) { QFile f(data.fileName); f.open(QFile::WriteOnly); f.save(data.serialize()); }

// … MyData data; data.fileName = …; // … QtConcurrent::run(saveMyData, data); // …

[ 21 ] Miscellaneous and Advanced Concepts

This essentially tells Qt to executesaveMyData function in a separate thread using data as the function argument.

To enable QtConcurrent::run you need to enable the QtConcurrent module by adding QT+=concurrent to the project file.

Threading in QML In QML you can execute scripts in a separate thread with the use of WorkerScript element. Its API is very simple—it accepts a URL of a script to execute via the source property. Once the script is started, you can communicate with it using messages. WorkerScript objects have a sendMessage() function that accepts a JavaScript object. The object is transmitted to the worker thread where it can be intercepted by connecting a function to WorkerScript.onMessage:

WorkerScript.onMessage = function(message) { … }

The script can also use sendMessage to transmit data to the main thread where again it can be read by connecting to onMessage and querying the reply property of the received object:

WorkerScript { source: "script.js" onMessage: { console.log(messageObject.reply) } }

Since the script is executed in a thread different than the main QML thread, it cannot access any items or their properties. It cannot even access properties of theWorkerScript object itself or any object exposed to QML from C++.

Qt Multimedia In this section we will have a look at how to play sounds and videos. This is crucial for successfully programing games or can you think of a modern game without music or videos? Normally you have a background music and additionally sound effects when a player jumps, kicks, shoots a gun, or performs similar actions. In high-end games there are also short videos introducing a level and/or telling parts of the game's story.

[ 22 ] Chapter 11

Before we start to "play" with Qt's Multimedia module, keep in mind that you have to enable it. In -based projects add QT += multimedia, if you are using QML import QtMultimedia 5.0. Notice further, that Qt Multimedia uses the media framework of the underlying operating system. This means that depending on the machine your game is running on, specific audio or video codecs may or may not be available.

Sound Instead of simply showing how to play music or sounds, let's write a small program that also illustrates how to record audio.

Playing sound in widget based applications

Time for action – recording an audio To demonstrate how to record and play audio we use this little program called RecordAndPlaySound:

The is—as you can see—very minimalistic: at the top there is a combo box named ui->input. Its purpose is selecting the audio input. Beneath we find two checkable buttons, one for recording audio (ui->record) and one for playing the last recorded audio (ui->play). Since you already know how to build such a simple GUI, we skip this part and directly have a look at the relevant code which is located in the main window's constructor. As always you'll find the sources for this example attached to this book:

RecordAndPlaySound::RecordAndPlaySound(QWidget *parent) : QMainWindow(parent), ui(new Ui::RecordAndPlaySound), m_file(QDir(QCoreApplication::applicationDirPath()) .absoluteFilePath("test.ogg")), m_recorder(new QAudioRecorder(this)), m_player(new QMediaPlayer(this)) { ui->setupUi(this); m_recorder->setOutputLocation(m_file);

[ 23 ] Miscellaneous and Advanced Concepts

const QStringList inputs = m_recorder->audioInputs(); foreach (const QString &input, inputs) { ui->input->addItem(m_recorder->audioInputDescription(input), input); } m_recorder->setAudioInput(ui->input->currentData().toString()); QAudioEncoderSettings settings; settings.setCodec("audio/vorbis"); m_recorder->setEncodingSettings(settings, QVideoEncoderSettings(), "ogg"); connect(m_player, SIGNAL(stateChanged(QMediaPlayer::State)), this, SLOT(playbackStateChanged(QMediaPlayer::State))); }

Now start the program, select the audio input, and check the record button. Once you say your test phrase, uncheck the record button to stop the recording. Now hit the play button. In theory you should then hear what you last have recorded...

What just happened In the initializer list we initialize some member variables: m_file of type QString holds the file path which will be used to store the recorded audio. m_recorder of type QAudioRecorder is responsible for recording and m_player of type QMediaPlayer for playing the audio. In this example m_file is set to a file named test.ogg which will be placed right beside the program's executable. In a real game you would have to determine the filename in a more sophisticated way.

In the constructor's body, after setting up the UI, we define wherem_recorder should save the recorded audio. This is done by passing the previously defined m_file to QMediaRec order::setOutputLocation(). Actually setOutputLocation() expects a QUrl, but thanks to implicit type conversion we can also pass a QString.

Since setOutputLocation() takes QUrl it is not restricted to local files. You can also use network files. Even if we did not check it in the example,setOutputLocation() returns false if the passed location can't be used to store media recording.

[ 24 ] Chapter 11

Next, we want to provide the ability to choose the audio input. For devices that have several audio inputs this is a must. By using QAudioRecorder::audioInputs() we get a list containing all inputs that are available on the device. Unfortunately the returned identifiers are not really readable, especially not for most users of your game. Or do you expect your customer to know what for example, alsa:front:CARD=Creative,DEV=0 means? People probably will run away screaming if they saw this kind of text, so we need a better way of dealing with the audio inputs. Thanks to QAudioRecorder::audioInputDescri ption(), by taking the identifier as an argument, we can convert the cryptic strings into a better readable format. This way we get the slightly nicer string HDA Creative, CA0110-IBG Analog Front speakers. So we loop through the list of audio inputs, generate the readable description and put them to the combo box. Note that we also pass the original audio input identifier to the items as the so called user data. Thus we are able to provide the following slot:

void RecordAndPlaySound::on_input_currentIndexChanged(int index) { m_recorder->setAudioInput(ui->input->itemData(index).toString()); }

Every time the current index of the checkbox changes, we fetch the user data, transform it to QString and pass it to QAudioRecorder::setAudioInput(), so that m_recorder will use this audio input for recording sounds. To start the program in a consistent state, we set the recorder's audio input to the user value of the combo box's currently selected item right after we have left the loop for setting up the box. If you do not define an audio input, Qt will take the default one.

Next we define the audio's encoding which is handled entirely by a class called QAudioEncoderSettings. Remember, however, that QAudioEncoderSettings—or better it's base class QMediaRecorder—can only handle encodings that are supported by the device's framework. To gather the available codecs and options, QMediaRecorder offers supportedAudioCodecs(), supportedAudioSampleRates(), and supportedContainers(). In our example we canonically dictate to use the free audio format Ogg Vorbis:

QAudioEncoderSettings settings; settings.setCodec("audio/vorbis"); m_recorder->setEncodingSettings(settings, QVideoEncoderSettings(), "ogg");

[ 25 ] Miscellaneous and Advanced Concepts

Therefore, after creating an object of QAudioEncoderSettings, we set the codec with setCodec() to audio/vorbis. For all other available options, QAudioEncoderSettings provides, we are fine with their default values.

If you like to change other options these self-explanatory functions would be of interest: setBitRate(), setChannelCount(), setEncodingMode(), setQuality(), and setSampleRate(). If you like to add encoder-specific options, which are not covered by Qt Multimedia's API, use setEncodingOption() and setEncodingOptions().

Last we need to set the chosen codec setting to m_recorder by using QMediaRecorder:: setEndocingSettings(). As first argument the audio setting is passed, as second a video setting—yes with Qt Multimedia you also can record videos—and as third the container format. Here we choose Ogg. At the end of the constructor we establish a connection which informs us about a state change of m_player. For now, do not worry about that, we will get to this in detail a bit later. Let's rather have a look how the actual recording is started and stopped:

void RecordAndPlaySound::on_record_toggled(bool checked) { if (checked) { m_recorder->record(); } else { m_recorder->stop(); } }

This implementation is pretty simple: If the button ui->record gets checked we start the recording by calling record() and as soon as the button gets unchecked we stop the recording with stop(). There is nothing more to do since we already set up the recorder in the constructor.

Have a go hero – making the audio settings fail save Our example will fail terribly if Ogg Vorbis is not supported. So go ahead and make it fail save! To do so, you have to check the available codecs with supportedAudioCodecs() and then fall back to another (supported) codec if Ogg Vorbis is not available.

[ 26 ] Chapter 11

Time for action – playing sound Now let's complete our little sample program and have a look at how to play back the recorded file:

void RecordAndPlaySound::on_play_toggled(bool checked) { if (checked) { m_player->setMedia(QUrl::fromLocalFile(m_file)); m_player->play(); } else { m_player->stop(); } }

The overall logic for playing sound is the same as it is for recording: when the button ui- >play gets checked, we call play() to start the playback. If the button gets unchecked, we stop the music with stop(). There is of course also a function named pause() to pause the playback, but for the sake of easiness we haven't implemented it here. Right before we are calling play(), we specify which file should be played. Therefore we call setMedia() and pass the local variable m_file, holding the file path to the recorded file. You do not have to call setMedia() each time before calling play(). Defining the media once is enough. At this point, I owe you an explanation for the connection statement in the constructor. In this statement the music player's signal stateChanged() was connected to this slot:

void RecordAndPlaySound::playbackStateChanged(QMediaPlayer::State state) { if (state == QMediaPlayer::StoppedState) ui->play->setChecked(false); }

The whole purpose of this slot is to uncheck the button ui->play when the music stops playing. So you have the chance to start the playback again. Hence we uncheck the button when the player enters StoppedState. This state signifies that currently no music is being played and that calling play() will play the media from the start. Apart from this state, QMediaPlayer can be in two more states: QMediaPlayer::PlayingState and QMediaPlayer::PausedState. The former indicates that the player is currently playing, the later that it was stopped but resume to play at the position where it was paused.

[ 27 ] Miscellaneous and Advanced Concepts

To sum up music playing with Qt Multimedia, it's a three liner:

QMediaPlayer *player = new QMediaPlayer; player->setMedia(QUrl::fromLocalFile("/path/to/file.wav")); player->play();

Have a go hero – making a voice chat In the chapter about networking you saw how to make a simple text-based chat. With the knowledge of recording and playing sounds, let's extend that example by sending small audio messages. The steps you need to do are: record an audio message, read the content of the recorded file, send it, receive it, save it to a temporary file, and play it back. There you go, you now have a simple voice chat.

Playing a sound in QML Unfortunately there is currently no built-in support for recording sound with QML. Playing sound, however, is straightforward and if you have studied the C++ part, there will be no surprises:

import QtQuick 2.0 import QtMultimedia 5.0 Rectangle { width: 360 height: 360 Text { id: button text: "Play"; anchors.centerIn: parent } Audio { id: music source: "/path/to/file.mp3" } MouseArea { anchors.fill: parent onPressed: { music.play() } } }

[ 28 ] Chapter 11 What just happened Well, let's skip the basic QML code for creating a button which is labeled Play and concentrate on the highlighted parts. First we have the type Audio and we give that object an ID that we can refer later, and with source we define the file that should be played. Last we start the playback by calling play() on the Audio object referenced by the identifier music when the rectangle gets clicked. It's like the three liner of C++: creating Audio, defining the source, and playing it. The right codec will be chosen automatically if the media framework supports it.

If you like to implement a play/stop button just alteronPressed to:

onPressed: { if (music.playbackState == Audio.StoppedState) { music.play() button.text = "Stop" } else { music.stop() button.text = "Play" } }

We simply have inserted a check of audio's playbackState which can be StoppedState, PausedState, and PlayingState. The meaning is the same as of QMediaPlayer::State. If the player is currently in the stopped state, we start the music and change the text of the button to "stop". Otherwise, we stop the music and set the button's text "play".

Alternatively to audio we also could have used the more generic media player.

Playlists and loops If you have a background music theme for your game, it surely does not consist of only one file. More likely you have multiple tracks that you want to play in a loop. Or maybe you really only have one file but need it to be played in a loop. This can easily be achieved with QMediaPlaylist. First you have to create an instance of this class:

QMediaPlaylist *playlist = new QMediaPlaylist;

Then you need to add music or sound tracks to the list which is done with addMedia(). As a parameter you can either pass a single QMediaContent or QList of QMediaContent. Since QMediaContent provides a default constructor taking QUrl, we can write:

playlist->addMedia(QUrl::fromLocalFile("/path/to/firstFile.mp3")); playlist->addMedia(QUrl::fromLocalFile("/path/to/secondFile.mp3"));

[ 29 ] Miscellaneous and Advanced Concepts

With clear(), on the other hand, one could remove all items from the list, but we do not want to do this right now. We would rather like to define how the sounds should be played. This can be done with setPlaybackMode(). As arguments the following options are available:

‹‹ Looping endlessly through the list can be done with: playlist->setPlaybackMode(QMediaPlaylist::Loop);

‹‹ Passing the playlist to the player and starting it can be done with:

QMediaPlayer *player = new QMediaPlayer; player->setPlaylist(playlist); player->play();

Be aware, that by calling setPlaylist() the parent ship of playlist is not passed to player, so we do need to take care of freeing the memory our self. If we use the player as the parent of the list—by passing it as an argument to the constructor, however, the playlist gets automatically deleted as soon as the player is deleted.

With save() and load(), QMediaPlaylist provides the ability to save and load playlists. At the end you have to swallow the bitter pill: QML does not support playlists. You have to manage the list on your own and start the next sound as soon as the player enters the stopped state.

Playing sound effects QMediaPlayer can surely be used to play sound effects. For sound effects, however, it is better to use QSoundEffect—if you are using uncompressed audio files like WAV files— as this class is especially designed to play low latency sound effects. It's usage is similar to QMediaPlayer. Let's have a look at this example:

QSoundEffect *effect = new QSoundEffect; effect->setSource(QUrl::fromLocalFile("soundeffect.wav")); effect->play();

First we create an instance of QSoundEffect, then with setSource() we set the file that should be played and finally we start the effect withplay() . If you want to play the effect multiple time use setLoopCount() to define how often it should be played. As a special parameter QSoundEffect::Infinite can be passed resulting in a repeatedly playback of the effect. Since QSoundEffect inherits QObject, it can be conveniently used within signal and slot connections:

connect(someObject, SIGNAL(someSignal()), effect, SLOT(play()));

[ 30 ] Chapter 11

With this statement every timesomeObject emits someSignal(), our effect plays the sound file soundeffect.wav. This approach is very light-weighted and should be preferred over QMediaPlayer for simple sound effects.

Video The good thing about playing videos is that it is almost the same as playing sounds. So you do not have to make yourself familiar with a new syntax.

Playing videos in widget-based applications Let's have a look at the following three lines of code:

QMediaPlayer *player = new QMediaPlayer; player->setMedia(QUrl::fromLocalFile("/path/to/movie.ogg")); player->play();

Do you recognize these lines? They are equal to those I have shown you for playing sounds and in fact, if you run the code, you will hear the sound of the video but you won't see anything. You first have to tell QMediaPlayer where to show the video. This is where a new module comes into play: Qt Multimedia Widgets. To enable Qt Multimedia Widgets add QT += multimediawidgets to the project file. Then we can use QVideoWidget—which behaves like a normal QWidget—as a canvas for the video:

QVideoWidget *videoWidget = new QVideoWidget; player->setVideoOutput(videoWidget);

After we created an instance of QVideoWidget we pass it to the player by calling it's function setVideoOutput(). This advises the player to use videoWidget as a canvas. Note that you can only set one video output to a player. Displaying a movie on different widgets with only one player is not possible.

QVideoWidget also provides an easy way to alter the brightness, contrast, hue, and saturation of the video. You may guess the function names: setBrightness(), setContrast(), setHue(), and setSaturation(). If your game is graphics-view-based, there is also a straightforward solution:

QGraphicsVideoItem *item = new QGraphicsVideoItem; player->setVideoOutput(item);

QGraphicsVideoItem inherits QGraphicsObject, which inherits QGraphicsItem, so that you can use QGraphicsVideoItem like any other item in Graphics View. And as we did with QVideoWidget, we set the instance of QGraphicsVideoItem as the player's video output. You do not have to do anything else.

[ 31 ] Miscellaneous and Advanced Concepts

You may ask yourself what about playing a video in a loop or multiple videos one after the other. Guess what! Of course you can use QMediaPlaylist also for videos like you have done for sounds!

Playing videos in QML The only real type you have to know for playing video in QML is Video:

Video { id: video source: "/path/to/video.ogg" }

With source you define the video file and with the definition of an ID you can start the video by calling video.play(). Video inherits the type Item so that it behaves like any other QML item. There is nothing more to say.

Video, however, is a convenience type which behaves like the combination of MediaPlayer and VideoOutput:

MediaPlayer { id: mediaPlayer source: "/path/to/video.ogg" } VideoOutput { source: mediaPlayer }

MediaPlayer defines the file to play and VideoOutput is the canvas for displaying the video—the same like QMediaPlayer and QVideoWidget in the C++ world. With source of VideoOutput you define which player's video should be shown.

Mobile technologies Qt is reaching out to more and more platforms that are used nowadays. This includes a number of popular mobile platforms. Mobile devices are usually equipped with additional hardware, less often seen on desktop systems such as sensors, GPS receivers, or NFC transmitters. In this section we will show you how to handle those technologies in Qt so that you can use them in your games.

[ 32 ] Chapter 11 Qt Sensors Mobile devices today offer a wide range of sensors. By using them, you can make your game richer in content as well as providing a noticeably better user experience. Even though mobile phones and tablets are equipped with various sensors, this unfortunately does not mean that you can use all of them in a Qt application. Qt only supports a specific range of sensors which differ from one operating system to the other. You also have to take into account that support for Android and iOS was first introduced in Qt 5.2. So the sensor feature for these operation systems is far from being mature. To see what sensors are supported on your platform, have a look at the documentation for "Compatibility Map". There you will find a table listing all available sensors for the different platforms.

To determine at runtime which sensors are available, you can call the static function QSensor::sensorTypes(). It returns a list of QByteArray holding the class name of all available sensor types.

To get access to the sensors, however, you have to activate the Qt Sensors module. In order to do this you have to add the line Qt += sensors in the project file. Afterward you can access the device's sensors through the provided C++ classes as well as through the corresponding QML types.

An example of using a tilt sensor For a first approach let's try to use the tilt sensor. It delivers information about the device's angle of tilt along the x and y axis. All sensors, by the way, do use a right-hand cartesian co- ordinate system as the following image demonstrates:

[ 33 ] Miscellaneous and Advanced Concepts

Time for action – reading the device's angle of tilt This will be a pretty small example. We are going to read the angles of tilt and simply display their values on two labels called xrotation and yrotation. The code of this example can be found under TiltSensor attached to this book. If you try the example the graphical result, admittedly, is not really spectacular but just think of what you could do with that information:

What just happened? So how do we get those angles? In the constructor of our base class we initialize a local member variable m_sensor which is a pointer to an instance of QTiltSensor:

m_sensor = new QTiltSensor(this); connect(m_sensor, SIGNAL(readingChanged()), this, SLOT(checkReading())); m_sensor->start();

Next we connect the sensor's signal QSensor::readingChanged() to the class' slot checkReading() and finally start the sensor by calling start(). This will connect QTiltSensor to a suitable backend at the device and start the delivery of new data of the sensor. Every time the sensor receives new data the signal readingChanged() will be emitted and thus the slot checkReading() will be called:

void TiltSensor::checkReading() { if (QTiltReading *reading = m_sensor->reading()) { ui->xrotation->setText(QString::number( static_cast(reading->xRotation()))); ui->yrotation->setText(QString::number( static_cast(reading->yRotation()))); } }

In this slot we get the readings of the sensor through reading(), which returns a pointer of the type QTiltReading. Since it could be null, we have to check for its validity. QTiltReading then offers the two functions xRotation() and yRotation() to get the actual angles of tilt around the x and the y axis in degrees. The returned value is qreal in both cases. Since we do not care if an angle is 1.63523 or 1.63524 we cast it to an integer and set this value to the labels. That's all we need to do; it's really that easy to get sensor data with Qt.

[ 34 ] Chapter 11

A word of warning regarding readingChanged(): due to the sensor's sensitivity and accuracy the reading will be performed very often. We are literally talking about hundreds of times per second! So the slot to which you connect this signal to better be really fast. On a more serious note, though, you do not need this accuracy for a game and so you should try to decrease the frequency of updates respectively to the frequency of how often you read the sensor's data. A simple—and most effective—solution is to not use readingChanged() at all. Instead you could use a timer and periodically check the sensor's data. This way you have total control over the frequency of readings of the sensor's data. A better, more sophisticated option is to tell the sensor to only inform you when new data is available. This is done by calling QSensor::setSkipDuplicates() with true as an argument. Now both exactly equal values as well as very similar values are skipped so that the signal is triggered less often.

Let's apply this knowledge to our example by changing the constructor as follow:

m_sensor = new QTiltSensor(this); if (m_sensor->connectToBackend()) { if (m_sensor->isFeatureSupported(QSensor::SkipDuplicates)) { m_sensor->setSkipDuplicates(true); connect(m_sensor, SIGNAL(readingChanged()), this, SLOT(checkReading())); } else { QTimer *timer = new QTimer(this); timer->start(1000); connect(timer, SIGNAL(timeout()), this, SLOT(checkReading())); } m_sensor->start(); }

We still initiate the local variable m_sensor but then call connectToBackend(), which tries to connect the tilt sensor to a suitable backend at the device. If no backend could be found, this function will return false and in such a case we will not proceed since the sensor is simply not available. Next, we check if the sensor is capable of skipping duplicate values. This is done by calling isFeatureSupported() with QSensor::SkipDuplicates as an argument. Note that isFeatureSupported() only delivers valid results if the sensor is already connected to a suitable backend. That's the reason why we called connectToBackend() first. Other features that can be tested for all types of sensors are QSensor::Buffering and QSensor::AlwaysOn. The former indicates if a sensor supports buffering so that it is possible to collect an amount of samples first before delivering them to the application at one time. The latter indicates if it is possible to keep a sensor active even if the screen is turned off. Normally, all sensors get suspended when the screen of a device is turned off. Beside these three keys which are available for all sensors, there are a couple of further keys only available for certain sensors. For example, orientable sensors can provide the functionality to change the axes' orientation based on the device's orientation. This feature could be checked with QSensor::AxesOrientation.

[ 35 ] Miscellaneous and Advanced Concepts

Back to the example: if skipping duplicates is supported on our device I advise to do so via setSkipDuplicates(). This is because in our example we are not interested in the precise value of the angle as we cast it from a qreal to an integer anyway nor do we need to get notified that the angle has not changed at all—the label wouldn't change in such a case. Next we connect the readingChanged() signal to our slot checkReading() as we have done before. Last, the sensor is started by calling start(). As a fall back, if skipping duplicates is not supported, we create QTimer based timer and start it with a timeout interval of one second. It's timeout signal is then likewise connected to the checkReading() slot. Everything else stays the same.

Have a go hero – using angles of tilt in your game The information about a device's tilt can be used perfectly to move a player in a game. So, for example, you can try to port the game with Benjamin from Chapter 6, Graphics View to a mobile device where you use the angle of tilt around the y axis to move the elephant and a change in the rotation around the x axis ti make Benjamin jump. Alternatively just create a scene with a single item on it and move it according to the angles all over the screen.

QSensor, QSensorReading, and QSensorFilter Like QTiltSensor there are a lot of other classes you can use to interact with sensors. Have a look at this impressive list:

Sensor class Description QAccelerometer Reports the device's linear acceleration along the x, y, and z axes. QAltimeter Reports the altitude in meters relative to mean sea level. QAmbientLightSensor Reports the intensity of the ambient light. QAmbientTemperatureSensor Reports the temperature in degree Celsius of the current device's ambient. QCompass Reports the azimuth of the device's top as degrees from magnetic north. QGyroscope Reports the device's movement around its axes in degrees per second. QHolsterSensor Reports if the device is holstered in a specific pocket. QIRProximitySensor Reports the reflectance of the outgoing infrared light. The range is from 0—zero reflection, to 1—total reflection. QLightSensor Reports the intensity of light in lux. QMagnetometer Reports the device's magnetic flux density along its axes.

[ 36 ] Chapter 11

Sensor class Description QOrientationSensor Reports the orientation of the device. QPressureSensor Reports the atmospheric pressure in Pascals. QProximitySensor Reports if an object is close to the device. Which distance is considered "close" depends on the device. QRotationSensor Reports the three angles that define the orientation of the device in a three-dimensional space. QTapSensor Reports if a device was tapped. QTiltSensor Reports the angle of tilt in degrees along the device's axes.

All these classes are convenience wrappers around QSensor and so they all inherit QSensor. Thus you can use them the same way we used the tilt sensor. After setting the sensor up and start it, you can get the actual values of a sensor by calling reading(). This function will return a pointer to an instance of QSensorReading. The object to which is being pointed to is a volatile cache holding only the most recent sensor data. So you have to use its values immediately or you have to store them somewhere if you want to use them later. Like QSensor the class QSensorReading is pretty generic. It only holds the time stamp of the reading and a list of QVariant representing the readings' data. Normally, you do not use this class directly but rather use an appropriate subclass. So, just like in the example, calling QTiltSensor::reading() returns a pointer of type QTiltReading which provides suitable functions to access the angle of tilt around the x (xRotation()) and y (yRotation()) axis. This way, you do not have to find the right values inside the list of QVariant of QSensorReading. This applies to all classes mentioned in the preceding table likewise: QAmbientLightSensor::reading() returns a pointer of type QAmbientLightReading with its convenience function lightLevel() and so on.

Besides QSensor and QSensorReading, there is a third important class named QSensorFilter—as well as the convenience abstract classes QTiltFilter, QAmbientLightFilter and so on. These classes provide an efficient callback facility for asynchronous notifications of sensor changes. If a filter is set to a sensor through addFilter(), the sensor calls the function QSensorFilter::filter() before emitting the readingChanged() signal. As an argument a pointer to the actual reading is passed to filter(). If filter() returns true, the readingChanged() signal is emitted. Otherwise it is not.

[ 37 ] Miscellaneous and Advanced Concepts

Time for action – filtering QTiltSensor As an exercise we alter the initial example so that it only shows new data if the angles of tilt around the x axis are between 5 and 10. Therefor we create a new filter called MyTiltFilter:

class MyTiltFilter : public QTiltFilter { public: bool filter(QTiltReading *reading) { const qreal xrot = reading->xRotation(); return (xrot >= 5.0 && xrot <= 10.0); } };

What just happened? We choose QTiltFilter as a base class because then we get a pointer of the type QTiltReading in QTiltFilter is only pure virtual function filter() instead of a generic QSensorReading pointer. Inside the function we store the rotation around the x axis in a local variable. Then we test if it is greater or equal 5.0 as well as if it is less or equal 10.0. The result of this comparison is finally returned. To activate the filter we only have to add it to our instance of QTiltSensor. This is achieved by creating a new member variable called m_filter which is initialized in the constructor:

m_sensor = new QTiltSensor(this); m_filter = new MyTiltFilter; m_sensor->addFilter(m_filter);

After its creation we assign it to the sensor via addFilter(). Pay attention that the sensor does not take the ownership of the filter. It is our responsibility to delete the filter in the destructor of our class TiltSensor. That ownership remains unassigned is perfectly fine since it gives you the opportunity to use a single filter for multiple sensors. A sensor on the other hand can also have multiple filters. Thus you can add additional filters if needed. To remove a filter you have to call removeFilter() with a pointer to the filter you want to remove as an argument.

[ 38 ] Chapter 11

Have a go hero – changing the reader's value With the filter discussed above no change of the rotation around the y axis is delivered if the rotation around the x axis in not in the range between 5 and 10. So a better solution would be to set the value of the angle of tilt around the x axis to 0 if it is not in range and do not entirely filter the reading out. This can be easily achieved since you can freely use the passed pointer inside the filter function. So if the rotation around the x axis is less than 5 or greater than 10 call setXRotation(0) to set its value to zero. Then returns true. Try this on your own. You can also try to create a second filter that manipulates the value of the rotation around the y axis. Even if this could be done in one single filter does it in two separate filters for exercise reasons.

QtSensorGesture Besides the low level access to sensors via QSensor, Qt also provides the possibility to recognize sensor gestures. Right out of the box Qt provides the following recognizers to detect the most common gestures:

ID Description QtSensors.cover A device with its face up is covered for one second. QtSensors.doubletap A device is being double tapped. QtSensors.hover Similar to cover, but the object hovering over the device is about 4 cm above the device. QtSensors.pickup A face-up device is picked up in a viewing position. QtSensors.pickup A device is shaken in a certain direction. QtSensors.slam A device is held in a top up position and then quickly swung with a downward motion. QtSensors.turnover A device is turned face down and places on a table or similar. QtSensors.twist A face up held device is twisted left or right. QtSensors.whip A device is moved down and immediately back up.

To detect a gesture these recognizers interpret the readings from the Accelerometer, the DoubleTap, the IR Proximity, the Orientation and/or the Proximity sensor. This means you can only get one of the mentioned gestures if the sensors which are needed by the corresponding recognizer are supported by the device. In order to detect a hover gesture for example the hover recognizer needs the IR Proximity sensor to be supported.

[ 39 ] Miscellaneous and Advanced Concepts

Time for action – detecting a sensor gesture Now let's see how we can detect a pickup gesture. To do this we already know that we have to use the recognizer with the ID QtSensors.pickup that detects pickup gestures. So first we check if it is available:

QSensorGestureManager manager; QStringList recognizers = manager.gestureIds(); bool pickupExists = recognizers.contains("QtSensors.pickup");

First we create a QSensorGestureManager object which manages all available recognizers. Its function gestureIds() returns a list that contains all IDs of the recognizers. Then we check if this list contains the ID that we want: QtSensors.pickup. Once we know it is there we then can create a QSensorGesture that uses the pickup recognizer:

QStringList ids; ids.append("QtSensors.pickup"); QSensorGesture *gesture = new QSensorGesture(ids, this); connect(gesture, SIGNAL(detected(QString)), this, SLOT(gestureDetected(QString))); gesture->startDetection();

What just happened? Next we create QStringList containing the pickup recognizer's ID. This list is then passed as a first argument to the constructor of QSensorGesture. With this class we can start the recognition by calling startDetection() or stop it by calling stopDetection(). Whether the detection is currently turned on can be checked via isActive().

Instead of checking the existence of a recognizer upfront we could just have used QSensorGesture. This class too does provide this information. You can call validIds() to get the identifiers of the recognizers that are used by the actual object/instance of QSensorGesture or you can use invalidIds() to receive a list of recognizers that could not be found. As you may have guessed because of our decision to use a list in order to define the recognizer, you can also pass multiple recognizers that should be used by QSensorGesture. If a gesture was recognized QSensorGesture emits a signal called detected() which transfers the name of the detected gesture as an argument. In our case it would be "pickup". In the example this signal was connected to a fictional slot called gestureDetected() where we have the possibility to react to the gesture.

[ 40 ] Chapter 11

Additionally the recognizers also provide specialized signals which are available at runtime. In our case we also could have used the signal pickup(). To get the information which signals are defined, call QSensorGesture::gestureSignals(). It will return a string list of all available signals.

Time for action – creating a own sensor gesture recognizer As described earlier, the QSensorGesture API is plugin based and allows us to add custom recognizers. So let's check if a device is shaken around the zero degrees angle around the x axis. To do this we have to subclass the abstract class QSensorGestureRecognizer and call the new class ShakeZeroRecognizer. The constructor and destructor of this class are empty expect that the private member variable m_active is set to false. m_active stores internally whether the recognizer is active or not. The first two public, pure virtual functions we have to implement are id() and isActive():

QString id() const { return QString("MySensors.shakeZero"); }

bool isActive() { return m_active; } id() has to return the identifier for the recognizer and thus we call it MySensors. shakeZero. Here you can be creative but make sure that the identifier is unique. The isActive() function should return true if the recognizer is active,false otherwise. Here we return the value of the member variable m_active.

Next, we have to implement the three protected functions create(), start(), and stop():

void create() { m_sensor = new QTiltSensor(this); m_sensor->setSkipDuplicates(true); connect(m_sensor, SIGNAL(readingChanged()), this, SLOT(checkReading())); }

bool start() {

[ 41 ] Miscellaneous and Advanced Concepts

m_active = m_sensor->start(); return m_active; }

bool stop() { m_sensor->stop(); m_active = false; return m_active; }

What just happened? The constructor of QSensorGesture will call create() to create the recognizer's backend. Thus we initiate a tilt sensor that we need to detect the device's angle of tilt. To be able to access this sensor we store a pointer to it in the private member m_sensor. Then we tell the sensor to skip duplicates and connect its readingChanged() signal to a custom slot. You might remember this procedure from the first example in this chapter. For sake of simplicity it is supposed that the sensor supports the feature of skipping duplicates. Nevertheless you might want to check this with isFeatureSupported() in real code. start() and stop() are called by QSensorGesture::startDetection() respectively QSensorGesture::stopDetection(). Thus we start or stop the sensor and accordingly alter the private member m_active so that isActive() will return the right state. What is missing is the actual recognition of the gesture. This is done in the custom checkReading() slot:

void checkReading() { QTiltReading *reading = m_sensor->reading(); if (!reading) return; const int x = static_cast(reading->xRotation());

First we get the sensors reading, check if the pointer is valid and then get the actual angle of tilt around the x axis as an integer. For the next instructions you have to know that there is another private member called m_reading of type QList>. It holds the recent information from the sensor as pairs of the angle and the timestamp of the reading:

if (m_readings.isEmpty()) { m_readings << qMakePair(x, reading->timestamp());

[ 42 ] Chapter 11

return; } else { QPair lastReading = m_readings.last(); if ((lastReading.first < 0 && x >= 0) || (lastReading.first >= 0 && x < 0)) { m_readings << qMakePair(x, reading->timestamp()); } else { return; } }

If m_readings is empty we add a new pair containing the actual angle and the timestamp of the reading. If there are previous values we take the one that was inserted last and check if the device has crossed the "magical" line of zero degrees. This is the case if the previous angle is less than 0 where the actual is not or when the previous angle is greater or equal 0 and the actual angle is less than 0. If it passed the line, we add a new pair to m_reading. If the device did not cross the line we do not have to investigate further if the conditions for a shakeZero gesture are met and thus we exit the slot:

if (m_readings.count() == 4) { if (qAbs(m_readings.last().second – m_readings.first().second) < 2000000) { emit detected("shakeZero"); emit shakeZero(); m_readings.clear(); } else { m_readings.removeFirst(); } } }

Now it is time to check if the requirements for the gesture are fulfilled. Therefore we define that m_readings must have four pairs. This means the device has passed the x axis three times at zero degrees. If this condition is met we further check if the three passes happened within 2 seconds. m_readings.last() gives us the latest inserted pair and with second we query its timestamp. The timestamp of a reading is the time in microseconds that has passed since a fixed point—which does not necessarily have to be January 1, 1970. It's a fixed time defined by the sensor. Anyway, we do not have to bother about the actual time because we only want to know the difference between the last pair and the first pair. This is done by the differentiation in the if condition.

[ 43 ] Miscellaneous and Advanced Concepts

Since some platforms do not deliver timestamps correctly, it is possible that the timestamp jumps backwards. If the four readings occurred within 2 seconds (= 2000000 microseconds) we emit the generic QSensorGesture::detected() signal with the gesture's ID shakeZero. Additionally we also emit a custom signal called shakeZero(). All we have to do to make the signal work was to simply declare it. QSensorGesture automatically interprets this and make the signal available at runtime. Last we clearm_readings since the stored readings resulted in a shakeZero gesture. If the four readings didn't occurred within 2 seconds, the oldest reading is removed. This way the next crossing could trigger the gesture.

To actually use our new gesture we have to register it:

QSensorGestureManager manager; manager.registerSensorGestureRecognizer(new ShakeZeroRecognizer); QStringList ids; ids.append("MySensors.shakeZero"); QSensorGesture *gesture = new QSensorGesture(ids, this); connect(gesture, SIGNAL(shakeZero()), this, SLOT(shakeZero())); gesture->startDetection();

We create a QSensorGestureManager object and call registerSensorGestureRecognizer() with an instance of our recognizer in order to register the gesture. Since the manager retains the ownership we do not have to take care of that. Once this is done, we can use our recognizer just like any other one. Also the custom signal shakeZero() works like a charm.

Have a go hero – creating your own gestures Now, with your knowledge about sensors and sensor gestures you can design recognition for all kinds of new gestures. For example, you can detect if a device is moved on a circuit or if it is moved along a rectangular shape. With these new gestures you can individualize your game and demand a maximum of (physical) user interaction. Have a go and design new gestures using more than just one sensor inside the recognizer.

Additional options for mobile devices Beside sensors, mobile devices such as mobile phones and tables offer huge variety of additionally options to enrich your game. Unfortunately, we can't discuss them all here in detail but I would like at least to mention them. The documentation, however, is pretty good so after going through this book your knowledge of Qt should be sufficient to let you learn more on these topics by yourself.

[ 44 ] Chapter 11 Qt Positioning With the help of the Qt Positioning API you can determine the position of the device. To determine the location, multiple sources can be used such as GPS, Wi-Fi or a text file. The retrieved geographic coordinates can be used to show the device's location on a map, log the distance a device covered—for example, to recognize the shape of specific path—or determine the speed and direction. All of this information can easily be used and integrated in a game.

Time for action – displaying coordinates So let's briefly see what the basic work for the Qt Positioning API flow is:

QGeoSatelliteInfoSource *source = QGeoSatelliteInfoSource::createDefaultSource(this); if (source) { connect(source, SIGNAL(positionUpdated(QGeoPositionInfo)), this, SLOT(positionUpdated(QGeoPositionInfo))); source->startUpdates(); }

What just happened? First we try to get a default position source by calling the static function QGeoSatelliteIn foSource::createDefaultSource(). The passed argument becomes the parent of the returned instance of type QGeoSatelliteInfoSource. If you rather want to use a specific source, you have to additionally pass its identifier. A list of all available sources is returned by the static function QGeoPositionInfoSource::availableSources(). If a position source is available, you would next connect its positionUpdated() signal to a custom slot and start the tracking by startUpdates(). With setUpdateInterval() you can specify the interval in milliseconds between each update. If you like to stop the updates, call stopUpdates().

The object of QGeoPositionInfo which is passed by the positionUpdated() signal holds all relevant information about the position. With timestamp() you inquire when the information were produced and with attribute() you can query the direction, the ground speed, the vertical speed, the magnetic variation, as well as the horizontal and vertical accuracy of the provided latitude-longitude and altitude values. The latitude, the longitude, and the altitude are hold in a QGeoCoordinate object which can be accessed by coordinate(). Beside the obligatory latitude(), longitude(), and altitude() functions to get the co-ordinates, this class also provides the possibility to calculate the distance to another co-ordinate by passing it to distanceTo() or to display the current location as a string with toString().

[ 45 ] Miscellaneous and Advanced Concepts

With the optional argument of toString() you can define the format of the string produced; to provide two examples, QGeoCoordinate::Degrees would give you the coordinates in decimal degrees and QGeoCoordinate::DegreesMinutesSecondsWithH emisphere would give you the coordinates in degrees-minutes-seconds as well as "N", "S", "E", or "W" to indicate the hemispheres of the co-ordinates.

To use the Qt Positioning API you have to add Qt += positioning to your project file. Of course, there are also QML bindings available to use this API with Qt Quick.

Have a go hero – monitoring if the device is in a specific area With QGeoAreaMonitorSource, QGeoAreaMonitorInfo, and QGeoShape, Qt offers the possibility to detect if you are close to an object or if you are currently inside a defined area. Once set up, the signals QGeoAreaMonitorSource::areaEntered() and QGeoAreaMon itorSource::areaExited() keep you informed if the device enters or leaves the defined area. Combined with QGeoCoordinate::distanceTo() this can be used perfectly in a scavenger hunt game. Have a try and create a small scavenger hunt game for your local area.

Bluetooth and NFC If you plan to connect your device to others you may want to use Bluetooth. With the Qt Bluetooth API you can easily get information about your own device, you can scan for other devices that are in range, get information about these devices and finally you can connect to them. With QBluetoothLocalDevice you get access to your device and can for example retrieve information about the device's MAC address with address(). QBluetoothLocalDevice can also be used to turn on your Bluetooth device or for requesting and monitoring device pairings. With the help of QBluetoothDiscoveryAgent you can discover nearby devices and then use either QBluetoothTransferManager to push data to another device or QBluetoothServer to communicate between devices. If you have a look at QBluetoothTransferManager and QBluetoothServer in the documentation, you will notice the similarity to QNetworkAccessManager and QTcpServer. If you have carefully read the chapter about networking, I have no doubt you can master this topic on your own.

With the Qt NFC (Near Field Communication) API you can easily use another extremely short-range wireless technology. For example use QNearFieldManager to register a message handler—a simple slot—with registerNdefMessageHandler(). As soon as a tag comes in range, you will be notified through this handler which receives QNdefMessage and QNearFieldTarget holding all necessary information. While registering the handler you can also define filters that not all NFC tags should be recognized.

[ 46 ] Chapter 11

Have a go hero – using Bluetooth and NFC in a game Bluetooth and NFC can be used in games to connect the virtual world to the real one. For example, if you develop a game where players can trade their character's equipment, Bluetooth can be used to only allow such trades if the two players actual meet and connect their devices via Bluetooth. With NFC you can easily realize a scavenger hunt-like game. For example, if you want to develop some sort of exploration game app for a zoo to see young visitors through the most important attractions, you can install NFC tags near the animal's compounds. The kids would have to find them with their mobile phones running your app and once they find a tag, they can see additional videos about that specific animal. Once they have found all hidden tags, they could get a little present.Debugging and testing

A very important and crucial point during software development is testing as well as debugging. You have to make sure and check that your game is working as you—and your users—expect it to. Software testing is of course a wide area with different topics and different angles of view. In our case we want to focus on two aspects: debugging and unit testing.

Debugging You surely have noticed, that in the previous chapters we used qDebug() quite often. You are already known that it prints out messages. The following section, however, will discuss its usage possibilities in more depth.

Using qDebug() and friends The easiest possibility to debug an application is to write messages to std::cout, std::cerr, or std::clog, which may help you to what your code is actually doing. With Qt you can use those C++-streams or even better use the streams provided by these four functions:

Function Purpose qDebug() Writing debug messages. qWarning() Writing warnings and minor errors that don't have critical impact on your game. qCritical() Writing critical error messages or reporting system errors. qFatal() Writing fatal error messages. After such an error you would exit your game.

All four functions are defined in the QtGlobal header file. Since most the other Qt header files include this header you can use qDebug() and friends right away without the need of including any special header. The message is given through the argument of the type const char*. So normally you would write something like this:

[ 47 ] Miscellaneous and Advanced Concepts

int someInt = 5; if ( someInt % 2 == 0) qDebug("Entering scope for even integers."); else qDebug("Entering scope for odd integers.");

If you run this code in Qt Creator you will see in the Application Output panel: Entering scope for odd integers. In this specific case we already know thatsomeInt is 5 but what if someInt was an argument of a function, then we may want to know for which value the debug message was printed. So we could extend the example code with the following line:

qDebug("Entering scope for odd integers: someInt = %d", someInt);

Now, we also will get the actual value of someInt. Even if this is a practical solution for such a short message with only one argument this will quickly become hard to read for complex messages with multiple arguments. Fortunately Qt can help us out but for that we first have to include the QDebug header. Then we are able to write:

#include qDebug() << "Entering scope for odd integers: someInt =" << someInt;

This will produce the output Entering scope for odd integers: someInt = 5. If you have a close look you will notice that a space was inserted after the equal sign. This is because every << expands to a space and after a complete instruction a new line is added:

qDebug() << "Line 1"; qDebug() << "Line 2";

This is the reason why the preceding code will result in two lines on the output panel. You may ask yourself, however, if that is all there is to it. It is nice but what's the real advantage? The advantage comes with Qt's container classes and types. Imagine you want to debug the content of a list or a hash. To do that, you would have to loop through their elements and print each single element. If you use the << operator instead, Qt will do the work for you:

QList list; list << 1.0 << 1.2 << 1.4; qDebug() << list; QHash hash; hash.insert("Apples", 1); hash.insert("Bananas", 3); qDebug() << hash;

The output then will look well formatted like this: (1, 1.2, 1.4) and QHash(("Bananas", 3)("Apples", 1)).

[ 48 ] Chapter 11

It is likely that you also want to know what location the messages are coming from. This can be done in two ways. The easiest is to use the macro Q_FUNC_INFO. A call like qDebug() << Q_FUNC_INFO; inside a function someFunction() of the class SomeClass will result in: SomeClass::someFunction(). Even if that should be precise enough to locate the corresponding source code in your game, you also can use the environment variable QT_ MESSAGE_PATTERN to customize the output. For this variable different placeholders are defined:

Placeholder Description %{appname} Name of the application. Same value as QCoreApplication::app licationName() returns it. %{file} The name of the source file including the path relative to the path of the executable. %{function} Name of the function. %{line} Line in the source file %{message} The actual message. %{pid} Current process identifier of the application. Same value as QCoreApp lication::applicationPid() returns it. %{threadid} Current thread identifier. %{type} Type of the handler, for example, "debug", "warning", "critical" or "fatal".

In Qt 5.2, QLoggingCategory was introduced which allows you to define categories for your messages. The corresponding calls for qDebug(), qWarning(), and qCritical() are qCDebug(), qCWarning(), and qCCritical(). Thus, when altering QT_MESSAGE_ PATTERN you can also use %{category} as a placeholder for the message's category. If you define QT_MESSAGE_PATTERN as %{message} (%{pid}), the process identifier, enclosed in braces, will be appended after the actual message. Since the process identifier may be important for debug messages, but not for warning messages, we can specify the output even closer. Everything between %{if-debug} and %{endif} will only appear if you use qDebug(). So we change QT_MESSAGE_PATTERN to %{message}%{if- debug} (%{pid})%{endif} and the process identifier will only occur at the end of debug messages. Of course there are also the conditionals %{if-warning}, %{if-critical}, and %{if-fatal}.

To tweak the output of qDebug() and friends during execution QT_MESSAGE_PATTERN is not of any help. For this task Qt provides qSetMessagePattern(). So if you like to change the appearance of qDebug() during runtime, you can write:

qDebug() << "foo"; qSetMessagePattern("%{message} (%{pid}; %{threadid})"); qDebug() << "bar";

[ 49 ] Miscellaneous and Advanced Concepts

This will output for example:

foo bar (18357; 0x207a9b0)

As you see, we have defined the message pattern with the qSetMessagePattern() parameter of type QString, which interprets the placeholders described above as well.

Time for action – defining your own message format The information where exactly a message came from can be very useful especially for large projects. So try to define QT_MESSAGE_PATTERN that fits your needs. You can add this variable locally to each project by using Qt Creator's great opportunity to define variables for the run environment or set it globally on your development machine. If you want to use Qt Creator, have a look at the projects (Ctrl + 5), change to the current kit's Run tab and there you will find under Run Environment a nice editor for altering, removing, and adding environment variables that are set before Qt Creator lunches the application.

Time for action – using qDebug() with custom classes To top the feature of using the qDebug() with a list or a hash—by the way, QDebug stream operator is overloaded for almost every important and useful class of Qt—you can also use the debug, warning, and error handles with our own classes.

Suppose we have this simple class:

class SimpleClass { public: SimpleClass(int loc) : local(loc) {} int local; };

If we would now use qDebug() to debug this class it would result in an error like: no match for 'operator<<' (operand types are 'QDebug' and 'SimpleClass'). In order to get it to work all we have to do is to overload the operator<< of QDebug.

QDebug& operator<<(QDebug dbg, const SimpleClass &sc) { dbg.nospace() << "(SimpleClass: local = " << sc.local << ")"; return dbg.space(); }

[ 50 ] Chapter 11

Now, if we write qDebug() << SimpleClass(5); we would get the debug message (SimpleClass: local = 5).

What just happened? How is that possible? Well, since we overloaded the stream operator of QDebug, Qt can now use it and write information about SimpleClass. In the operator we get the debug stream and a constant reference to the object that should be printed out. So we can use dbg like we would work with for example, qDebug(). As two special functions we used QDebug::nospace() which prevents a space from being inserted by the operator<< whereas QDebug::space() does the exact opposite. This solution, however, will fail if you like to print private members. An easy method but risky and unsafe solution would be to declare the operator as a friend by adding friend QDebug& operator<< (QDebug dbg, const SimpleClass &sc); to SimpleClass. Since one can cast the constness away this is not very safe and you should avoid it. Another solution would be to provide a toString() method in SimpleClass. As a member function it could access the private members without restrictions and thus no friend declaration is needed.

If you have overloaded the stream operator for a custom class you can use it for qDebug(), qWarning(), and qCritical(). This is because all function returns aQDebug object that is once configured withQtDebugMsg , once with QtWarningMsg and once with QtCriticalMsg. Only qFatal() can't make use of the stream operator.

Depending on how excessive you are using qDebug() and qWarning(), it can become quite noisy. To turn all debug and warning messages off, you can define QT_NO_DEBUG_ OUTPUT and/or QT_NO_WARNING_OUTPUT in the project file. Thus all messages will be suppressed.

Time for action – redirecting the stream of QDebug By default, messages are printed to stderr or sent to the depending what platform you are on. With qInstallMessageHandler(), however, you can intervene and define yourself what should be done with the messages. Therefore, you first have to define your own message handler of type QtMessageHandler which is defined as void myMessageHandler(QtMsgType, const QMessageLogContext &, const QString &); For an example let's put all messages in a file:

void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message) {

[ 51 ] Miscellaneous and Advanced Concepts

Q_UNUSED(context) QString text; text += "[" + QDateTime::currentDateTime().toString() + "] "; switch (type) { case QtDebugMsg: text += "Debug: "; break; // … } text += message; QFile log("myApp.log"); log.open(QIODevice::WriteOnly | QIODevice::Append); QTextStream stream(&log); stream << text << "\n"; log.close(); }

What just happened? First we define myMessageHandler of type QtMessageHandler. Then, inside that function we create aQString called text. To this string you can append whatever you like, in the example we assigned the time, the type of the error and the actual message. Then we open a file where we specified QIODevice::Append so that the text is appended to the content of the file rather than replacing it. After we have written text to the file using QTextStream we close it before leaving the function. If you want to avoid the temporarily created string you could stream the information directly to the file.

To open and close a file each time qWarning(), qDebug(), and so on is called, which is not an ideal solution. In real code, open the file only once and close it when leaving the application. Last, we only have to tell Qt to use our message handler. Ideally this is done before QApplication is constructed so that possible warnings of QApplication are also written to the file. So at the first line of the main function we write: qInstallMessageHandler(myMessageHandler);

If we call qDebug() << SimpleClass(5); again [Di. Nov. 19 21:10:30 2013] Warning: (SimpleClass: local = 4) will be appended to the file called myApp.log.

In the example we did not have to use QMessageLogContext but you might want to use it since it holds information about the path of the file, the function's name, and the line number.

[ 52 ] Chapter 11

Have a go hero – redirecting the messages to QTextEdit You have seen how to redirect the messages to a file, now it might be handy to see the messages beside your game in a text edit. So have a try and alter the previous example to show the messages in a text edit.

Testing assumptions During development, it is useful to also test pre- and post-conditions or—in a more general sense—to test assumptions you have made. Therefore Qt offers three macros to help you with that.

If you have to check simple conditions use Q_ASSERT. To check at a certain point if the variable cnt equals 5 you would write:

int cnt = 4; Q_ASSERT(cnt == 5);

Since the cnt isn't 5 in this example, Q_ASSERT will use qFatal() to print an error message like ASSERT: "cnt == 5" in file ../Debugging/main.cpp, line 12 and will then abort.

To customize and pass additional information to the error message generated byQ_ASSERT you can use Q_ASSERT_X instead:

Q_ASSERT_X(cnt == 5, "Core Computation", "List size is not 5");

If the condition is false the last two arguments are used to form the error message which in the example would look like ASSERT failure in Core Computation: "List size is not 5", file ../Debugging/main.cpp, line 12. If the test condition is met Q_ASSERT_X will also abort the execution of the program.

Q_CHECK_PTR, the last macro, is designed for testing if a pointer is null:

char *c = 0; Q_CHECK_PTR(c);

This code will abort the process telling you that the program ran out of memory.

All three macros are useful to spot errors during the development but useless for the release mode. This is because during compilation in release mode the variable QT_NO_DEBUG is set preventing all of the checks from being performed. Thus the program will no longer exit if a condition is false.

[ 53 ] Miscellaneous and Advanced Concepts

Using a debugger As a matter of fact nothing can replace a real debugger like GDB or CDB. qDebug() is nice for a first approach but if you can't figure out the problem in a short period of time better switch to a real debugger on time. Qt Creator offers you plenty of options for efficiently using a debugger. It supports GDB, LLDB, and CDB. So you can use at least one of them under Windows, , or Mac OS X. Help on how to install the debugger on your platform can be found in Qt Creator's documentation under the Setting Up Debugger section.

Time for action – debugging a sample code block To get an impression of the integration in Qt Creator let's try to debug the function MyScene::movePlayer() of our elephant game from Chapter 6, Graphics View. This function does the logic for the parallel scrolling via a calculation of medium complexity.

The code of interest is listed as follows and we want to check if and when the highlighted code is executed:

if (direction > 0) { if (m_realPos > m_fieldWidth - (width() - rightBorder)) { m_player->moveBy(dx, 0); } else { if (m_realPos - m_skippedMoving < rightBorder) { m_player->moveBy(dx, 0); } else { m_skippedMoving += dx; } //…

So we need to set a to cause a halt of execution at this point. The breakpoint can be set by either clicking to the left of the line number or by pressing F9 while the cursor is on that line. Instead of F9 you can, of course, define a custom shortcut. If you want to do this, have a look at Tools | Options | Environment | Keyboard. After you have toggled the breakpoint, a red dot with an hourglass will show up:

[ 54 ] Chapter 11

If you change the creator's edit mode to the debug mode (Ctrl + 4) you can find a view called , which lists all breakpoints you have set so far. If you like to alter a breakpoint, for example, to change the line number or its type, right click on either the icon next to the line number or the list item on the view and choose Edit breakpoint. The following dialog will pop up and allow you to easily edit this breakpoint:

[ 55 ] Miscellaneous and Advanced Concepts

Now start debugging the game by pressing F5. The game will pop up and as soon as you hit the right arrow key, Qt Creator will be focused and is shown on top:

What just happened? As you pressed the key MyScene::movePlayer() was called and line 116 was reached. Thus the breakpoint causes the execution to halt. On the debug mode you then have different views holding various information. We will focus on the most important two views, the Stack and Locals and Expressions view. Under Windows | Views you can display other views as you like.

On the lower left of the picture you see the so called Stack view. There, as soon as the game is interrupted you will find all nested function calls that leads to the current state. This is called a call stack trace. The first element of the list contains as a function MyScene::movePlayer, as the file mygraphicsscene.cpp and as line number 116. This was expected since we set the breakpoint there. The next line indicates the function which was executed right before and the function that called MyScene::movePlayer(). If you double click on that line, Qt Creator opens the corresponding file at the given line number. This way you can easily and quickly go through the sources that lead to the function call that you were interested in.

[ 56 ] Chapter 11

Second, have a look at the top right. Here you'll see the Locals and Expressions view. It outlines information about local and member variables. There you can see that for example, the local variable rightBorder has a value of 277. To reproduce how you get to the actual scope at line 116, you would start at the firstif condition direction > 0. The value of direction is 1 as you can see from the first entry and you can also see that this variable is an integer type. On the first line of the function we have defined this variable as int direction = m_player->direction();. So if you want to double check—assumed you know that Player::direction() returns the value of the private member called m_direction—you can check that too. Just follow the tree starting at this/m_player/m_ direction. The corresponding line is highlighted in the preceding screenshot. As you see you can get a pretty clear picture of the value of almost every variable of your game.

If this information already satisfies you hit F5 to continue the execution. If you want to know what happens next you can step over, step into or step out of the function. This way you can keep going step by step and investigate how your game evolves. You can use the buttons right over the Stack view for the navigation inside the code.

Have a go hero – making yourself familiar with the debugger Go ahead and make yourself familiar with the debugger and also have a look at the other views and their information. The better you know the debugger environment the faster you can develop because do not think that you will not make mistakes while coding. You will make them and most probably not in places where you can easily spot the error. Thus, you will definitely have to use a debugger sooner or later.

But wait, you may ask yourself how to debug Qt Quick application. The answer is pretty easy: like you would debug a C++ application. Since the introduction of Qt 4.8 QML debugging is enabled by default, you only have to make sure that in Qt Creator's run settings, the check box for QML debugging in the Debugger Settings page is enabled. If so, simply set your breakpoints and start debugging with F5. That's all. A great feature when debugging QML applications is that you can change properties on the fly. To do that either open the QML/JS Console and type in JavaScript commands to alter variables or start editing variables in the Locals and Expressions tab by simply double-clicking on them.

If you use C++ as well as QML in your application, make sure C++ debugging is also enabled in the Debugger Settings page so that you can debug both components without any limitation.

The Qt Creator Manual in general is very good and self-explanatory. In its documentation you will also find a chapter about debugging C++ and QML applications. Have a look athttp://qt-project.org/doc/ qtcreator-latest.

[ 57 ] Miscellaneous and Advanced Concepts Testing Even though you can use the Qt Test framework to test the GUI of your application or your game, it is not its strength as it only offers rudimentary tools to do so. So you might want to use another tool for GUI testing. For unit testing, however, Qt Test is just perfect.

Here is how it works. First, you have to create a class that inherits QObject. Next you have to define at least one private slot. Each slot is later treated as one unit test. If you add more than one slot, they get invoked in the order in which you have declared them. Last call QTest::qExec() passing the class that holds your test as an argument. qExec() then executes all test and prints the result to stderr by default.

Writing unit tests

Time for action – writing a first unit test So let's make our first, minimalistic unit test. Remember to add Qt += testlib to the project file in order to make the Qt Test framework available:

#include class SimpleTest : public QObject { Q_OBJECT private slots: void firstTest() {} }; int main(int argc, char *argv[]) { SimpleTest test; return QTest::qExec(&test, argc, argv); } #include "tst_simpletest.moc"

If you run this example you get this output:

********* Start testing of SimpleTest ********* Config: Using QtTest library 5.1.1, Qt 5.1.1 PASS : SimpleTest::initTestCase() PASS : SimpleTest::firstTest() PASS : SimpleTest::cleanupTestCase() Totals: 3 passed, 0 failed, 0 skipped ********* Finished testing of SimpleTest *********

[ 58 ] Chapter 11 What just happened? As described before, we create a QObject derived class called SimpleTest and add a private slot named firstTest() to it. Then we add the obligatory main function where we create a SimpleTest object and pass it to QTest::qExec() along the command-line parameters. This call will automatically invoke the one and only test which will succeed as it is empty. You'll find this information in the output along with the information that the version of Qt was 5.1.1. But what about initTestCase() and cleanupTestCase()? We do not have declared these slots.

Well, before Qt starts the test on a class, it tries to invoke a slot called initTestCase() if it exists. When all tests on a class are finished, the test framework will call cleanupTestCase(). You can use these two functions to initialize and clean up the entire test. They are comparable with a constructor and a destructor. To initialize or to clean up before and after a single test Qt will automatically call the functions init() and cleanup(). So if you want to use them, just define—and implement—these four functions as private slots. Qt will do the rest.

If you have a look at the main() function, you'll see that there is nothing special at all about it. So Qt keeps some useful macros available in order to free you from having to type these lines of code. A call of QTEST_APPLESS_MAIN(SimpleTest) would produce the exact same main function as in the previous example. If you need QApplication for your tests, you can use the macro QTEXT_MAIN. If QCoreApplication is enough use QTEST_ GUILESS_MAIN. This will save you a lot of writing.

Even faster and much more comfortable is to use Qt Creator. Choose File | New File or Project | Other Projects | Qt Unit Test will get you a wizard where you can define and adjust a test case in no time. Since we used the Q_OBJECT macro in a .cpp file (tst_simpletest. cpp), we have to include the .moc file by hand. This way qmake will generate the needed instructions for the meta object .

Time for action – writing a real unit test So far our test case was empty. Let's change that and add a real test. In general you can do inside a test slot whatever you want. There are no special limitations. At one point, however, you have to check if a condition is met. For this task the following macros come in handy:

[ 59 ] Miscellaneous and Advanced Concepts

The most brutal way to force a test to fail is to use QFAIL as it stops the execution of the test immediately and prints the error message you could define as a parameter. If you ran a test case like this:

void firstTest() {QFAIL("No way!");}

You would get as a report (shorted as the following reports will also be):

FAIL! : SimpleTest::firstTest() No way! Loc: [../UnitTest/tst_simpletest.cpp(7)] Totals: 2 passed, 1 failed, 0 skipped

The report states that one test failed and due to the prefix FAIL! you can spot the troublemaker easily. Additionally, the file and the malicious line number are mentioned.

If a test requires special preconditions, for example, the existence of certain modules, but they are not met, you can skip a test with QSKIP. Here is an example:

void areMathematiciansCrazy() { if (1 != 2) QSKIP("Thank goodness! 1 still isn't 2."); }

The following code results in:

SKIP : SimpleTest::areMathematiciansCrazy() Thank goodness! 1 still isn't 2. Loc: [../UnitTest/tst_simpletest.cpp(7)] Totals: 2 passed, 0 failed, 1 skipped

The QCOMPARE macro is used to compare two values, the actual to an expected one. For example:

QCOMPARE(1+1, 11);

This code would compare if 1+1 equals 11. Note that QCOMPARE is very strict on the data types. So both values have to be of the same type. If this test fails, the output informs you about the actual value 2 and what you would have expected 11. For example, you could see an output like this:

FAIL! : SimpleTest::simpleTest() Compared values are not the same Actual (1+1): 2 Expected (11): 11

[ 60 ] Chapter 11

With QVERIFY you can check a condition. If it is false the test will fail and print an error. QVERIFY(1==2); would cause a log like FAIL! : SimpleTest::simpleTest() '1==2' returned FALSE. If you like to add a customized, more descriptive message text, use the macro QVERIFY2. The message that could be defined as a second parameter will be printed after the error message as seen in the previous code. A sample usage of this macro could be QVERIFY2(1==1, "Well, now mathematicians are crazy.").

Last I would like to mention QTRY_COMPARE_WITH_TIMEOUT and QTRY_VERIFY_WITH_ TIMEOUT. Both behave like QCOMPARE and QVERIFY except that as a second or third parameter a timeout can be specified. The macros then compare the values or check the conditions until they becometrue or the timeout is reached. In the latter case the test will fail. For convenience there are also QTRY_COMPARE and QTRY_VERIFY which have a timeout of 5 seconds defined.

Writing unit test with data If you have a unit test that needs to test a function with different values, you can separate the testing logic form the data. For this create a private slot named like the slot of the actual test and add _data to it.

Time for action – running unit test which uses a data function

void test_data() { QTest::addColumn("string"); QTest::addColumn("count"); QTest::newRow("simple string") << "Hello" << 5; QTest::newRow("with interpunctation") << "world!" << 6; } void test() { QFETCH(QString, string); QFETCH(int, count); QCOMPARE(string.count(), count); }

If you run this code it will result in:

PASS : SimpleTest::test(simple string) PASS : SimpleTest::test(with interpunctation)

[ 61 ] Miscellaneous and Advanced Concepts What just happened? In the function test_data() we declared that we need two variables respectively two values for each test run of test() by calling Qtest::addColumn() twice. Of course the number of variables is not limited. Each call of addColumn() first defines the type of the new variable, QString and int, and then the name of this variable, string and count. With QTest::newRow() we define the values of these variables. The parameter of newRow() should be a short descriptive text of what is going to be tested. Then with the stream operator the values are defined. As the names of the functions addColumn() and newRow() suggests itself: think of this variable definitions as a simple table that is defined.

The test() function then loops through the rows of this imaginary table. Each time we fetch the values out of the cells by using QFETCH. Here, the arguments of QFETCH has to match the previous declaration made by QTest::addColumn(). After the fetch is done we can use string and count as a normal QString and integer. If you have a look at the output you will spot the use case of the argument of QTest::newRow(). It is printed after the test name so that you can see which data pair was processed and passed, was skipped or failed of course.

Useful command-line arguments To complete this part about the Qt Test framework, let's stress two useful capabilities of the test's command-line options.

Suppose you have defined multiple time consuming tests and the last one fails. Now, after you have tried to fix the cause of the failure you have to perform all tests again to notice that the fix does not work. This is a quite unsatisfying workflow. You have to check functions that run over and over again only to test a specific one. Of course, you could move the declaration of that test to the top to force it to be executed at the beginning but that is not an ideal solution. Fortunately, this issue can be solved with a command-line option. When you invoke the test program, simply pass the name of the slot you want to execute. It will then be the only test that is performed. For example, if your unit test creates the executable named unittest.exe and you would like to test firstTest(), you can call unittest. exe firstTest. If you like to execute more than one specific test, just add the names of the other tests separated by a space. If you do not pass any specific test at all, all tests will be performed.

[ 62 ] Chapter 11

Passing a command-line argument does not mean you have to leave Qt Creator. Have a look at the Projects view. For the active Kit choose the Run tab and there inside the Run section you find a line edit for defining arguments. Here you can simply define the names of the slots that should be performed. If a test uses the data functionality as described earlier, you can specify the specific row by adding the row's name right after the slot's name separated by a colon. Enclose the entire name by quotes whenever the row's name contains spaces. For example, unittest.exe test:"simple string".

The second useful capability comes in play when you work with multiple test classes each holding a lot of unit test. Then you most likely need to process the results in a more efficient way than going through the output in the Qt Creator's Application Output panel. With the command-line option -o you can define a file in which the results should be stored. This file can then be further processed, for example, by a report tool or something similar. The default format of the file is a simple text file holding the messages as you have seen them in the output panel. Since this format may not be the best for further automatic processing, you can pass -xml as an additional command line argument causing the output formatted as XML. Beside -txt, the default format, and -xml you can also pass -lightxml, to get a stream of XML tags, or -xunitxml, to get an Xunit XML document, to the command line to influence to format of the output.

Pop quiz – testing your knowledge Q1. What suffix do the convenience wrapper around QSensor have which facilitate the reading form a sensor?

1. The suffix is Watcher such as QRotationWatcher. 2. The suffix is Broker such as QRotationBroker. 3. The suffix is Reading such as QRotationReading. Q2. What class do you have to subclass if you like to detect a custom defined gesture?

1. The class is named QSensorRecognizer. 2. The class is named QSensorGestureRecognizer. 3. The class is named QGestureRecognizer.

[ 63 ] Miscellaneous and Advanced Concepts

Q3. Which module provides information about the device's current position and how do you activate it?

1. It's the Qt Positioning module and you activate it by adding QT += positioning to the project file. 2. It's the Qt Position module and you activate it by adding QT += position to the project file. 3. It's the Qt Location module and you activate it by adding QT += location to the project file.

Q4. What stream operator do you have to overload to comfortably use your own class with qDebug()?

1. One has to overload QDebug& operator<<(). 2. One has to overload QDebug& operator+(). 3. One has to overload QDebug operator||().

Q5. What does Q_ASSERT(condition)?

1. It aborts the execution of the program if condition is false, regardless if the program was built in release or debug mode. 2. It aborts the execution of the program if condition is true. 3. It aborts the execution of the program if condition is false, only if the program was built in debug mode.

Summary In the first part of this chapter you familiarized yourself with a number of frameworks for making your games take advantage or multiprocess and multithreaded architectures and also to reach out to a larger number of end-users by making your games talk to them in their own language. The last framework we presented to you allows to record and output multimedia content in both the widgets and Qt Quick worlds.

Then you learned about using sensors. You have seen how to retrieve sensor data and which different sensor types are available. Unfortunately, not all sensors are supported on each device. Next you learned about the build-in sensor gestures. The example of the shaking gesture has furthermore shown how to create custom gestures in order to customize your game experience.

[ 64 ] Chapter 11

In the section about Qt Positioning, Bluetooth and NFC, you were briefly introduced to additional possibilities you have on mobile devices. Connecting two player's devices can be a real fun factor for your game since playing in groups is gaining in popularity.

Since testing and debugging are essential parts of software development and should take as much time as inventing and coding a game, we had a look at these too. First you saw how to use qDebug() and how you could redirect its output. In situations where this technique does not help you spot the error, you have seen how elegantly Qt Creator integrates platform debugger. With Qt Creator you can easily set and manage breakpoints as well as inspect the call stack.

At the end you finally learned how to create unit test using Qt Test. This way you can automatically guarantee that your game will function well. With the knowledge about debugging and testing you are good to go for programming.

[ 65 ]