4
\$\begingroup\$

When I create a "Custom Font" in Unity 4.6.1, I get this:

enter image description here

"Ascii Start Offset" indicates which character is first in the font. I've set it to 48 (the zero character) by hand, and my custom font works fine just for numbers.

But I'm creating these fonts at runtime as a build step. I access "Character Rects" through Font.characterInfo in code:

font.characterInfo = infoList.ToArray();

So the names don't necessarily align. But I can't figure out how to change "Ascii Start Offset" at runtime; none of the available members of Font class seem to be related. Is this possible?

\$\endgroup\$
5
\$\begingroup\$

"Ascii Start Offset" is a Unity internal field. It is not available in any of the Managed(C#) DLL's, so you can not use reflection to get to it. The "Ascii Start Offset" field is named m_AsciiStartOffset in Unity's internal representation of the Font class.

Since the "Ascii Start Offset" is shown in the inspector, I knew it had to be available using a Custom Editor. All of the properties shown, are available to the custom editor via Editor.serializedObject. I figured this out using a reflection tool and diving into what Unity does behind the scenes when drawing fields. There was, of course, more churn before I figured it out.

Luckily there is Editor.CreateEditor so you can make your own custom editor on the fly. Normally Custom Editors are made with a decorator (you can see an example below the horizontal break).

You can't use this snippet in game runtime, but it works just fine anywhere else in a editor script.

public void SetAsciiStartOffset(Font font, int asciiStartOffset)
{
    Editor editor = Editor.CreateEditor(font);

    SerializedProperty startOffsetProperty = editor.serializedObject.FindProperty("m_AsciiStartOffset");
    startOffsetProperty.intValue = asciiStartOffset;

    // Save off all of the values to Unity's internal structure
    editor.serializedObject.ApplyModifiedProperties();
}

Here is a full Unity Editor Window script that uses the snippet above to change "Ascii Start Offset". The XML->Font code is by Almo(question asker).

GitHub Gist: GenerateCustomFontWindow.cs

You can access the editor window by going to Window -> Generate Custom Font:


This following script will loop through all the properties/fields shown in the Unity Inspector and print out the Display name, actual internal name, and its type. It is just to show how I found the variable name, knowing it is shown in the inspector.

using UnityEngine;
using UnityEditor;

// Custom Editor of Font: http://docs.unity3d.com/ScriptReference/Font.html
[CustomEditor(typeof(Font))]
public class CustomFontEditorPropertyLogger : Editor {


    // This will loop through all the properties/fields shown in the Unity Inspector
    // and print out the Display name, actual internal name, and its type
    public override void OnInspectorGUI()
    {
        GUILayout.Label("Woah, Custom Font Inspector Script!");

        // Basically From `UnityEditor.FontInspector` which is an internal method
        UnityEngine.Object[] objArray = base.targets;
        for (int i = 0; i < (int)objArray.Length; i++)
        {
            if (objArray[i].hideFlags == HideFlags.NotEditable)
            {
                return;
            }
        }
        //base.DrawDefaultInspector();

        // You can find individual properties if you know their internal name via `FindProperty`
        //this.serializedObject.FindProperty("m_AsciiStartOffset");

        // This is essentially what `base.DrawDefaultInspector();` (commented out above) does
        // From `UnityEditor.Editor.DrawDefaultInspector()`
        SerializedProperty propertyIterator = this.serializedObject.GetIterator();
        for (bool i = true; propertyIterator.NextVisible(i); i = false)
        {
            Debug.Log(propertyIterator.displayName + ": " + propertyIterator.name + " of type: " + propertyIterator.type);

            EditorGUILayout.PropertyField(propertyIterator, true, new GUILayoutOption[0]);
        }
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.