It was starting to get a bit annoying having to keep whose turn it was in our heads, and most of the time i ended trying to flick on the wrong window. To make matters worse, this week we added rank-based rounds to the gameplay: Once every player has taken her turn, the round is over and the game chooses the order under which players will play the next round based on their distance to the finishing line. Thus, we had even more things to remember, such as the current round and the players’ ranking, and were forced, as it were, to include a heads-up display (HUD).
Something simple, just like this:
Unconcerned, at this point, for the HUD’s aesthetics, we instantiated a new
BitmapFont with its default 14 pt Arial font included with libGDX and, as a first attempt, rendered the current round using the same
ViewPort that we have setup to render the world, expressed in SI units.
The result was a 2 × 1 meters text.
Besides the obvious issue with the size, that could be fixed simply enough scaling down the font, this approach presents two additional problems:
The text size is affected by the viewport’s zoom, and at every frame we have to compute the label position within the world (i.e., in meters) so that it will be shown at the screen’s top-left corner.
This is, of course, doable, but it would be better if we could use pixels to place all elements in the HUD, as this is its “natural” units.
The solution is to use separate
ViewPort objects to render the world and the HUD.
ViewPorts works wonderfully for all our purposes but one:
we wanted the “Your Turn” label to follow the player’s puck after she flicks it.
It would seem that we have to place the label in the world at the same position as the puck, that is expressed in meters. And that would mean that we have again the problem with the text size affected by the viewport’s zoom that we mentioned above. We can not just set the zoom to one only to render the text because then its position on the screen would be completely different than that of the puck.
We realized that, instead of placing the text at the puck’s position inside the world, in meters, we can draw it after the world has been rendered to the screen and, thus, “converted” to pixels. For instance, the following figure is a view 3 meters wide and 1.5 meters tall of the world drawn to a screen of 640 × 320 pixels. After rendering, the puck is at pixel coordinates (320, 160) because the camera is centered on it.
Since the camera it is not necessarily centered around the puck, we need to convert to puck’s world position to screen coordinates and then from screen coordinates to the coordinates used by HUD’s
ViewPort has the
unproject methods to perform these coordinates conversions.
Therefore, the most obvious code is:
This does not work: the Y axis is drawn inverted.
It turns out that libGDX uses various coordinate systems.
The two system relevant to this article, mentioned above, are world coordinates and HUD coordinates;
the fundamental difference between these two is their units:
world uses meters and HUD pixels.
ViewPort.unproject assumes that the position is in a third coordinate system:
This coordinate system also uses pixels as units, but the most important difference with HUD is that the y-axis points downwards.
That is, the point (0, 0) is on the top-left corner when using touch coordinates but on the bottom-left with HUD coordinates.
Therefore, we must reverse the Y-axis returned by