1 - installing the tools and running samples
2 - calling C++ library from Java
3 - abstracting types and logging
4 - timing service
today we will create first from the set of services. It will be timing service. Service is here some class or set of classes that enclose some functionality and is fully reusable in future projects.
Until now our engine run as fast as possible calling engine_tick method. In this method we set background color but so far we do not know how much time elapsed form previous call. So we have no information that would be handy in whatever you can imagine - timing animation, showing the player time spent in level, timing bombs explosion, etc.
On the image bellow you can see project structure. New files we are going to create today are highlighted with green. Beside this we will make changes into Main.cpp. As the timing service is the first one from set off services we will create in future we are also going to create Context class. This class works as a bag full of services which is easy to reference and handle inside game.
As with the logging class we are preparing ourselves for future when we want to go cross-platform. ITimeService.h is abstract interface class that defines interface that will be common for all supported systems - only Android now. TimeServiceBase is class that implements those parts of the ITimeService, that are the same for all systems. Finally, AndroidTimeService implements rest of the methods.
Listing for ITimeService.h is simple:
The common base for all systems looks like this:
We added some member variables to store elapsed time from last update of timer and also previous time. This base class also has construct method. This method is part of construction of the object. First the constructor is called and then construct method is called. It is called two-phase construction. Imagine that you are creating new object that needs to create several other objects on the heap. Next imagine that first of these objects is successfully created but you get out of memory error when constructing the second one. In such a case the original object is not constructed and thus its destructor is not called. But you already successfully created on of its child objects in constructor. Who will destruct it? Answer is no one - you will get memory leak.
Opposite to this you can do two phase construction. First allocate the object and just initialize its member variables that do not need additional memory allocations or do thing that can not fail. Then call construct method that will do the rest. Good explanation and example of this can be found here.We are not allocating any memory for time service now. But what if there was system that would need it in future...
Implementation of TimeServiceBase is here:
As you can see some methods just say "Feature not implemented for current system". I found this very useful when I was adding new Tizen system into my cross platform engine. As I was writing Tizen implementation of the all the services one by one I was able to run it and when I came across some that was not implemented yet I got log message about it but there was minimum of crashes. Also when see this you know there is needed some system specific implementation.
Now we can implement Android specific parts. AndroidTimeService.h has this listing:
and implementation is like this:
In now method we are reading current time for monotonic clock. But, what is current time? According for example to this documentation you can read that it is "Clock that cannot be set and represents monotonic time since some unspecified starting point.". The starting point is often system boot. Fortunately it is not interested for us. We need it just to measure time leaps from one call to another and to calculate the elapsed time. Last time as well as elapsed time are in seconds.
Creating context class
Our first service is created so let's put it into bag for services - into the context. But first we have to create this bag. This is the header for Context class. It is first class that is created in Engine directory of our engine structure:
As can be seen it is just set of getters and setters. Only interesting is destructor because ownership of all created services is handeled to context and it is then responsible for destructing them (except for application). In implementation you can see it:
Maybe you noticed that in all .cpp files, there is defined LOG_TAG in the very top. This tag helps in debugging as all log messages from the same .cpp file are tagged with it.
As a last step change system.h file - add TimeService to it:
As we have now also the context we can wire it into Main.cpp. We will initialize the services when the engine starts and destroy the context (and all services in it) when the engine is to be destroyed.
Wiring contextChange top of the Main.cpp to this:
Adjust engine_start and engine_stop methods:
and also adjust resume_engine method. We will reset the time service in it:
Finally, to see some effect change engine_tick method to this:
the counter variable is based on value of counter and the screen is blinking from yellow to light blue. The complete change of color takes 1 second.
Today we created first of engine services - the TimeService. It tells us how much time elapsed from last tick and we can use this information to adjust whatever is based on real time in the game. Thanks to this we can base for example our animations on real time and not on frame rate which may differ from device to device.