A few months ago I started to incorporate Phaser game engine in one of my biggest projects, a new Educational webapp that teaches math to young children. Phaser is an amazingly fast engine and I am glad I have given it a try. There were however some annoying performance problems with text fonts. Since there were only limited tools available, I decided to write a custom solution to generate bitmap fonts (.png + .xml) from the command line. It is a node.js package that is available at:
phaser-bitmapfont-generator
github: https://github.com/stephanvermeire/phaser-bitmapfont-generator#readme
npm: https://www.npmjs.com/package/@rtpa/phaser-bitmapfont-generator
The tool is inprobably very accessable for Phaser developers since it is able to convert a Phaser 3 textStyle configuration object to the accoring .png + xml files.
In short, this small script:
const generator = require('@rtpa/phaser-bitmapfont-generator');
(async () => {
//generate textures
await generator.TextStyle2BitmapFont(
{
path: './mydir',
fileName: 'myBitmapfont',
textStyle: {
fontFamily: 'Impact',
fontSize: '50px',
color: '#fde5c0',
shadow: {
offsetX: 4,
offsetY: 4,
blur: 0,
fill: true,
stroke: true,
color: '#000000'
},
}
}
);
//exit node
return process.exit(1);
})();
generates the following files from the command line:
and:
<?xml version="1.0"?>
<font>
<info face="Impact" size="100"/>
<common lineHeight="86" base="19"/>
<pages>
<page id="0" file="myBitmapfont.png"/>
</pages>
<chars>
<char id="32" x="0" y="0" width="22" height="105" xoffset="0" yoffset="0" xadvance="18" page="0"/>
<char id="33" x="26" y="0" width="31" height="105" xoffset="0" yoffset="0" xadvance="27" page="0"/>
<char id="34" x="61" y="0" width="41" height="105" xoffset="0" yoffset="0" xadvance="37" page="0"/>
<char id="35" x="106" y="0" width="67" height="105" xoffset="0" yoffset="0" xadvance="63" page="0"/>
<char id="36" x="177" y="0" width="59" height="105" xoffset="0" yoffset="0" xadvance="55" page="0"/>
<char id="37" x="240" y="0" width="73" height="105" xoffset="0" yoffset="0" xadvance="69" page="0"/>
<char id="38" x="317" y="0" width="62" height="105" xoffset="0" yoffset="0" xadvance="58" page="0"/>
<char id="39" x="383" y="0" width="23" height="105" xoffset="0" yoffset="0" xadvance="19" page="0"/>
<char id="40" x="410" y="0" width="35" height="105" xoffset="0" yoffset="0" xadvance="31" page="0"/>
<char id="41" x="449" y="0" width="35" height="105" xoffset="0" yoffset="0" xadvance="31" page="0"/>
<char id="42" x="488" y="0" width="32" height="105" xoffset="0" yoffset="0" xadvance="28" page="0"/>
<char id="43" x="524" y="0" width="57" height="105" xoffset="0" yoffset="0" xadvance="53" page="0"/>
<char id="44" x="585" y="0" width="21" height="105" xoffset="0" yoffset="0" xadvance="17" page="0"/>
<char id="45" x="610" y="0" width="33" height="105" xoffset="0" yoffset="0" xadvance="29" page="0"/>
<char id="46" x="647" y="0" width="22" height="105" xoffset="0" yoffset="0" xadvance="18" page="0"/>
<char id="47" x="673" y="0" width="44" height="105" xoffset="0" yoffset="0" xadvance="40" page="0"/>
<char id="48" x="721" y="0" width="58" height="105" xoffset="0" yoffset="0" xadvance="54" page="0"/>
<char id="49" x="783" y="0" width="42" height="105" xoffset="0" yoffset="0" xadvance="38" page="0"/>
<char id="50" x="829" y="0" width="54" height="105" xoffset="0" yoffset="0" xadvance="50" page="0"/>
<char id="51" x="887" y="0" width="57" height="105" xoffset="0" yoffset="0" xadvance="53" page="0"/>
<char id="52" x="948" y="0" width="54" height="105" xoffset="0" yoffset="0" xadvance="50" page="0"/>
<char id="53" x="0" y="109" width="58" height="105" xoffset="0" yoffset="0" xadvance="54" page="0"/>
<char id="54" x="62" y="109" width="58" height="105" xoffset="0" yoffset="0" xadvance="54" page="0"/>
<char id="55" x="124" y="109" width="43" height="105" xoffset="0" yoffset="0" xadvance="39" page="0"/>
<char id="56" x="171" y="109" width="57" height="105" xoffset="0" yoffset="0" xadvance="53" page="0"/>
<char id="57" x="232" y="109" width="58" height="105" xoffset="0" yoffset="0" xadvance="54" page="0"/>
<char id="58" x="294" y="109" width="24" height="105" xoffset="0" yoffset="0" xadvance="20" page="0"/>
<char id="59" x="322" y="109" width="24" height="105" xoffset="0" yoffset="0" xadvance="20" page="0"/>
<char id="60" x="350" y="109" width="57" height="105" xoffset="0" yoffset="0" xadvance="53" page="0"/>
<char id="61" x="411" y="109" width="57" height="105" xoffset="0" yoffset="0" xadvance="53" page="0"/>
<char id="62" x="472" y="109" width="57" height="105" xoffset="0" yoffset="0" xadvance="53" page="0"/>
<char id="63" x="533" y="109" width="56" height="105" xoffset="0" yoffset="0" xadvance="52" page="0"/>
<char id="64" x="593" y="109" width="81" height="105" xoffset="0" yoffset="0" xadvance="77" page="0"/>
<char id="65" x="678" y="109" width="55" height="105" xoffset="0" yoffset="0" xadvance="51" page="0"/>
<char id="66" x="737" y="109" width="59" height="105" xoffset="0" yoffset="0" xadvance="55" page="0"/>
<char id="67" x="800" y="109" width="59" height="105" xoffset="0" yoffset="0" xadvance="55" page="0"/>
<char id="68" x="863" y="109" width="59" height="105" xoffset="0" yoffset="0" xadvance="55" page="0"/>
<char id="69" x="926" y="109" width="46" height="105" xoffset="0" yoffset="0" xadvance="42" page="0"/>
<char id="70" x="976" y="109" width="44" height="105" xoffset="0" yoffset="0" xadvance="40" page="0"/>
<char id="71" x="0" y="218" width="59" height="105" xoffset="0" yoffset="0" xadvance="55" page="0"/>
<char id="72" x="63" y="218" width="60" height="105" xoffset="0" yoffset="0" xadvance="56" page="0"/>
<char id="73" x="127" y="218" width="33" height="105" xoffset="0" yoffset="0" xadvance="29" page="0"/>
<char id="74" x="164" y="218" width="37" height="105" xoffset="0" yoffset="0" xadvance="33" page="0"/>
<char id="75" x="205" y="218" width="58" height="105" xoffset="0" yoffset="0" xadvance="54" page="0"/>
<char id="76" x="267" y="218" width="42" height="105" xoffset="0" yoffset="0" xadvance="38" page="0"/>
<char id="77" x="313" y="218" width="76" height="105" xoffset="0" yoffset="0" xadvance="72" page="0"/>
<char id="78" x="393" y="218" width="58" height="105" xoffset="0" yoffset="0" xadvance="54" page="0"/>
<char id="79" x="455" y="218" width="59" height="105" xoffset="0" yoffset="0" xadvance="55" page="0"/>
<char id="80" x="518" y="218" width="54" height="105" xoffset="0" yoffset="0" xadvance="50" page="0"/>
<char id="81" x="576" y="218" width="59" height="105" xoffset="0" yoffset="0" xadvance="55" page="0"/>
<char id="82" x="639" y="218" width="58" height="105" xoffset="0" yoffset="0" xadvance="54" page="0"/>
<char id="83" x="701" y="218" width="56" height="105" xoffset="0" yoffset="0" xadvance="52" page="0"/>
<char id="84" x="761" y="218" width="50" height="105" xoffset="0" yoffset="0" xadvance="46" page="0"/>
<char id="85" x="815" y="218" width="59" height="105" xoffset="0" yoffset="0" xadvance="55" page="0"/>
<char id="86" x="878" y="218" width="56" height="105" xoffset="0" yoffset="0" xadvance="52" page="0"/>
<char id="87" x="938" y="218" width="85" height="105" xoffset="0" yoffset="0" xadvance="81" page="0"/>
<char id="88" x="0" y="327" width="51" height="105" xoffset="0" yoffset="0" xadvance="47" page="0"/>
<char id="89" x="55" y="327" width="51" height="105" xoffset="0" yoffset="0" xadvance="47" page="0"/>
<char id="90" x="110" y="327" width="44" height="105" xoffset="0" yoffset="0" xadvance="40" page="0"/>
<char id="91" x="158" y="327" width="32" height="105" xoffset="0" yoffset="0" xadvance="28" page="0"/>
<char id="92" x="194" y="327" width="44" height="105" xoffset="0" yoffset="0" xadvance="40" page="0"/>
<char id="93" x="242" y="327" width="32" height="105" xoffset="0" yoffset="0" xadvance="28" page="0"/>
<char id="94" x="278" y="327" width="52" height="105" xoffset="0" yoffset="0" xadvance="48" page="0"/>
<char id="95" x="334" y="327" width="59" height="105" xoffset="0" yoffset="0" xadvance="55" page="0"/>
<char id="96" x="397" y="327" width="37" height="105" xoffset="0" yoffset="0" xadvance="33" page="0"/>
<char id="97" x="438" y="327" width="54" height="105" xoffset="0" yoffset="0" xadvance="50" page="0"/>
<char id="98" x="496" y="327" width="56" height="105" xoffset="0" yoffset="0" xadvance="52" page="0"/>
<char id="99" x="556" y="327" width="53" height="105" xoffset="0" yoffset="0" xadvance="49" page="0"/>
<char id="100" x="613" y="327" width="56" height="105" xoffset="0" yoffset="0" xadvance="52" page="0"/>
<char id="101" x="673" y="327" width="55" height="105" xoffset="0" yoffset="0" xadvance="51" page="0"/>
<char id="102" x="732" y="327" width="33" height="105" xoffset="0" yoffset="0" xadvance="29" page="0"/>
<char id="103" x="769" y="327" width="56" height="105" xoffset="0" yoffset="0" xadvance="52" page="0"/>
<char id="104" x="829" y="327" width="56" height="105" xoffset="0" yoffset="0" xadvance="52" page="0"/>
<char id="105" x="889" y="327" width="31" height="105" xoffset="0" yoffset="0" xadvance="27" page="0"/>
<char id="106" x="924" y="327" width="31" height="105" xoffset="0" yoffset="0" xadvance="27" page="0"/>
<char id="107" x="959" y="327" width="52" height="105" xoffset="0" yoffset="0" xadvance="48" page="0"/>
<char id="108" x="0" y="436" width="31" height="105" xoffset="0" yoffset="0" xadvance="27" page="0"/>
<char id="109" x="35" y="436" width="81" height="105" xoffset="0" yoffset="0" xadvance="77" page="0"/>
<char id="110" x="120" y="436" width="56" height="105" xoffset="0" yoffset="0" xadvance="52" page="0"/>
<char id="111" x="180" y="436" width="55" height="105" xoffset="0" yoffset="0" xadvance="51" page="0"/>
<char id="112" x="239" y="436" width="56" height="105" xoffset="0" yoffset="0" xadvance="52" page="0"/>
<char id="113" x="299" y="436" width="56" height="105" xoffset="0" yoffset="0" xadvance="52" page="0"/>
<char id="114" x="359" y="436" width="40" height="105" xoffset="0" yoffset="0" xadvance="36" page="0"/>
<char id="115" x="403" y="436" width="51" height="105" xoffset="0" yoffset="0" xadvance="47" page="0"/>
<char id="116" x="458" y="436" width="34" height="105" xoffset="0" yoffset="0" xadvance="30" page="0"/>
<char id="117" x="496" y="436" width="56" height="105" xoffset="0" yoffset="0" xadvance="52" page="0"/>
<char id="118" x="556" y="436" width="48" height="105" xoffset="0" yoffset="0" xadvance="44" page="0"/>
<char id="119" x="608" y="436" width="71" height="105" xoffset="0" yoffset="0" xadvance="67" page="0"/>
<char id="120" x="683" y="436" width="47" height="105" xoffset="0" yoffset="0" xadvance="43" page="0"/>
<char id="121" x="734" y="436" width="49" height="105" xoffset="0" yoffset="0" xadvance="45" page="0"/>
<char id="122" x="787" y="436" width="39" height="105" xoffset="0" yoffset="0" xadvance="35" page="0"/>
<char id="123" x="830" y="436" width="41" height="105" xoffset="0" yoffset="0" xadvance="37" page="0"/>
<char id="124" x="875" y="436" width="31" height="105" xoffset="0" yoffset="0" xadvance="27" page="0"/>
<char id="125" x="910" y="436" width="41" height="105" xoffset="0" yoffset="0" xadvance="37" page="0"/>
<char id="126" x="955" y="436" width="56" height="105" xoffset="0" yoffset="0" xadvance="52" page="0"/>
</chars>
</font>
The bitmap font .png file is compressed automatically and you can ajust various settings from the configuration object that is passed into the generator script. There are several examples available at github and npm to help you get started.
Happy coding and enjoy!
Stephan