在unity的开发过程中,为了实现更好的表现,经常要使用美术字体,记录下美术字体的制作流程。

首先,美术的同学会给一张制作好的美术字的图片,当然如果能直接给fnt文件就更省事了。

拿到图片后,将图片的spriteMode设置为Multiple,然后Sprite Editor进行图片区域的划分,把图片分成宽度高度一致的小图,

分享一个在unity中使用的图片切割的工具脚本:

/**
* UnityVersion: 2018.3.10f1
* FileName:     ImageSlicer.cs
* Author:       TYQ
* CreateTime:   2019/04/19 00:04:26
* Description:
*/
/*
* Author:
* Date:2019/01/30 10:24:22
* Desc:图集切割器 (针对Multiple格式的图片)
* 操作方式:选中图片,选择编辑器的 Assets/ImageSlicer/Process to Sprites菜单
*/
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
using System.Collections.Generic;
public static class ImageSlicer
{[MenuItem("Assets/ImageSlicer/Process to Sprites")]static void ProcessToSprite(){Texture2D image = Selection.activeObject as Texture2D;//获取旋转的对象string rootPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(image));//获取路径名称string path = rootPath + "/" + image.name + ".PNG";//图片路径名称TextureImporter texImp = AssetImporter.GetAtPath(path) as TextureImporter;//获取图片入口AssetDatabase.CreateFolder(rootPath, image.name);//创建文件夹foreach (SpriteMetaData metaData in texImp.spritesheet)//遍历小图集{Texture2D myimage = new Texture2D((int)metaData.rect.width,  (int)metaData.rect.height);//abc_0:(x:2.00, y:400.00, width:103.00, height:112.00)for (int y = (int)metaData.rect.y; y < metaData.rect.y + metaData.rect.height;  y++)//Y轴像素{for (int x = (int)metaData.rect.x; x < metaData.rect.x +  metaData.rect.width; x++)myimage.SetPixel(x - (int)metaData.rect.x, y - (int)metaData.rect.y,  image.GetPixel(x, y));}//转换纹理到EncodeToPNG兼容格式if (myimage.format != TextureFormat.ARGB32 && myimage.format !=  TextureFormat.RGB24){Texture2D newTexture = new Texture2D(myimage.width, myimage.height);newTexture.SetPixels(myimage.GetPixels(0), 0);myimage = newTexture;}var pngData = myimage.EncodeToPNG();//AssetDatabase.CreateAsset(myimage, rootPath + "/" + image.name + "/" +  metaData.name + ".PNG");File.WriteAllBytes(rootPath + "/" + image.name + "/" + metaData.name + ".PNG",  pngData);// 刷新资源窗口界面AssetDatabase.Refresh();}}
}

然后在同目录就能拿到切割好的小图了,这个图片可以在BMFont字体工具中导出fnt文件。

接下来,下载BMFont,BMFont下载地址:http://www.angelcode.com/products/bmfont/

字符ID:选中字符后可以看到字符id

点击Edit/openImage,可以选择导入图片,编辑图片,删除图片等。

字符编码可以直接查询,地址为:http://www.mytju.com/classcode/tools/encode_utf8.asp

在options中可以预览,导出设置,导出字体等,最后可以导出一张图片和一个fnt文件,这个文件在unity中不能直接使用,要转成fontsettings

在unity中新建一个CustonFont,新建一个材质,然后使用编辑器导出工具BMFontMaker进行字体的生成

将对应的4个文件填入,点生成字体,美术字就能使用了,这个编辑的拓展的代码如下:

//----------------------------------------------
//            NGUI: Next-Gen UI kit
// Copyright © 2011-2015 Tasharen Entertainment
//----------------------------------------------
using UnityEngine;
using System.Collections.Generic;
using System.Diagnostics;
/// <summary>
/// This improved version of the System.Collections.Generic.List that doesn't release the  buffer on Clear(),
/// resulting in better performance and less garbage collection.
/// PRO: BetterList performs faster than List when you Add and Remove items (although  slower if you remove from the beginning).
/// CON: BetterList performs worse when sorting the list. If your operations involve  sorting, use the standard List instead.
/// </summary>
public class BetterList<T>
{
#if UNITY_FLASHList<T> mList = new List<T>();/// <summary>/// Direct access to the buffer. Note that you should not use its 'Length'  parameter, but instead use BetterList.size./// </summary>public T this[int i]{get { return mList[i]; }set { mList[i] = value; }}/// <summary>/// Compatibility with the non-flash syntax./// </summary>public List<T> buffer { get { return mList; } }/// <summary>/// Direct access to the buffer's size. Note that it's only public for speed and  efficiency. You shouldn't modify it./// </summary>public int size { get { return mList.Count; } }/// <summary>/// For 'foreach' functionality./// </summary>public IEnumerator<T> GetEnumerator () { return mList.GetEnumerator(); }/// <summary>/// Clear the array by resetting its size to zero. Note that the memory is not  actually released./// </summary>public void Clear () { mList.Clear(); }/// <summary>/// Clear the array and release the used memory./// </summary>public void Release () { mList.Clear(); }/// <summary>/// Add the specified item to the end of the list./// </summary>public void Add (T item) { mList.Add(item); }/// <summary>/// Insert an item at the specified index, pushing the entries back./// </summary>public void Insert (int index, T item){if (index > -1 && index < mList.Count) mList.Insert(index, item);else mList.Add(item);}/// <summary>/// Returns 'true' if the specified item is within the list./// </summary>public bool Contains (T item) { return mList.Contains(item); }/// <summary>/// Return the index of the specified item./// </summary>public int IndexOf (T item) { return mList.IndexOf(item); }/// <summary>/// Remove the specified item from the list. Note that RemoveAt() is faster and is  advisable if you already know the index./// </summary>public bool Remove (T item) { return mList.Remove(item); }/// <summary>/// Remove an item at the specified index./// </summary>public void RemoveAt (int index) { mList.RemoveAt(index); }/// <summary>/// Remove an item from the end./// </summary>public T Pop (){if (buffer != null && size != 0){T val = buffer[mList.Count - 1];mList.RemoveAt(mList.Count - 1);return val;}return default(T);}/// <summary>/// Mimic List's ToArray() functionality, except that in this case the list is  resized to match the current size./// </summary>public T[] ToArray () { return mList.ToArray(); }/// <summary>/// List.Sort equivalent./// </summary>public void Sort (System.Comparison<T> comparer) { mList.Sort(comparer); }
#else/// <summary>/// Direct access to the buffer. Note that you should not use its 'Length'  parameter, but instead use BetterList.size./// </summary>public T[] buffer;/// <summary>/// Direct access to the buffer's size. Note that it's only public for speed and  efficiency. You shouldn't modify it./// </summary>public int size = 0;/// <summary>/// For 'foreach' functionality./// </summary>[DebuggerHidden][DebuggerStepThrough]public IEnumerator<T> GetEnumerator (){if (buffer != null){for (int i = 0; i < size; ++i){yield return buffer[i];}}}/// <summary>/// Convenience function. I recommend using .buffer instead./// </summary>[DebuggerHidden]public T this[int i]{get { return buffer[i]; }set { buffer[i] = value; }}/// <summary>/// Helper function that expands the size of the array, maintaining the content./// </summary>void AllocateMore (){T[] newList = (buffer != null) ? new T[Mathf.Max(buffer.Length << 1, 32)] :  new T[32];if (buffer != null && size > 0) buffer.CopyTo(newList, 0);buffer = newList;}/// <summary>/// Trim the unnecessary memory, resizing the buffer to be of 'Length' size./// Call this function only if you are sure that the buffer won't need to resize  anytime soon./// </summary>void Trim (){if (size > 0){if (size < buffer.Length){T[] newList = new T[size];for (int i = 0; i < size; ++i) newList[i] = buffer[i];buffer = newList;}}else buffer = null;}/// <summary>/// Clear the array by resetting its size to zero. Note that the memory is not  actually released./// </summary>public void Clear () { size = 0; }/// <summary>/// Clear the array and release the used memory./// </summary>public void Release () { size = 0; buffer = null; }/// <summary>/// Add the specified item to the end of the list./// </summary>public void Add (T item){if (buffer == null || size == buffer.Length) AllocateMore();buffer[size++] = item;}/// <summary>/// Insert an item at the specified index, pushing the entries back./// </summary>public void Insert (int index, T item){if (buffer == null || size == buffer.Length) AllocateMore();if (index > -1 && index < size){for (int i = size; i > index; --i) buffer[i] = buffer[i - 1];buffer[index] = item;++size;}else Add(item);}/// <summary>/// Returns 'true' if the specified item is within the list./// </summary>public bool Contains (T item){if (buffer == null) return false;for (int i = 0; i < size; ++i) if (buffer[i].Equals(item)) return true;return false;}/// <summary>/// Return the index of the specified item./// </summary>public int IndexOf (T item){if (buffer == null) return -1;for (int i = 0; i < size; ++i) if (buffer[i].Equals(item)) return i;return -1;}/// <summary>/// Remove the specified item from the list. Note that RemoveAt() is faster and is  advisable if you already know the index./// </summary>public bool Remove (T item){if (buffer != null){EqualityComparer<T> comp = EqualityComparer<T>.Default;for (int i = 0; i < size; ++i){if (comp.Equals(buffer[i], item)){--size;buffer[i] = default(T);for (int b = i; b < size; ++b) buffer[b] = buffer[b  + 1];buffer[size] = default(T);return true;}}}return false;}/// <summary>/// Remove an item at the specified index./// </summary>public void RemoveAt (int index){if (buffer != null && index > -1 && index < size){--size;buffer[index] = default(T);for (int b = index; b < size; ++b) buffer[b] = buffer[b + 1];buffer[size] = default(T);}}/// <summary>/// Remove an item from the end./// </summary>public T Pop (){if (buffer != null && size != 0){T val = buffer[--size];buffer[size] = default(T);return val;}return default(T);}/// <summary>/// Mimic List's ToArray() functionality, except that in this case the list is  resized to match the current size./// </summary>public T[] ToArray () { Trim(); return buffer; }//class Comparer : System.Collections.IComparer//{//    public System.Comparison<T> func;//    public int Compare (object x, object y) { return func((T)x, (T)y); }//}//Comparer mComp = new Comparer();/// <summary>/// List.Sort equivalent. Doing Array.Sort causes GC allocations./// </summary>//public void Sort (System.Comparison<T> comparer)//{//    if (size > 0)//    {//        mComp.func = comparer;//        System.Array.Sort(buffer, 0, size, mComp);//    }//}/// <summary>/// List.Sort equivalent. Manual sorting causes no GC allocations./// </summary>[DebuggerHidden][DebuggerStepThrough]public void Sort (CompareFunc comparer){int start = 0;int max = size - 1;bool changed = true;while (changed){changed = false;for (int i = start; i < max; ++i){// Compare the two valuesif (comparer(buffer[i], buffer[i + 1]) > 0){// Swap the valuesT temp = buffer[i];buffer[i] = buffer[i + 1];buffer[i + 1] = temp;changed = true;}else if (!changed){// Nothing has changed -- we can start here next  timestart = (i == 0) ? 0 : i - 1;}}}}/// <summary>/// Comparison function should return -1 if left is less than right, 1 if left is  greater than right, and 0 if they match./// </summary>public delegate int CompareFunc (T left, T right);
#endif
}
//----------------------------------------------
//            NGUI: Next-Gen UI kit
// Copyright © 2011-2015 Tasharen Entertainment
//----------------------------------------------
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// BMFont reader. C# implementation of http://www.angelcode.com/products/bmfont/
/// </summary>
[System.Serializable]
public class BMFont
{[HideInInspector][SerializeField] int mSize = 16;                   // How much to  move the cursor when moving to the next line[HideInInspector][SerializeField] int mBase = 0;                    // Offset from  the top of the line to the base of each character[HideInInspector][SerializeField] int mWidth = 0;                   // Original  width of the texture[HideInInspector][SerializeField] int mHeight = 0;                  // Original  height of the texture[HideInInspector][SerializeField] string mSpriteName;// List of serialized glyphs[HideInInspector][SerializeField] List<BMGlyph> mSaved = new List<BMGlyph>();// Actual glyphs that we'll be working with are stored in a dictionary, making the  lookup fasterDictionary<int, BMGlyph> mDict = new Dictionary<int, BMGlyph>();/// <summary>/// Whether the font can be used./// </summary>public bool isValid { get { return (mSaved.Count > 0); } }/// <summary>/// Size of this font (for example 32 means 32 pixels)./// </summary>public int charSize { get { return mSize; } set { mSize = value; } }/// <summary>/// Base offset applied to characters./// </summary>public int baseOffset { get { return mBase; } set { mBase = value; } }/// <summary>/// Original width of the texture./// </summary>public int texWidth { get { return mWidth; } set { mWidth = value; } }/// <summary>/// Original height of the texture./// </summary>public int texHeight { get { return mHeight; } set { mHeight = value; } }/// <summary>/// Number of valid glyphs./// </summary>public int glyphCount { get { return isValid ? mSaved.Count : 0; } }/// <summary>/// Original name of the sprite that the font is expecting to find (usually the  name of the texture)./// </summary>public string spriteName { get { return mSpriteName; } set { mSpriteName = value;  } }/// <summary>/// Access to BMFont's entire set of glyphs./// </summary>public List<BMGlyph> glyphs { get { return mSaved; } }/// <summary>/// Helper function that retrieves the specified glyph, creating it if necessary./// </summary>public BMGlyph GetGlyph (int index, bool createIfMissing){// Get the requested glyphBMGlyph glyph = null;if (mDict.Count == 0){// Populate the dictionary for faster accessfor (int i = 0, imax = mSaved.Count; i < imax; ++i){BMGlyph bmg = mSaved[i];mDict.Add(bmg.index, bmg);}}// Saved check is here so that the function call is not needed if it's trueif (!mDict.TryGetValue(index, out glyph) && createIfMissing){glyph = new BMGlyph();glyph.index = index;mSaved.Add(glyph);mDict.Add(index, glyph);}return glyph;}/// <summary>/// Retrieve the specified glyph, if it's present./// </summary>public BMGlyph GetGlyph (int index) { return GetGlyph(index, false); }/// <summary>/// Clear the glyphs./// </summary>public void Clear (){mDict.Clear();mSaved.Clear();}/// <summary>/// Trim the glyphs, ensuring that they will never go past the specified bounds./// </summary>public void Trim (int xMin, int yMin, int xMax, int yMax){if (isValid){for (int i = 0, imax = mSaved.Count; i < imax; ++i){BMGlyph glyph = mSaved[i];if (glyph != null) glyph.Trim(xMin, yMin, xMax, yMax);}}}
}
using UnityEngine;
using UnityEditor;
public class BMFontEditor : EditorWindow
{[MenuItem("Tools/BMFont Maker")]static public void OpenBMFontMaker(){EditorWindow.GetWindow<BMFontEditor>(false, "BMFont Maker", true).Show();}[SerializeField]private Font targetFont;[SerializeField]private TextAsset fntData;[SerializeField]private Material fontMaterial;[SerializeField]private Texture2D fontTexture;private BMFont bmFont = new BMFont();public BMFontEditor(){}void OnGUI(){targetFont = EditorGUILayout.ObjectField("Target Font", targetFont,  typeof(Font), false) as Font;fntData = EditorGUILayout.ObjectField("Fnt Data", fntData,  typeof(TextAsset), false) as TextAsset;fontMaterial = EditorGUILayout.ObjectField("Font Material", fontMaterial,  typeof(Material), false) as Material;fontTexture = EditorGUILayout.ObjectField("Font Texture", fontTexture,  typeof(Texture2D), false) as Texture2D;if (GUILayout.Button("Create BMFont")){BMFontReader.Load(bmFont, fntData.name, fntData.bytes); // 借用NGUI封装的读取类CharacterInfo[] characterInfo = new  CharacterInfo[bmFont.glyphs.Count];for (int i = 0; i < bmFont.glyphs.Count; i++){BMGlyph bmInfo = bmFont.glyphs[i];CharacterInfo info = new CharacterInfo();info.index = bmInfo.index;info.uv.x = (float)bmInfo.x / (float)bmFont.texWidth;info.uv.y = 1 - (float)bmInfo.y / (float)bmFont.texHeight;info.uv.width = (float)bmInfo.width /  (float)bmFont.texWidth;info.uv.height = -1f * (float)bmInfo.height /  (float)bmFont.texHeight;info.vert.x = 0;info.vert.y = -(float)bmInfo.height;info.vert.width = (float)bmInfo.width;info.vert.height = (float)bmInfo.height;info.width = (float)bmInfo.advance;characterInfo[i] = info;}targetFont.characterInfo = characterInfo;if (fontMaterial){fontMaterial.mainTexture = fontTexture;}targetFont.material = fontMaterial;fontMaterial.shader = Shader.Find("UI/Default");Debug.Log("create font <" + targetFont.name + "> success");Close();}EditorUtility.SetDirty(targetFont);}
}
//----------------------------------------------
//            NGUI: Next-Gen UI kit
// Copyright © 2011-2015 Tasharen Entertainment
//----------------------------------------------
using UnityEngine;
using UnityEditor;
using System.Text;
/// <summary>
/// Helper class that takes care of loading BMFont's glyph information from the specified  byte array.
/// This functionality is not a part of BMFont anymore because Flash export option can't  handle System.IO functions.
/// </summary>
public static class BMFontReader
{/// <summary>/// Helper function that retrieves the string value of the key=value pair./// </summary>static string GetString (string s){int idx = s.IndexOf('=');return (idx == -1) ? "" : s.Substring(idx + 1);}/// <summary>/// Helper function that retrieves the integer value of the key=value pair./// </summary>static int GetInt (string s){int val = 0;string text = GetString(s);
#if UNITY_FLASHtry { val = int.Parse(text); } catch (System.Exception) { }
#elseint.TryParse(text, out val);
#endifreturn val;}/// <summary>/// Reload the font data./// </summary>static public void Load (BMFont font, string name, byte[] bytes){font.Clear();if (bytes != null){ByteReader reader = new ByteReader(bytes);char[] separator = new char[] { ' ' };while (reader.canRead){string line = reader.ReadLine();if (string.IsNullOrEmpty(line)) break;string[] split = line.Split(separator,  System.StringSplitOptions.RemoveEmptyEntries);int len = split.Length;if (split[0] == "char"){// Expected data style:// char id=13 x=506 y=62 width=3 height=3 xoffset=-1  yoffset=50 xadvance=0 page=0 chnl=15int channel = (len > 10) ? GetInt(split[10]) : 15;if (len > 9 && GetInt(split[9]) > 0){Debug.LogError("Your font was exported with  more than one texture. Only one texture is supported by NGUI.\n" +"You need to re-export your font,  enlarging the texture's dimensions until everything fits into just one texture.");break;}if (len > 8){int id = GetInt(split[1]);BMGlyph glyph = font.GetGlyph(id, true);if (glyph != null){glyph.x                =  GetInt(split[2]);glyph.y                =  GetInt(split[3]);glyph.width            =  GetInt(split[4]);glyph.height   = GetInt(split[5]);glyph.offsetX  = GetInt(split[6]);glyph.offsetY  = GetInt(split[7]);glyph.advance  = GetInt(split[8]);glyph.channel  = channel;}else Debug.Log("Char: " + split[1] + " (" +  id + ") is NULL");}else{Debug.LogError("Unexpected number of entries  for the 'char' field (" + name + ", " + split.Length + "):\n" + line);break;}}else if (split[0] == "kerning"){// Expected data style:// kerning first=84 second=244 amount=-5if (len > 3){int first  = GetInt(split[1]);int second = GetInt(split[2]);int amount = GetInt(split[3]);BMGlyph glyph = font.GetGlyph(second, true);if (glyph != null) glyph.SetKerning(first,  amount);}else{Debug.LogError("Unexpected number of entries  for the 'kerning' field (" +name + ", " + split.Length + "):\n" +  line);break;}}else if (split[0] == "common"){// Expected data style:// common lineHeight=64 base=51 scaleW=512  scaleH=512 pages=1 packed=0 alphaChnl=1 redChnl=4 greenChnl=4 blueChnl=4if (len > 5){font.charSize  = GetInt(split[1]);font.baseOffset = GetInt(split[2]);font.texWidth  = GetInt(split[3]);font.texHeight = GetInt(split[4]);int pages = GetInt(split[5]);if (pages != 1){Debug.LogError("Font '" + name + "'  must be created with only 1 texture, not " + pages);break;}}else{Debug.LogError("Unexpected number of entries  for the 'common' field (" +name + ", " + split.Length + "):\n" +  line);break;}}else if (split[0] == "page"){// Expected data style:// page id=0 file="textureName.png"if (len > 2){font.spriteName =  GetString(split[2]).Replace("\"", "");font.spriteName =  font.spriteName.Replace(".png", "");font.spriteName =  font.spriteName.Replace(".tga", "");}}}}}
}
//----------------------------------------------
//            NGUI: Next-Gen UI kit
// Copyright © 2011-2015 Tasharen Entertainment
//----------------------------------------------
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// Glyph structure used by BMFont. For more information see  http://www.angelcode.com/products/bmfont/
/// </summary>
[System.Serializable]
public class BMGlyph
{public int index;      // Index of this glyph (used by BMFont)public int x;          // Offset from the left side of the texture to the left side  of the glyphpublic int y;          // Offset from the top of the texture to the top of the  glyphpublic int width;      // Glyph's width in pixelspublic int height;     // Glyph's height in pixelspublic int offsetX;    // Offset to apply to the cursor's left position before  drawing this glyphpublic int offsetY; // Offset to apply to the cursor's top position before drawing  this glyphpublic int advance;    // How much to move the cursor after printing this characterpublic int channel;    // Channel mask (in most cases this will be 15 (RGBA,  1+2+4+8)public List<int> kerning;/// <summary>/// Retrieves the special amount by which to adjust the cursor position, given the  specified previous character./// </summary>public int GetKerning (int previousChar){if (kerning != null && previousChar != 0){for (int i = 0, imax = kerning.Count; i < imax; i += 2)if (kerning[i] == previousChar)return kerning[i + 1];}return 0;}/// <summary>/// Add a new kerning entry to the character (or adjust an existing one)./// </summary>public void SetKerning (int previousChar, int amount){if (kerning == null) kerning = new List<int>();for (int i = 0; i < kerning.Count; i += 2){if (kerning[i] == previousChar){kerning[i + 1] = amount;return;}}kerning.Add(previousChar);kerning.Add(amount);}/// <summary>/// Trim the glyph, given the specified minimum and maximum dimensions in pixels./// </summary>public void Trim (int xMin, int yMin, int xMax, int yMax){int x1 = x + width;int y1 = y + height;if (x < xMin){int offset = xMin - x;x += offset;width -= offset;offsetX += offset;}if (y < yMin){int offset = yMin - y;y += offset;height -= offset;offsetY += offset;}if (x1 > xMax) width  -= x1 - xMax;if (y1 > yMax) height -= y1 - yMax;}
}
//----------------------------------------------
//            NGUI: Next-Gen UI kit
// Copyright © 2011-2015 Tasharen Entertainment
//----------------------------------------------
using UnityEngine;
using System.Text;
using System.Collections.Generic;
using System.IO;
/// <summary>
/// MemoryStream.ReadLine has an interesting oddity: it doesn't always advance the  stream's position by the correct amount:
///  http://social.msdn.microsoft.com/Forums/en-AU/Vsexpressvcs/thread/b8f7837b-e396-494e-88e1-30547fcf385f
/// Solution? Custom line reader with the added benefit of not having to use streams at  all.
/// </summary>
public class ByteReader
{byte[] mBuffer;int mOffset = 0;public ByteReader (byte[] bytes) { mBuffer = bytes; }public ByteReader (TextAsset asset) { mBuffer = asset.bytes; }/// <summary>/// Read the contents of the specified file and return a Byte Reader to work with./// </summary>static public ByteReader Open (string path){
#if UNITY_EDITOR || (!UNITY_FLASH && !NETFX_CORE && !UNITY_WP8 && !UNITY_WP_8_1)FileStream fs = File.OpenRead(path);if (fs != null){fs.Seek(0, SeekOrigin.End);byte[] buffer = new byte[fs.Position];fs.Seek(0, SeekOrigin.Begin);fs.Read(buffer, 0, buffer.Length);fs.Close();return new ByteReader(buffer);}
#endifreturn null;}/// <summary>/// Whether the buffer is readable./// </summary>public bool canRead { get { return (mBuffer != null && mOffset < mBuffer.Length);  } }/// <summary>/// Read a single line from the buffer./// </summary>static string ReadLine (byte[] buffer, int start, int count){
#if UNITY_FLASH// Encoding.UTF8 is not supported in Flash :(StringBuilder sb = new StringBuilder();int max = start + count;for (int i = start; i < max; ++i){byte byte0 = buffer[i];if ((byte0 & 128) == 0){// If an UCS fits 7 bits, its coded as 0xxxxxxx. This makes  ASCII character represented by themselvessb.Append((char)byte0);}else if ((byte0 & 224) == 192){// If an UCS fits 11 bits, it is coded as 110xxxxx 10xxxxxxif (++i == count) break;byte byte1 = buffer[i];int ch = (byte0 & 31) << 6;ch |= (byte1 & 63);sb.Append((char)ch);}else if ((byte0 & 240) == 224){// If an UCS fits 16 bits, it is coded as 1110xxxx 10xxxxxx  10xxxxxxif (++i == count) break;byte byte1 = buffer[i];if (++i == count) break;byte byte2 = buffer[i];if (byte0 == 0xEF && byte1 == 0xBB && byte2 == 0xBF){// Byte Order Mark -- generally the first 3 bytes in  a Windows-saved UTF-8 file. Skip it.}else{int ch = (byte0 & 15) << 12;ch |= (byte1 & 63) << 6;ch |= (byte2 & 63);sb.Append((char)ch);}}else if ((byte0 & 248) == 240){// If an UCS fits 21 bits, it is coded as 11110xxx 10xxxxxx  10xxxxxx 10xxxxxxif (++i == count) break;byte byte1 = buffer[i];if (++i == count) break;byte byte2 = buffer[i];if (++i == count) break;byte byte3 = buffer[i];int ch = (byte0 & 7) << 18;ch |= (byte1 & 63) << 12;ch |= (byte2 & 63) << 6;ch |= (byte3 & 63);sb.Append((char)ch);}}return sb.ToString();
#elsereturn Encoding.UTF8.GetString(buffer, start, count);
#endif}/// <summary>/// Read a single line from the buffer./// </summary>public string ReadLine () { return ReadLine(true); }/// <summary>/// Read a single line from the buffer./// </summary>public string ReadLine (bool skipEmptyLines){int max = mBuffer.Length;// Skip empty charactersif (skipEmptyLines){while (mOffset < max && mBuffer[mOffset] < 32) ++mOffset;}int end = mOffset;if (end < max){for (; ; ){if (end < max){int ch = mBuffer[end++];if (ch != '\n' && ch != '\r') continue;}else ++end;string line = ReadLine(mBuffer, mOffset, end - mOffset - 1);mOffset = end;return line;}}mOffset = max;return null;}/// <summary>/// Assume that the entire file is a collection of key/value pairs./// </summary>public Dictionary<string, string> ReadDictionary (){Dictionary<string, string> dict = new Dictionary<string, string>();char[] separator = new char[] { '=' };while (canRead){string line = ReadLine();if (line == null) break;if (line.StartsWith("//")) continue;
#if UNITY_FLASHstring[] split = line.Split(separator,  System.StringSplitOptions.RemoveEmptyEntries);
#elsestring[] split = line.Split(separator, 2,  System.StringSplitOptions.RemoveEmptyEntries);
#endifif (split.Length == 2){string key = split[0].Trim();string val = split[1].Trim().Replace("\\n", "\n");dict[key] = val;}}return dict;}static BetterList<string> mTemp = new BetterList<string>();/// <summary>/// Read a single line of Comma-Separated Values from the file./// </summary>public BetterList<string> ReadCSV (){mTemp.Clear();string line = "";bool insideQuotes = false;int wordStart = 0;while (canRead){if (insideQuotes){string s = ReadLine(false);if (s == null) return null;s = s.Replace("\\n", "\n");line += "\n" + s;}else{line = ReadLine(true);if (line == null) return null;line = line.Replace("\\n", "\n");wordStart = 0;}for (int i = wordStart, imax = line.Length; i < imax; ++i){char ch = line[i];if (ch == ','){if (!insideQuotes){mTemp.Add(line.Substring(wordStart, i -  wordStart));wordStart = i + 1;}}else if (ch == '"'){if (insideQuotes){if (i + 1 >= imax){mTemp.Add(line.Substring(wordStart, i  - wordStart).Replace("\"\"", "\""));return mTemp;}if (line[i + 1] != '"'){mTemp.Add(line.Substring(wordStart, i  - wordStart).Replace("\"\"", "\""));insideQuotes = false;if (line[i + 1] == ','){++i;wordStart = i + 1;}}else ++i;}else{wordStart = i + 1;insideQuotes = true;}}}if (wordStart < line.Length){if (insideQuotes) continue;mTemp.Add(line.Substring(wordStart, line.Length -  wordStart));}return mTemp;}return null;}
}

Unity美术字体教程--BMFont美术字体的制作流程以及在unity中美术字体的生成相关推荐

  1. zb怎么做渲染图_美术丨教程:使用ZBrush渲染制作女神的衣物和皮肤

    原标题:美术丨教程:使用ZBrush渲染制作女神的衣物和皮肤 翻译:BeforeDawn 在今天这个简易的女神的衣物和皮肤制作教程中,我将会带你了解我是如何使用ZBrush渲染制作女神的衣物和皮肤,以 ...

  2. cocos2dx 字体外发光_亚克力发光字制作流程有哪些,你知道吗?遵义制作厂家

    一.材料: 1.亚克力字面板 2.亚克力字边条 3.支撑块(5mm透明亚克力) 4.瞬间502胶水 5.透明建筑结构胶及胶枪 6.建筑防水密封膏及胶枪 7.厚4mmPVC底板 8.LED发光模组 9. ...

  3. android手机可以换字体吗,安卓手机字体怎么改?安卓手机爱字体换字体教程

    安卓手机字体怎么改?大家都知道,换安卓字体是需要Root权限的,随着安卓系统的不断升级,Root的难度也逐步上升,但这个问题与我们无关,让刷机工具头疼去吧,我们只需要点击某软件的"一键Roo ...

  4. gt designer2不能初始化字体管理器_Windows Terminal 1.1预览版发布:新增字体粗细、随开机启动等功能...

    经历了数月的公开测试之后,微软于上月发布了 Windows Terminal 1.0 正式版.今天微软再次发布了 1.1 预览版更新,引入了包括字体粗细.随开机启动等诸多功能.Windows Term ...

  5. 在 Ubuntu 中更换字体

    环境 Ubuntu 18.04.3 LTS 下载并解压字体 首先,下载要安装的字体.在本教程中,我们将使用Hack字体.用wget从github中下载字体: wget https://github.c ...

  6. Android中设置字体居中,【Android】TextView中不同大小字体如何上下垂直居中?

    前言 在客户端开发中,我们往往需要对一个TextView的文字的部分内容进行特殊化处理,比如加粗.改变颜色.加链接.下划线等.iOS为我们提供了AttributedString,而Android则提供 ...

  7. Office如何在文稿中嵌入字体(macOS)

    写在前面 很多时候,我们都会下载一些非预置的字体安装在电脑上,有时可以用.我们在Microsoft Office套件中的PowerPoint.Excel.Word软件中添加用这些美轮美奂的字体书写的文 ...

  8. access字体变为斜体_Linux折腾记(四):Linux桌面系统字体配置详解

    字体显示效果测试 文字: 复制代码代码如下: 这一段是为了测试宋体字的显示效果,包括宋体里面自带的英文字体,"This is english,how does it look like?&q ...

  9. 富文本中添加字体选项功能_扑中的字体功能

    富文本中添加字体选项功能 A little extra help for styling your text 样式设置方面的一些额外帮助 I recently learned about a litt ...

  10. html字体怎么设置大写,如何在html中设置字体的属性

    如何在html中设置字体的属性 发布时间:2021-06-08 17:45:33 来源:亿速云 阅读:72 作者:Leah 这篇文章给大家介绍如何在html中设置字体的属性,内容非常详细,感兴趣的小伙 ...

最新文章

  1. 计算机专业好的广东二本学校排名2015,2015年广东省二本大学排名名单
  2. 重启jboss出现问题:端口被占用
  3. spring mvc DispatcherServlet详解之三---request通过ModelAndView中获取View实例的过程
  4. 如何设计实时数据平台(设计篇)
  5. 07_QueueWithTwoStacks
  6. 深入浅出 RPC - 浅出篇+深入篇
  7. oracle导致的负载高,Oracle 11g 数据库服务器CPU、IO负载高的故障排除流程
  8. ROS 可视化(一): 发布PointCloud2点云数据到Rviz
  9. 洛谷P1402 酒店之王
  10. 汉字字符内码查询_计算机等级考试查询系统
  11. Oracle、SQL Server、MySQL数据类型对比
  12. Linux+Nginx+SpringBoot+War环境下websocket部署遇到的问题
  13. SpringBoot解决XSS跨站脚本攻击
  14. vue 倒计时 插件_vue+moment实现倒计时效果
  15. java one_javaone是什么意思
  16. LUA学习--Hotfix
  17. Shell 获取服务器IP地址
  18. the volume for a file has been externally altered so that the opened file is no longer valid
  19. JavaScript-标签语句
  20. matplotlib设置坐标轴

热门文章

  1. HTTP下载龙卷风系列Office/Photoshop/金山词霸快译/
  2. 前后端分离项目session跨域失效的解决方案
  3. 2022最新RiPro-V2子主题美化包源码+实测可用
  4. 软考中级数据库系统工程师复习资料
  5. 电脑五笔,电脑键盘五笔指法练习表
  6. 免费杀软中的王者:德国小红伞评测
  7. 必读论文|20篇聊天机器人领域必读论文速递
  8. ORB-SLAM2代码详解
  9. win10笔记本ps/2键盘鼠标失灵,错误代码39、错误代码10
  10. 老系统维护(一)[转]