Rex Rhino

Ludei Cocoonjs XML / bitmap font workaround?

Recommended Posts

Hey guys,

 

I'm a bit confused: I thought since the pixi guys apparently didn't merge the above fix, yet, I'd just go and throw it in myself. But I tried to locate the PIXI.BitmapFontLoader within the pixi.js (not minified) that comes with Phaser (2.0.4) or even within the phaser.js file but couldn't find anything.

 

What am I missing? Or rather: How would I have to approach this?

 

I thought I'd be less hassle than converting XMLs to JSONs and stuff.

Share this post


Link to post
Share on other sites

I don't know if that fixed was merged in or not, but I am using the latest dev version of pixi, with the latest version of cocoonjs, and I am able to use xml bitmap fonts without any issues. I have not made any fixes or changes or workarounds, it just seems to work OK now.

 

My guess is that Ludei have fixed the problem on their end.

 

Edit: Oops, this is an old thread, and I wasn't paying attention close enough when I received this in my email... it works with pixi and cocoonjs, but I haven't yet tested with phaser. I apologize for posting erroneous information. Sorry guys!

Share this post


Link to post
Share on other sites

I'm a bit confused: I thought since the pixi guys apparently didn't merge the above fix, yet, I'd just go and throw it in myself. But I tried to locate the PIXI.BitmapFontLoader within the pixi.js (not minified) that comes with Phaser (2.0.4) or even within the phaser.js file but couldn't find anything.

 

What am I missing? Or rather: How would I have to approach this?

 

I thought I'd be less hassle than converting XMLs to JSONs and stuff.

 

They're not included because Phaser doesn't use any of the Pixi asset loading methods at all.

Share this post


Link to post
Share on other sites

@Rex Rhino no worries. That's good to know! :)

@rich: That's unfortunate. Since this topic is filed under "Phaser" I was hoping the fixes were all Phaser related. But now I'm pretty stuck: I tried to apply the DOMishParser approach and it doesn't seem to work with 2.0.4 anymore. It blew up in my face trying to execute a getAttribute() call on the "info" object. I used the data provided by @GregP but still it wouldn't even finish parsing. I attempted to fix it but without any luck so far.

Is anything in the works to allow loading JSON data with bitmap fonts for Phaser?

Share this post


Link to post
Share on other sites

Hey @Starnut, I use a modified version of the DOMishParser:

(function (cocoonjsphaser) {    cocoonjsphaser.utils = {        fixDOMParser: function () {            window.DOMParser = DOMishParser;        }    };    function DOMishParser() { }    DOMishParser.prototype.parseFromString = function (data) {        return new DOMishObject(JSON.parse(data));    };    function DOMishAttributes() { }    DOMishAttributes.prototype.getNamedItem = function (name) {        return {            nodeValue: this[name] || null        };    };    function makeDOMishObject(data) {        return new DOMishObject(data);    }    function DOMishObject(data) {        this.attributes = this.convertContent(data);        this.length = Object.keys(this.attributes).length;    }    DOMishObject.prototype.documentElement = document;    DOMishObject.prototype.convertContent = function (obj) {        var attributes = new DOMishAttributes(),            prop;        for (prop in obj) {            if (obj[prop] !== null && typeof obj[prop] === 'object') {                attributes[prop] = Array.isArray(obj[prop]) ?                    obj[prop].map(makeDOMishObject) : new DOMishObject(obj[prop]);            } else {                attributes[prop] = obj[prop];            }        }        return attributes;    };    DOMishObject.prototype.getElementsByTagName = function (name) {        return this.attributes[name] ?            Array.isArray(this.attributes[name]) ?            this.attributes[name] : [this.attributes[name]] : [];    };    DOMishObject.prototype.getAttribute = function (name) {        return this.attributes.getNamedItem(name).nodeValue;    };}(window.cocoonjsphaser = window.cocoonjsphaser || {}));
if (navigator.isCocoonJS) {    cocoonjsphaser.utils.fixDOMParser();}

Share this post


Link to post
Share on other sites

Hey everyone,

 

it all works perfectly for me, now (Phaser 2.0.4, CocoonJS 2.0, iOS 7.1.1).

 

Since I found it a bit hard to collect all of the pieces from across the forum and the web, here's a quick guide with an improved conversion script that might help anyone still dealing with this issue:

 

1. Create the bitmap font with any tool that provides XML based BMFont output. Personally I used bmGlyph for Mac, but it should work fine with Littera (free web service) or GlyphDesigner as well. Angel Code's Bitmap Font Generator for Windows.

 

2. I use the modified DOMish parser suggested by @Hsaka in my index.html right before I create the Phaser game instance.

 

3. I pick the file-format within the preloader depending on whether it runs under CocoonJS or not and attach it to the file names like so:

var fileFormat = (this.game.device.cocoonJS) ? '.json' : '.xml';this.load.bitmapFont('titleFont', 'assets/fonts/title-font.png', 'assets/fonts/title-font' + fileFormat);

4. I rename the font data files from .fnt to .xml and convert them using a modified version of @Hadan's nodejs script (you need nodejs installed for this). I improved it so it converts all .xml files within a given folder to .json files. The command line call now looks like this (assuming it lies at the top level of your project):

$ node fontConverter.js assets/fonts/

If you don't pass a folder, it converts all files within the folder the script lies in.

 

Moreover, you can now pass it a string to filter for, if you don't want all of the files in the given folder to be converted. The following call converts all XML files in the folder assets/fonts/ that have 'title' in their names:

$ node fontConverter.js assets/fonts/ title

And here is the above mentioned script from the fontConverter.js file:

var fs = require('fs'),    xml2js = require('xml2js');// init the file parservar parser = new xml2js.Parser({ explicitRoot: false, mergeAttrs: true, explicitArray: false });// init the target directoryvar targetDir = __dirname +  "/";// check if a target directory was passedtargetDir += (process.argv.length > 2) ? process.argv[2] : '';// check if a file filter was passedvar fileFilter = (process.argv.length > 3) ?process.argv[3] : null;console.log('\nLooking for files in', targetDir);if (fileFilter) console.log("... the names of which contain the string '"+fileFilter+"'\n");var parseNextFile = function(files){        if (files && files.length > 0)    {        // get the first file in the list        var file = files.shift();        // split off pure file name without format ending        var fileName = file.substr(0, file.indexOf("."));        // read the file        fs.readFile(targetDir + file, function(err, data)        {            // parse the file's content            parser.parseString(data, function(err, result)            {                // keep only the relevant information                result.char = result.chars.char;                delete result.chars;                // turn it into a JSON string and write it into to a .json file with the same name as the XML                fs.writeFile(targetDir + fileName + ".json", JSON.stringify(result), function(err) {                    if (err)                     {                        console.log(err);                    }                    else                    {                        console.log("Converted file", file, "to", fileName + ".json");                        // parse the next file                        parseNextFile(files);                    }                });            });         });    }    else    {        console.log("Conversion complete...\n");    }};// check if the target directory existsif (!fs.existsSync(targetDir)){    console.log(targetDir, "does not exist!");}else{    // read all files from the target directory    var files = fs.readdirSync(targetDir);    var n = files.length,        i;    for (i = n; --i >= 0;)    {        var file = files[i];        var index = file.indexOf(".xml");        // only process XML files that match the given filter        if (index === -1 || (fileFilter && file.indexOf(fileFilter) === -1))        {            // delete the file entry            files.splice(i, 1);        }    }    if (!files || files.length === 0)    {        console.log("No files found!");    }    else    {        // parse all found files        parseNextFile(files);    }}

It's a mix of synchronous and asynchronous calls, cause I didn't manage to let it all asynchronously and I'm a little short on time. Not perfect but it does the trick.

 

Thanks to everyone who shared information on this. You're awesome!
Without you guys, I would've lost days and most probably my mind. :)

 

EDIT: Just noted there was some duplicate check in the code and cleaned it all up a bit more.

Share this post


Link to post
Share on other sites

Here's also a solution which works with the original XML font files: https://github.com/videlais/xml-for-cocoonjs

 

Here's the script file which I tried in my project: https://raw.githubusercontent.com/videlais/xml-for-cocoonjs/master/src/xml-for-cocoonjs.js

 

Worked like magic :)

 

...Although, a JSON bitmap loader in Phaser/PIXI itself would still be pretty sweet. 

Share this post


Link to post
Share on other sites

Hi, I'm sorry if this is a stupid question, I'm pretty new to this whole thing... but where do I write the fixed DOMishParser?

I've currently written it in it's own file and then I've done this in index.html:

 

if (navigator.isCocoonJS) {    	cocoonjsphaser.utils.fixDOMParser();}

and then in my preload:
 

var fileFormat = (this.game.device.cocoonJS) ? '.json' : '.xml';this.load.bitmapFont('bitFont', 'fonts/bitFont.png', 'fonts/bitFont' + fileFormat);

but I get an error when I run it in the launcher:
"JavaScript Exception (line:13 Tag: 'load'): Error:Phaser.Loader.Invalid XML given"

What have I done wrong? Does that mean I haven't probably changed the loader or hasn't it been converted to json correctly? 

Share this post


Link to post
Share on other sites

@Toknos

 

I pasted the DOMish parser code right before creating the game instance within the index. I didn't put it into a file of it's own. It looks like this:

<script type="text/javascript">(function (cocoonjsphaser) {    cocoonjsphaser.utils = {        fixDOMParser: function () {            window.DOMParser = DOMishParser;        }    };    //... rest of the implementation}(window.cocoonjsphaser = window.cocoonjsphaser || {}));(function () {    // I use this HTML file for CocoonJS only, so no extra check necessary.    cocoonjsphaser.utils.fixDOMParser();    //... check for width and height.    var game = new Phaser.Game(width, height, Phaser.CANVAS, '');       //... declare states and start Boot state.})();</script>

Both scripts (haden's and my adaption) only work with XMLs in BMFont format. So either use the BMFont tool (Windows) directly to create them or use a tool that produces equivalent (e.g. bmGlyph on Mac) output.  Then run the script to convert the XMLs. I'm not sure but I think I remember Littera output to not be compatible.

 

Also: make sure, your cocoonJS checks works and returns "true" under CocoonJS. If you don't use Phaser.States in your project, but instead have all the code in one file, you may have to omit 'this.' in 'this.game.device.cocoonJS' in order to make it work - but then again your load call shouldn't work either, so maybe you are using states - but I thought I'd just mention it.

 

Let us know if any of this helped.

Share this post


Link to post
Share on other sites

I use Phaser 2.0.7

Is there any solution for Literra fonts?
When I try to use it with CocoonJS I get error:

JavaScript Exception ( Tag: 'load'): Error:Phaser.Loader. Invalid XML givenat Phaser.Loader.xmlLoadComplete (script/phaser.js:48365:19)at XMLHttpRequest._xhr.onload (script/phaser.js:48047:33)

And if not, what the easiest way to use custom fonts without any hacks?

Share this post


Link to post
Share on other sites

I still am unable to get the workaround to work posted here: http://www.html5gamedevs.com/topic/2312-ludei-cocoonjs-xml-bitmap-font-workaround/?p=37671

 

I am using Phaser 2.0.7 and testing with Cocoon 2.0.2 and 1.4.7. I test on my Note II. I run the code using the DOMishParser no matter what and it works in Chrome browser on my computer and on phone's browser (also Chrome). However, when I run the code in Cocoon's launcher, no text shows up.

 

I changed the code to

if (navigator.isCocoonJS || 1 == 1) {    cocoonjsphaser.utils.fixDOMParser();}var fileFormat = (navigator.isCocoonJS || 1 == 1) ? '.json' : '.xml';

in order to force the game to always use the DOM parser fix.

 

I use fontConverter.js to convert the xml file produced by bmGlyph and it works fine in browsers.

 

No errors are shown in the Cocoon debugger, no text shows up however.

Share this post


Link to post
Share on other sites

@zablockijj Hard to tell what's wrong if the debug console remains silent. If it failed to parse the JSON files you'd for sure get an error. Maybe the problem lies elsewhere?

I have to admin that I haven't tried Phaser 2.0.7, yet, but either way I'd stick with CocoonJS 2.0.2 (not 1.4.7). And I would make sure to avoid building potential traps with complicated checks that are supposed to return true anyways. Keep it simple and remove all potential trouble makers until it works ...

//if (navigator.isCocoonJS) {    cocoonjsphaser.utils.fixDOMParser();//}var fileFormat = '.json';//(navigator.isCocoonJS) ? '.json' : '.xml';

... and then slowly start commenting in the code again until it breaks.

 

 

@patmood thanks for the feedback. Glad I could help :)

Share this post


Link to post
Share on other sites

@zablockijj I've attached a bitmap font which works for me. It was created using bmfont. You could probably swap your font for this one and see if it works for you. If it works, you can compare the json and see if there are any differences. (Not allowed to upload json files so rename mecha.txt to mecha.json)

mecha.xml

post-1796-0-22181000-1406722746.png

mecha.txt

Share this post


Link to post
Share on other sites

EDIT: I solved my disappearing sprite and text problem. For whatever reason in Cocoon, adding the following line:

this.game.add.sprite(-200, -200, '');

fixed the problem.

 

 

ORIGINAL:

 

@Hsaka, you're bitmap font worked amazingly!! Thank you. I am running into the problem, however, where, in Cocoon only (not in my browser), the text is disappearing after a few seconds until a collision event between two entities occurs and updates the score.

 

What I find throughout my game is that depending on the order that I create sprites, text, etc in the create functions, those created in the latter portion of the create function for a game state will fail to be visible in Cocoon when I test. The sprite (or text) will exist and have its touch events and all, however, I cannot see them on the screen (i.e. they are invisible). THIS DOES NOT HAPPEN IN MY BROWSER.

 

Here is where I call the text:

create: function() {   ...stuff, other sprites are made...   scoreText = game.add.bitmapText(20, 20, 'mecha','Score: '+score, 30);   livesText = game.add.bitmapText(20, 50, 'mecha','Lives: '+lives, 30);},update: function() {   scoreText.setText('Score: '+score);   livesText.setText('Lives: '+lives);   // if a collision happens then call function that increments score of decrements lives}

I don't know why some sprites and text is disappearing after a few seconds of visibility.

Share this post


Link to post
Share on other sites

Sorry if this is a silly idea, but I thought it might be simpler for some cases than converting the font data to JSON.

 

How about loading the font as a spritesheet?

With fixed width fonts (for example pixel fonts) all you'd need is a text string with the order of characters like "abcdefghijklmnopqrstuvwxyz0123456789,.!?;:'()-+" to act as a lookup table, and of course you'd need a custom function to convert any string of text into a block of graphics on the screen.

 

Again apologies if this only makes sense to myself :)

Share this post


Link to post
Share on other sites

EDIT: solved this one, see next post :)

 

Hey @Starnut, I use a modified version of the DOMishParser:

 

Hey everyone,

 

it all works perfectly for me, now (Phaser 2.0.4, CocoonJS 2.0, iOS 7.1.1).

 

Since I found it a bit hard to collect all of the pieces from across the forum and the web, here's a quick guide with an improved conversion script that might help anyone still dealing with this issue:

 

Thank you both for sharing your solutions :) I would have never figured this out by myself.. However, I've implemented it, get no errors but the texts are not displayed. :(

 

I've added the DOMishParser from Hsaka and I've converted the .xml file to .json with this online tool (with "Prefix attributes " set to empty, and "JSON output indentation" to tab delimited) which as far as I can see gives the same result as the nodejs script, the resulting json file gives no errors when loading.

 

I've whittled it down to the bare minimum, all that my example code does (see github link below) is replace the DOMParser, replace .xml with .json in the preloader and display some texts. I've added my own test variable TEST_FONT_JSON which replaces the "if (navigator.isCocoonJS)" just so that I can test the code example in the Chrome desktop browser. When I set TEST_FONT_JSON=false it loads normally with the xml file and the texts are displayed fine. But when I set TEST_FONT_JSON=true then it loads the json file without any errors in the console but no text is displayed..

 

What am I doing wrong here?  :wacko: github code example:

https://github.com/BdR76/phaserbitmapfont

Share this post


Link to post
Share on other sites

@zablockijj I've attached a bitmap font which works for me. It was created using bmfont. You could probably swap your font for this one and see if it works for you. If it works, you can compare the json and see if there are any differences. (Not allowed to upload json files so rename mecha.txt to mecha.json)

 
I've taken a look at your mecha.txt as a reference and I've found the error in my example, it was in the json file structure. :) Apparently the json converter handled the char-section slightly different than the nodejs script. My chars section in the json file looked like this:
"chars": {    "count": "91",    "char": [        {            "id": "97",            etc

Instead of just this (so without an extra chars container): 

"char": [    {        "id": "97",        etc.

I've changed this manually and now it works :) Btw I also removed my whole kernings section, it doesn't seem to be used at all, at least I don't see any difference without it. The "pages" section in your mecha.txt is also a little different, but I've left my section as pages-page and that also seems to work.

 

 

But I hope it will work by default without any of this hacks soon  :)

Amen to that..

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.