在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_FLASH
List<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) buf