Unity3D for iOS: “IndexOutOfRangeException: Array index is out of range” Error While Adding a New BMP Font for UIToolkit


	var font1Txt:UIText = new UIText( textToolkit, "interstatereg", "interstatereg2x.png" ); 

/*
IndexOutOfRangeException: Array index is out of range.
UIText.loadConfigfile (System.String filename) (at Assets/Plugins/UIToolkit/UIElements/UIText.cs:135)
UIText..ctor (.UIToolkit manager, System.String fontFilename, System.String textureFilename) (at Assets/Plugins/UIToolkit/UIElements/UIText.cs:86)
Instructions+$animateIn$18+$.MoveNext () (at Assets/Scripts/MyScriptFile.js:42)
*/

In UIText.cs line 135 contains the _fontDetails array (defined in the constructor to hold 256 items or id’s from 0-255). Also in line 135 “idNum” being used to specify the array’s index during the loop:

...
_fontDetails = new UIFontCharInfo[256];
...
_fontDetails[idNum].charID = new int();

To get more info, I added a log statement to UIText.cs on a little before line 135 (mentioned in the error above) like so:

Debug.Log("++++ idNum = " + idNum);

This showed me the exact line from the .fnt file was causing the problem, “char id=8482″:

/* //from the Console: 
++++ idNum = 8482
UnityEngine.Debug:Log(Object)
UIText:loadConfigfile(String) (at Assets/Plugins/UIToolkit/UIElements/UIText.cs:132)
UIText:.ctor(UIToolkit, String, String) (at Assets/Plugins/UIToolkit/UIElements/UIText.cs:86)
$:MoveNext() (at Assets/Scripts/MyScriptFile.js:42)
*/

//from .fnt (.txt) file: 
char id=8482   x=145     y=83     width=20     height=11     xoffset=0     yoffset=5    xadvance=18     page=0  chnl=0 

8482 looks like the “id” for the trademark “TM” character & UIText.cs can’t use it since the _fontDetails array is defined to only use the 0 – 255 range (see constructor method in UIText.cs).

ASCII v. Unicode

I don’t fully understand the reason why my attempt at adding a “TM” character resulted in char id of 8482 but I’m guessing Bitmap fonts via UIToolkit work with ASCII characters, hence the 0 – 255 range, while my computer used Unicode (which goes well beyond 0-255) when I typed “TM” into Hiero’s “Sample text” text box.

I was hesitant to click the ASCII button in Hiero to add “TM” because every time I do that Hiero grinds to a halt and basically stops working. So, replacing the Unicode “TM” with Hiero is doable but takes forever on any of my machines (including a 2.7 GHz Intel Core i5 iMac w/ 8G RAM). May be you’ll have better luck with low priced alternative software on Mac or Angelcode on PC (free).

Copy/Pasting Text from Photoshop

I got a similar “IndexOutOfRangeException: Array index is out of range” error when copy/pasting a paragraph from a .PSD file:

IndexOutOfRangeException: Array index is out of range.
UIText.drawText (.UITextInstance textInstance, Single xPos, Single yPos, Single scale, Int32 depth, UnityEngine.Color[] color, UITextAlignMode instanceAlignMode, UITextVerticalAlignMode instanceVerticalAlignMode) (at Assets/Plugins/UIToolkit/UIElements/UIText.cs:235)
UIText.addTextInstance (System.String text, Single xPos, Single yPos, Single scale, Int32 depth, UnityEngine.Color[] colors, UITextAlignMode alignMode, UITextVerticalAlignMode verticalAlignMode) (at Assets/Plugins/UIToolkit/UIElements/UIText.cs:579)
UIText.addTextInstance (System.String text, Single xPos, Single yPos, Single scale, Int32 depth, Color color, UITextAlignMode alignMode, UITextVerticalAlignMode verticalAlignMode) (at Assets/Plugins/UIToolkit/UIElements/UIText.cs:569)
Instructions+$animateIn$12+$.MoveNext () (at Assets/Scripts/Instructions.js:57)

Pretty sure it’s the ASCII v. Unicode issue again. In this case, characters like curly quotes caused the error.

Unity3D for iOS: Switching From GUI to UIToolKit for Text & Menus to Improve Performance

UIToolkit is an open source Unity plugin specifically created for optimized performance on mobile devices (via reduced number of draw calls). Here’s a good summary of why Unity3D’s default GUI is not a good choice for mobile devices, key ones being:

  • Excessive draw calls…
  • Draws excessive processing power when using GUI, even worse with GUILayout… In-game GUI still requires high performance, and the overhead of calling GUI, or GUILayout are just too big to overlook even on today‚Äôs high-powered phones.

Setting Up

1. Download the .unitypackage from UIToolkit’s downloads page on GitHub.

2. I mostly followed the developer’s instructions, using a mix of:

  • “Setup” instructions on their Github page
  • the two intro videos
  • the code examples in the demo scenes that come with the package download (Github).

You can also try this quick “how to” from UnityAnswers. Just remember, to add UIToolkit elements via code you also have to create a public var in your script & use the Inspector to assign a one of the UIToolkit instances under the UI GameObject in your Hierarchy.

NOTE: don’t expect TweenLite or iTween style performance from UIToolkit’s built-in animation engine. Also note, UIToolkit-based UI can’t be animated with iTween, as far as I’ve seen.

Make the texture atlases for your buttons

Created 2 texture maps for the buttons containing Up and Down states for the 4 buttons using the free version of TexturePacker. The 2nd texture map had the “2x” added to each file name, for iPhone retina display. CORRECTION: When creating the individual graphic slices in GIMP or Photoshop, make sure to name the regular and “2x” versions of the same slice the same exact file name (no “2x”). This will ensure that the respective .txt JSON files generated by TexturePacker will have the 2 sizes named the same and as long as the retina sprite sheet .png file generated by TexturePacker has the “2x” in it’s file name, UIToolkit will grab the correct image size automatically.

Note: the free version of Texture Packer won’t allow you to efficiently size the image to minimize empty space.

UPDATE, 08.09.2012: Unity3D doesn’t allow TexturePacker Pro’s “Allow free sizes” checkbox to do it’s thing. It’s tempting to use it because it cuts the overall size of the sprite sheet but looks like Unity ends up flipping out and stretches the resultant image, forcing it into value it recognizes like 256, 512, 1024, 2048.

UPDATE, 08.10.2012: UIToolkit currently doesn’t support TexturePacker Pro’s rotated sprites (“Allow rotation” checkbox). Looks like someone tried to add that functionality but didn’t have time to finish.

Convert fonts to bitmaps (.png and .fnt files) for use with TexturePacker and Unity: AngelCode’s BMFont on Windows

Converted my fonts to Bitmap font files with .fnt extension. Hiero, the free bitmap font conversion tool for Mac has some limitations (like it doesn’t allow you to turn off antialiasing for small copy fonts). There’s a free Windows tool that does called Angelcode Bitmap Font Generator. Glyph Designer is relatively inexpensive alternative.

I first tried using AngelCode’s BMFont tool on Windows XP via Parallels and it generated these two .png & a .fnt files for my font:

Prior to Unity import, I renamed .fnt files to .txt.

Here’re some screenshots of Font and Export settings I used in Angelcode’s bitmap font tool (click to for larger image):

After importing the .png, .txt (.fnt) and .txt (JSON) files into an empty Unity scene and setting it up correctly, I got no errors in the Console and no fonts on screen (link to .unitypackage of this project).

I suspect the problem is in the font files and not in my UIToolkit or Project setup because I also included the Text demo files from UIToolkit in the .unitypackage above. When I tried to simply switch the font to the “prototype” example and it’s associated texture in Inspector, everything worked. It’s only when I switched the .fnt and texture from Angelcode that the text failed to show up. UPDATED, 04.09.2012: After taking a look at UIText.cs, I realized I was wrong – the problem was in the way I was calling the UIText constructor. For correct usage, see the mainMenuScript.js code example below.

Convert fonts to bitmaps: Hiero on Mac

Hiero ran fine the first time for the standard fonts version, however when I tried to change the settings for the “2x” version of the font it got super sluggish on me. I reinstalled the Hiero .jnpl numerous times, restarted my system, etc., to no avail. Hiero ran super slow 1 minute or so after launch on OS X 10.6.8, java version “1.6.0_31″, JRE build 1.6.0_31-b04-413-10M3623. UPDATE: after looking into it more, it seems like the main performance culprit with Hiero is the ASCII button under the “Sample Text” text box. When, instead of hitting that button, I manually copy/pasted in some of the extra characters I needed, the freezing & sluggishness issues didn’t happen.

The PNG created from Hiero had the text upside down, so I had to open the PNG in Photoshop & do a Edit > Transform > Flip Vertical to fix that.

Still same problem – no Console errors and no text showing up on screen in Unity. Here’s the .unitypackage that uses the Hiero fonts. Now fixed, see below.

GlyphDesigner is a good not-free alternative to Hiero on Mac. It’s around $30.

Make texture atlases for your fonts with TexturePacker

Created 2 more texture maps for Fonts using the .png files created by your bitmap fonts program. One for each device resolution (standard & retina), using Unity’s “2x” naming convention for the retina sprite sheet’s name. Basically, you need this step to generate the JSON formatted .txt files that will serve as a map for the .png that contains all of the font characters.

NOTE: When creating the individual graphic slices in GIMP or Photoshop, make sure to name the regular and “2x” versions of the same slice the same file name. This will ensure that the respective .txt JSON files will have the 2 sizes named the same and as long as the retina sprite sheet .png file generated by TexturePacker has the “2x” in it’s file name, UIToolkit will grab the correct image size automatically.

If you used Hiero – your font .png files will be flipped upside down. Just open them in Photoshop & do a vertical flip.

Import .txt (.fnt), .png (font texture atlas) and .txt (JSON texture atlas info) into a Unity project

Here’s a working UIText .unitypackage for iOS and one w/ Build Settings changed to Android (still developed on Mac). NOTE: If you’re on Windows, the iOS sample might not import because you’re missing the iOS SDK (blame Steve Jobs). I included the Android version – hopefully it will work for Windows users (let me know in the comments, either way). This sample is using two UIToolkit objects under one UI parent, including a UIText instance. Compare the mainMenuScript.js with it’s counterpart in earlier unsuccessful attempt for iOS.

If the font shows up with vertical bleeding at the top of the letters and the bottom of the letters being cut off, here’s an easy fix. Open the gunplayDemoSheet2x.txt (JSON) file and change the “y” value of the “frame” from 0 to 2.

"frame": {"x":0,"y":2,"w":1024,"h":321},

mainMenuScript.js

#pragma strict

var textToolkit2:UIToolkit;
var buttonToolkit:UIToolkit;

function Start() {

	//this gives no errors BUT fonts don't show up...: 
	//var text = new UIText( textToolkit2, "gunplayDemoSheet", "gunplay.png" ); //UIText(obj, "name_of_texture_in_Resources_folder", 'line 3 in .fnt file')	
	
	//set Game panel to iPhone 4G Tall (640x960): 
	var text = new UIText( textToolkit2, "gunplay", "gunplay.png" ); //UIText(obj, "name .fnt (.txt) file in Resources folder", 'line 3 in .fnt file')	
		
	var x = UIRelative.xPercentFrom( UIxAnchor.Left, .1f ); //0.1f = 10% from Left
	var y = UIRelative.yPercentFrom( UIyAnchor.Top, .05f ); //0.5f = 5% from Top
	text.addTextInstance( "Finally some \ntext. Oops, there's \nbleeding. Need to \nfix the \ntexture map.", x, y );	
	

	var newGameBtn = UIButton.create( buttonToolkit, "playAgainUp.png", "playAgainDown.png", 0, 0 );
	newGameBtn.positionFromTopLeft(.5f, .2f); 	
	newGameBtn.highlightedTouchOffsets = new UIEdgeOffsets( 30 );

}

Here’re the settings screenshots to hook everything up (NOTE: In the screenshots below and code sample above I’m using a True Type font called Gunplay; in the AngelCode and Hiero screenshots I was using Gotham – sorry, if that’s confusing, I haven’t had the time to update those.):

Here’s an example of the UI parent object set up with more than one child. UI > “UIToolkit – buttons” object:

UI > “UIToolkit – text” object: