unity 如何正确获取字符宽度

问题描述

我正在尝试创建一个脚本,当一行文本接近该行的宽度时,它会尝试正确包装文本(即,如果字符不是“-”或“”,则添加一个连字符在单词的字母之间(就像单词编辑软件的工作方式)但是当我尝试运行它时,我的一堆字符消失了。

这是我正在测试的文字,“一个畸变拥有奇异的解剖结构、奇怪的能力、外星人的心态,或者三者的任意组合。”

但这些是我的测试脚本的结果

"找到信息 (' ','e','r','a','t','i','o','h','s','l','d' )” “发现没有信息('A','n','b','z','m','y',',','g','c','f','。')” “没有找到()”

并且仅使用具有可用信息的字符编译文本的输出是“erratio has a iarre aato strae ailities a alie idset or a oiatio o the Three”

这是我的测试脚本

public class Test : MonoBehavIoUr
{
    [Serializefield] 
    private Type m_Type; 
    // Not System.Type,is a custom class

    [Serializefield] 
    private Font m_Font; 
    // Set to Arial for testing.

    private List<string> m_FoundWithInfo;
    private List<string> m_FoundWithoutInfo;
    private List<string> m_DidntFind;
    private void Awake()
    {
        m_FoundWithInfo = new List<string>();
        m_FoundWithoutInfo = new List<string>();
        m_DidntFind = new List<string>();
        foreach (char c in m_Type.GetDescription())
        {
            if (m_Font.HasCharacter(c))
            {
                if (m_Font.GetCharacterInfo(c,out CharacterInfo info,14,FontStyle.normal))
                {
                    if (!m_FoundWithInfo.Contains($"'{c}'"))
                    {
                        m_FoundWithInfo.Add($"'{c}'");
                    }
                }
                else
                {
                    if (!m_FoundWithoutInfo.Contains($"'{c}'"))
                    {
                        m_FoundWithoutInfo.Add($"'{c}'");
                    }
                }
            }
            else
            {
                if (!m_DidntFind.Contains($"'{c}'"))
                {
                    m_DidntFind.Add($"'{c}'");
                }
            }
        }
        Debug.Log($"Found with info ({string.Join(",",m_FoundWithInfo)})");
        Debug.Log($"Found without info ({string.Join(",m_FoundWithoutInfo)})");
        Debug.Log($"Didnt Find ({string.Join(",m_DidntFind)})");
    }
}

我如何才能使返回的文本与原始文本相同?

为了澄清测试脚本只检查哪些必要的字符没有任何与之关联的 CharacterInfo。

解决方法

获取角色信息

Unity 字体管理对纹理进行操作以渲染字符,并且需要通知加载哪些字符才能将它们添加到字体纹理中,然后才能在渲染文本时使用它们。除非您请求加载示例之外的字符,否则字体中存在但没有可用信息的字符是因为在查询字体信息时没有将它们加载到字体纹理中。

Font.HasCharacter 检查您使用的字体是否定义了字符 - 如果返回 false,则该字符不存在于字体中且无法加载使用。示例是检查仅包含拉丁字符的字体中的非拉丁符号。 Font.HasCharacter 返回 true 意味着您可以将该字符加载到字体纹理中。

Font.GetCharacterInfo 从当前加载的字体纹理中获取有关符号的信息 - 因此加载的字体可能有可用的字符,但未加载;如果您手动渲染文本,这将导致 Font.GetCharacterInfo 返回 false 并使字符不渲染。要解决此问题,您需要使用 RequestCharactersInTexture 请求 Unity 加载您需要的字符 - 文档还包含有关如何处理手动文本渲染(包括字体纹理更新)的示例。在加载字符之前,您将无法获取其字体信息,因为当前使用的字体纹理中不存在该信息。调用 RequestCharactersInTexture 时,传递文本中出现的所有字符,无论它们是否已加载 - 这样您就可以确保 Font 在加载新字符时不会卸载先前加载的字符。

确定换行符

在制定解决方案以确定在哪里放置换行符时,您可能需要考虑 kerning - 根据周围的字符,字体可能希望使用不同的字符间距,有时甚至使用不同的字形。如果您手动渲染文本,请确保在计算换行符之间对字距进行一致处理 - 没有字距调整是一个好策略,只要您使用的字体不严重依赖于字距调整。如果您想支持字距调整,您应该处理子字符串而不是单个字符,并尝试找到为整行引入换行符的最佳点 - 一行的宽度可能不同于出现在所述行中的所有字符宽度的总和。