In the HTML version of my PlayN game, how can I reliably load fonts so text displays on startup?
-
22-06-2021 - |
Question
I'm using v1.3.1 of PlayN. This issue is discussed in the following google groups thread but I'm not sure how to implement the suggestions proposed:
https://groups.google.com/forum/?fromgroups#!topic/playn/kiE2iEYJqM0
Perhaps someone can offer some sample code. Currently I'm following the technique referenced in the HTML link in this answer:
https://stackoverflow.com/a/9116829/1093087
My problem: on the home screen of my game, I display some text using loaded fonts. Works fine in Java version. However, in HTML version, the text doesn't display initially. On the next screen, or if I later return to the home screen, text is properly displayed. So I concluded that it was due to the asynchronous loading of fonts as discussed in the google groups thread.
My remedy was to add a splash screen that displays an image for a few seconds, giving the fonts a chance to load, before redirecting to screen with the text on it. But no matter how long I set the delay, the text is still not displayed.
Here's my HTML file which loads my game and the fonts:
<!DOCTYPE html>
<html>
<head>
<title>mygamePlayn</title>
<!-- fonts -->
<style>
@font-face {
font-family: "DroidSans-Bold";
src: url(mygame/fonts/DroidSans-Bold.ttf);
}
@font-face {
font-family: "UbuntuMono";
src: url(mygame/fonts/UbuntuMono-Bold.ttf);
}
</style>
</head>
<body bgcolor="black">
<script src="mygame/mygame.nocache.js"></script>
</body>
</html>
Here's my core Java code that generates the text that's not initially displaying (but works otherwise):
public static CanvasImage generateTextImage(String text, String fontName,
Integer fontSize, Integer fontColor, Style fontStyle, Integer padding) {
Font font = graphics().createFont(fontName, fontStyle, fontSize);
TextFormat fontFormat = new TextFormat().withFont(font).withTextColor(fontColor);
TextLayout layout = graphics().layoutText(text, fontFormat);
Integer width = (int) layout.width() + padding * 2;
Integer height = (int) layout.height() + padding * 2;
CanvasImage textImage = graphics().createImage(width, height);
textImage.canvas().drawText(layout, padding, padding);
return textImage;
}
Solution
I think I've finally figured out a solution to my problem. It required using Google WebFont Loader in the following somewhat roundabout fashion:
1) I saved the fonts -- in this case, DroidSans-Bold, Inconsolata, and UbuntuMono-Bold -- in my PlayN project's resources/fonts
directory.
2) In resources/css
, I add a fonts.css
stylesheet where I add the @font-face
definitions for my locally saved fonts. My fonts.css
file:
@font-face { font-family: DroidSans; src: url('../fonts/DroidSans-Bold.ttf'); } @font-face { font-family: Inconsolata; src: url('../fonts/Inconsolata.ttf'); } @font-face { font-family: UbuntuMono; src: url('../fonts/UbuntuMono-Bold.ttf'); } @font-face { font-family: UbuntuMono; font-weight: bold; src: url('../fonts/UbuntuMono-Bold.ttf'); }
Note: I use the same value for my font-family name as that which I used for the font names in my PlayN code. For example, I load the DroidSans font in my PlayN code like this:
Font font = graphics().createFont("DroidSans", fontStyle, fontSize);
3) I then use Google WebFont Loader in my game's html file (MyGame.html
) to load the fonts before the game loads. My MyGame.html
file:
<!DOCTYPE html> <html> <head> <title>MyGame</title> <style> body { background-color:black; color:white; } </style> <!-- Google AJAX Libraries API --> <script src="http://www.google.com/jsapi"></script> <script> google.load("jquery", "1.4.2"); google.load("webfont", "1"); WebFontConfig = { custom: { families: ['DroidSans', 'UbuntuMono'], urls: [ 'mygame/css/fonts.css' ] }, loading: function() { console.log("loading fonts"); }, fontloading: function(fontFamily, fontDescription) { console.log("loading font: " + fontFamily + "-" + fontDescription); }, fontactive: function(fontFamily, fontDescription) { console.log(fontFamily + "-" + fontDescription + " is active"); }, fontinactive: function(fontFamily, fontDescription) { console.log(fontFamily + "-" + fontDescription + " is INACTIVE"); }, active: function() { console.log("font-loading complete"); }, }; google.setOnLoadCallback(function() { console.log("Google onLoad callback"); WebFont.load(WebFontConfig); }); </script> </head> <body> <div id="playn-root"> <script src="mygame/mygame.nocache.js"></script> </div> </body> </html>
The console logging in the WebFont.load
callbacks helped verify that the fonts were successfully loaded before the PlayN game code.
I would have preferred to use WebFont Loader with the fonts served through googleapis.com, but I couldn't figure out how to sync up the references between my PlayN code and the stylesheet. (Now that I look at it, if I didn't want to host the fonts myself, I suppose I could have just used the same url listed in the googleapi.com stylesheets.) Whatever the case, this pattern seems to solve the problem.*
*For Google Chrome. I haven't tested any other browsers.