Time
Time is an essential thing. It is utilized in every computer game, it is used in game logic, animations, visual effects and user input handling.
But how exactly time is measured on WOWCube device?
As we already know, the WOWCube device is built out of eight modules with its own CPU and memory. Each runs CubiOS operating system that hadles hardware components of the module. One of the components is a clock, a device that produces ticks at some very high, constant frequency. Once module is started, it begins to do these ticks and it never stops. So knowing the number of ticks passed between two moments we can actually see how long it took or how much time passed.
Time ticks are very important for all CubiOS internal function too. Graphics on screens, memory, sensors and power - all this obeys the rhythm set by the internal clock. All ongoing processes that run insinde WOWCube use time. If internal clock stops, device turns unresponsive.
So in order to create a cubeapp that implements any kind of dynamics, we would want to use the time as well, right?
But how do we know that tick has elapsed? How do we know how fast this happened?
For that, ON_Tick() callback is used. It is called by CubiOS every time new tick passes, as frequent as device can do.
Using this callback, we can do multiple useful things with time. Most typical tasks are to calculate time elapsed from the last iteration of game logic (i.e last frame) and implement a timer that ticks with given periodicity.
Let's take a look at the example.
Measuring elapsed time
Firstly, we would want to measure time elapsed between two calls of ON_Tick() callback.
In order to calculate the time between, we need to know two things: when the previous tick happened and when the current tick did. For that, variables are declared:
And now all we have to do is to see the difference of currentTime and previousTime like this:
In order to fill the variables with actual time values, getTime() function is used. This function returns current time of the module in milliseconds.
A millisecond (from milli- and second; symbol: ms) is a thousandth (0.001 or 1/1000) of a second.
Thus, subtracting previous time from current time we will get amount of milliseconds passed between two moments in time.
And sice we do this math every time ON_Tick() is called, the deltaTime will be getting a time between two ticks!
Pay attention!
The calling frequency of
ON_Tick()callback is not guaranteed to be constant, may vary and depends on the actual CPU load of the module. The load, in turn, depends on a complexity of a codeON_Tick()callback implements. More complex the code is, more CPU load is put.
Implementing a timer
Timer is a specialized type of clock used for measuring specific time intervals.
A principle of implementation of a timer is not much different. Timer checks elapsed time between the ticks and it fires if that time is greater or equal to requested delay value.
Using timers it is very easy to implement recurrent in-game actions that happen each 1, or 5, or 10 seconds.
Let's see the code. First, a timer structure is declared:
Timer has two components - delay and time. First one is a desired delay, second one is for storing current time value.
We also declare a variable for keeping a number of seconds passed. This variable will be incremented every time the timer ticks.
Now, the timer must be initialized. This is done inside ON_Init() callback that is called when cubeapp is started:
Timer delay is initialized with 1000 milliseconds or 1 second.
The last bit is in ON_Tick(): each second the value of seconds is incremented.
Measuring FPS
Frame rate (expressed in frames per second or FPS) is the frequency (rate) at which consecutive images (frames) are displayed on module screens.
FPS is one of the most important metrics of any computer game with graphics. It is essential to keep it at acceptable rates while the game plays. Sudden drops of FPS value may get user dissatisfied with the game.
The way of calculation of FPS is rather trivial: as long as we know deltaTime, the FPS value would be calculated as
This, however, is where things are getting slightly more complicated on WOWCube platform...
Fixed point arithmetic
At the moment, the only way to deal with fractional values on WOWCube platform is a fixed point arithmetic. Unlike it in other programming languages, WOWCube SDK DOES NOT SUPPORT neither float, nor double variable types.
Why is that? Why not to use common types?
In short, this is done for two reasons:
- make the code faster
- make it consume less memory
The WOWCube is a powerful device with eight grunty CPUs, but it is still a very compact, portable piece of hardware that needs top level of overall optimization to deliver the best user experience. Hence the use of fixed point instead of full-fleged floating point rationals.
There is also another, less obvious reason too: fixed point arithmetics defines the precision in an exact and intuitive manner unlike the common floating point arithmetics. Fixed point values have limited precision regardless of how they are implemented. In simple terms it means that while tiny errors in floating point values can build up to larger, noticable errors after repeating operations, with fixed point arithmetics such will never happen. So fixed point, and especially decimal arithmetic is more appropriate for cubeapp applications where all numbers lie in a limited range.
The fixed point format used in WOWCube SDK uses three decimal digits and stores the values in two's complement. This gives a range of
-2147483to+2147482with 3 digits behing the decimal point.
Fixed point arithmetic also goes by the name of
scaled integerarithmetic. Basically, a fixed point number is the numeration of a fraction where the denominator is implied. In WOWCube SDK, the denominator is 1000. Therefore, the integer value of 12345 stands for 12345/1000 or 12.345
Measuring FPS (part II)
So, in order to calculate FPS, we must deal with fractional values. Hence, fixed point values must be used.
The fps variable is declared this way:
Then, its value is calculated in ON_Tick() callback
Here's what's happening in the code:
- Integer value of
1000is converted into fixed point value - Integer value of
deltaTimeis converted into fixed point value too - First value is divided by second value with
fdiv()function - The
fdiv()function returns fixed point value offps
Rendering results
It's a final part of the excercise, and it is quite simple.
In order to render time values, three simple steps are taken inside ON_Render() callback:
-
Clear the screen
-
Render the text with values
-
Commit changes
Time and TimersPAWNWrapped for easier reading. Turn wrap off to inspect exact line lengths.
The only thing that's left uncovered is the strformat function call.
Check out Working with Strings example to learn more...