Our Mascots Mascots
Tenshi-Oni Game Tenshi-Oni Game
Anime Shop Anime Store

Monday, October 20, 2014

How to Add GlyphDesigner Custom Bitmap Fonts To a Swift Spritekit Game


Back in June, Apple announced an entirely new programming language to us IOS developers; that language being Swift.  After coding Tenshi-Oni on and off since 2011 in Objective-C, I quickly came to like the new programming language since it felt more modern and easy to dive into. Swift has similarities to Python, Scala, AS3 & Javascript while supposedly almost matching the speed of a hardcoded C/C++ project; Apple claims it's .  As programmers, particularly game programmers, we want our games to be as fast as possible no matter how much we pack into a game scene; 60fps is the mantra and no, 30fps is not "cinematic".. it's a sign that somebody couldn't make fast enough code for a certain device.  Those of us that design the art assets also want to customize what goes on the screen as much as possible..this is where a tool like Glyph Designer comes into play.  Since Swift is so new... there wasn't any tutorials on how to use Glyph Designer with a Swift developed game in the SpriteKit framework.  After a weekend of puling out my hair and finding the solution.. I thought Id share it all with you...

In my game, Tenshi-Oni (yes a game still in development as of this post ^^;;), I've used the Glyph Designer program to make custom fonts.  Anyone familiar with Glyph Designer knows how wonderful of a tool it is to create beautiful bitmap fonts. Tenshi-Oni runs in the Cocos2D framework and Glyph Designer works like a charm in it.

To use a custom, stylized font in Cocos2D, you simply...

  1. Export a .fnt file, which outputs a .png to which the .fnt file uses to parse through
  2. Create a CCLabelBMFont with the fntFile NSString parameter matching the .fnt file name 
  3. and it's ready to use with that CCLabelBMFont


This also works well in the Sparrow Framework from what I understand.

...but for the SpriteKit Framework... things get a little bit more invovled...

Let's backtrack and say you wish to just use a custom (non bitmap) font in SpriteKit. As of IOS 8, you have to:

  1. Import the font to the project (in either the .otf or .ttf format)
  2. In your project's info.plist file, you have to add a field titled Fonts provided by application
  3. On item 0, create a String matching your font's name and the .otf or .ttf extension ie: "yourfont.ttf"
Great, this creates a custom font that you maybe got from say fontsquirrel.com or made yourself...

but... it doesn't quite help with the actual stylizing of that font.  

For me, and I'd imagine other programmer/designers, I found that SpriteKit doesn't do a great job of customizing a font's look.  You can maybe hardcode two fonts on top of eachother to give the effect of a dropshadow or stroke...but it never seems to look right.  I feel I'd rather have more control of the font's look and feel than just slapping in a font that I can only change it's color or size.  A well stylized font not only catches the player's attention but becomes easier to designer around as you don't have to worry about say.. what background color is behind a "SCORE" text.  Always remember this design rule when it comes to text.  Using a solid color font might look great on a few different color backgrounds... but what if you create new levels with different color schemes?  You'd have to code that font to change color and doing so might change the whole theme you had already established.  At least, that's how I feel as a designer in addition to a programmer.

How to work with Glyph Designer Bitmap Fonts (Before Swift / in Objective-C)

Before Swift, Glyph Designer's creators at 71squared already came up with some great helper classes to make up for SpriteKit's inability to use their .fnt methodology.  The process for anyone coding in Objective-C was pretty simple..
  • Import those custom made classes ( SSBitmapFont & SSBitmapFontLabelNode) to your project
  • Build your fonts in Glyph Designer and exporting them as .skf(SpriteKit) and/or .skf(SpriteKit@2x) depending on the resultions you are working with. Note: as of this post, Gylph Designer, does not yet have support for the iPhone 6 Plus's @3x resolution.
  • doing so creates a .skf file and a texture atlas folder with every character as their own .png. (this is akin to the .fnt/.png control/output used in Cocos2D but texture atlases tend to be much faster formats anyways since the 
  • Make sure to import the new header files into the class you would need to assess those objects with
  • Create the SSBitmapFont object as described on their download page: 

NSString *path = [[NSBundle mainBundle] pathForResource:@"myFont"
                                        ofType:@"skf"];
NSURL *url = [NSURL fileURLWithPath:path];
NSError *error;
SSBitmapFont *bitmapFont = [[SSBitmapFont alloc] initWithFile:url
                                                 error:&error];

if (error)
{
    NSLog(@"%@ : %@", error.domain, error.localizedDescription);
    return nil;
}


  • Create the SSBitMapFontLabel objects from this font:

SSBitmapFontLabelNode *myLabel = [bitmapFont nodeFromString:@"Hello World!!"];
[self addChild:myLabel];
  • and maybe use some class functions of SSBitMapFontLabel to align your font
myLabel.horizontalAlignment = SSBMFLabelHorizontalAlignmentModeCenter;
myLabel.verticalAlignment = SSBMFLabelVerticalAlignmentModeLeft;

For people coding in Objective-C... great.. it's works fine.  But what about doing this in Swift?!?

HOW TO USE GLYPH DESIGNER FONTS IN SWIFT...

At first, I thought about rewriting the entire SSBitMapFont and SSBitMapFontLabel classes in Swift... but unfortunately you only have access to their interface files (.h files) and not their (.m) implementation files; it's all packed into libSSBitmapFont.a since I'd imagine the implementation code (though probably still obtainable) is proprietary code.  

As of the date of this posting, 71squared has yet to make these classes in Swift... so, how do you use the code? Simple: Accessing Objecive-C classes via a Bridging Header.  In short, a bridging header is a .h interface file that lets you use Objective-C and Swift in the same project.  The file is usually named YourProjectName-Bridging-Header.h

How do you use it in a mostly Swift project?(Like my game PikiPop seen above) 
Again, very simple... add the import statements to the file exactly like you would add them in an Objective-c project. ie:

#import "SSBitmapFont.h"
#import "SSBitmapFontLabelNode.h"


That's it! That is all my PikiPop-Bridging-Header.h file has and now my entire Swift project can use SSBitmapFont and SSBitmapFontLabelNode objects


Now, you are not out of the woods yet. You still need to create your SSBitmapFont object to then be used by SSBitmapFontLabelNodes.


Here's how you rewrite implementation of these objects in Swift:


To create the SSBitmapFont object (remember to have your .skf file(s) and texture atlases imported into your project at this point) here's how I do it in PikiPop.  First I created a function that returns an SSBitmapFont object.  This is the swift version of how 71Squared did it in their demo file.

class func bitmapFontForFile(filename:String) -> SSBitmapFont{
        // Generate a path to the font file
        let path = NSBundle.mainBundle().pathForResource(filename, ofType: "skf")!
        //assert(path.isEmpty, "Could not find font file")
        // Create a new instance of SSBitmapFont using the font file and check for errors
        let errorPointer = NSErrorPointer()
        let url = NSURL.fileURLWithPath(path)
        let bitmapFont = SSBitmapFont(file: url, error: errorPointer)
        //assert(errorPointer != nil, "\(errorPointer.memory) : \(errorPointer.debugDescription)")
        return bitmapFont
    }

Do note that I made this a class function since I'm using this function during the game's asset loading screen at it's initial dispatch...thus I needed to make this a function of (in this case) my HUD.swift class. I also use global shared variables as storage of this data; this is to only allocate memory once for these font objects instead of calling them over and over again. You don't have to do this but Swift, unlike C/C++/Objective-C easily makes true full copies of objects (not just references) and I don't want to inadvertently cause ARC to do a massive garbage collect nor bog the CPU/Stack by creating another hard copy of something I can just reference to.

 Also note that as of this post I didn't create the assert warnings well. They seemed to have been firing off no matter if the file URL was right or wrong. I'd advise anyone using this to maybe complete that aspect so to better catch errors than what I did here in commenting them out.


Next, create the SSBitmapFont object.  Here's how I did it for the "combo_text" font I made... seen in the picture at the top of this post.


let comboBitMapFont:SSBitmapFont = bitmapFontForFile("combo_text")

Then I finally create the SSBitmapFontLabelNode that uses this font and add it to my HUD object (which is a child of my game's scene)


let comboTextNum = comboBitMapFont_.nodeFromString("x\(comboCount)")
comboTextNum.position = CGPointMake(currentScene.frame.size.width * 0.47, currentScene.frame.size.height * 0.8)
self.addChild(comboTextNum)


and there it is.  That's the "X3" you see in the photo up top.  The "Combo x" uses another font object and so does the "SCORE" text.  Also note that the bitmapFontForFile("combo_text") line will use either the .skf file or the .skf@2x file based on which resolution the player is using on their device.  So, there's no need to create separate SSBitmapFont objects for each resolution.

Anyways, I hope this helps allow you to add much better looking fonts into your Swift/SpriteKit games and apps ^_^



Post a Comment

 
Copyright © 2002- Chucks Anime Shrine
Re-Design by Chuck Gaffney | BTT