Unity高版本TMP中文字体问题

  • 解决方案:选择中文字体库大的中文字体粘贴进项目中,然后右键 -> Create -> TextMeshPro -> Font Asset -> SDF,完成此过程就会创建新字体,然后尝试该字体是否能正常显示,不能正常显示则尝试调整新字体文件的Atlas Width/Atlas Height,一直调整到最大都不行的话就换字体。
  • 目前已经尝试成功的字体
    • 阿里巴巴普惠体
    • 思源黑体

可序列化问题

1
2
3
4
5
6
7
8
9
using UnityEngine;

[CreateAssetMenu(fileName = "NewStoryNode", menuName = "Game Data/Story Node")]
public class StoryNode : ScriptableObject
{
public int ID;

public Choice[] choices;
}

查看以上代码,分析一下为什么Int能在Inspector面板正确显示,但Choice[]却不能正确显示

这里需要引出一个知识点————Unity 的 Inspector 只能显示那些被标记为 [Serializable]结构体的字段。

也就是说 choices 的不显示很可能是没给 Choice 类加标签导致的

解决方案也很简单,给 Choice 类加标签就行,就像下面这样

1
2
3
4
5
6
[System.Serializable]
public class Choice
{
public string choiceText;
public StoryNode nextStoryNode;
}

这里要注意一点,Unity 的 Inspector 不支持直接序列化引用类型的数组(如 MonoBehaviour[]ScriptableObject[]

这意味着 Choice 必须是一个普通的 C# 类


文件编码问题可能导致的、其他非常隐蔽的异常和bug

1. 脚本编译与解析错误

场景:C# 脚本文件被意外保存为带BOM的UTF-8

  • 隐蔽异常

    • 编译器错误指向第一行:Unity 或 C# 编译器可能会报告一个莫名其妙的语法错误,位置就在文件的第一行第一个字符。错误信息可能是“意外的字符”、“需要命名空间、类型或委托声明”等。
    • #if 等预处理指令失效:如果BOM恰好出现在 #if UNITY_EDITOR 这样的预处理指令之前,可能会导致编译器无法正确识别该指令,使得本应在特定平台编译的代码被错误地包含或排除。
    • Assembly Definition (.asmdef) 文件解析失败:如果 .asmdef 这个JSON格式的文件被保存为带BOM的UTF-8,Unity的程序集解析器可能会直接忽略这个文件或报错,导致整个程序集的代码无法被正确编译和引用,引发大量的“找不到类型或命名空间”的错误。
  • 为什么隐蔽

    • BOM是不可见字符,你在代码编辑器里看第一行是完全正常的 using UnityEngine;
    • 错误信息通常不会直接说“文件编码错误”或“发现BOM”,而是会给出一些看似是语法问题的误导性提示。开发者很容易陷入检查语法、括号匹配等无用功中。

2. 配置文件与数据文件解析失败

场景:JSON, XML, CSV, INI 等数据文件

  • 隐蔽异常

    • JSON 解析失败:一个严格的JSON解析器(比如很多网络库中使用的)在遇到BOM时会直接抛出“无效的JSON令牌”或类似的解析错误,因为它期望文件的第一个字符是 {[
    • XML 解析失败:和 log4net 的情况类似,XML解析器期望文件以 <?xml ... ?>< 开头。BOM的存在会让它认为文件格式不正确。
    • CSV 数据错位:如果一个CSV文件的第一行是表头,BOM可能会被当作第一个表头字段的一部分,导致 Header1 变成 \uFEFFHeader1。当你按表头名字去取数据列时,就会失败。更糟糕的是,有些解析器可能会把BOM当作一个空字段,导致所有列向后错位一格。
  • 为什么隐蔽

    • 和脚本文件一样,肉眼看不出问题。
    • 失败的方式多种多样,可能是直接崩溃,也可能是返回 null 或空数据,让你误以为是文件内容本身是空的。

3. 网络通信与HTTP请求问题

场景:HTTP请求的Body或Header

  • 隐蔽异常

    • 服务器端认证失败 (401/403):假设你需要计算请求体(Request Body)的HMAC签名并放在请求头(Header)里。如果你从一个带BOM的文件中读取内容作为请求体,计算出的签名就会是错误的,因为BOM也参与了计算。服务器端用不带BOM的原始数据计算签名,两者永远对不上,导致请求被拒绝。
    • 服务器端数据解析失败 (400 Bad Request):你发送一个POST请求,请求体是JSON格式。如果你从一个带BOM的文本文件读取内容直接发送,服务器端的JSON解析器会因为BOM的存在而解析失败,返回400错误。
    • 文件上传后损坏:上传一个文本文件(比如Shader、配置文件),如果服务器端的处理逻辑对BOM敏感,这个文件在服务器上可能就无法被其他程序正确使用。
  • 为什么隐蔽

    • 你本地看到的数据是好的,发送前检查也是好的,但服务器就是不认。
    • 错误发生在你看不到的服务器端,你只能得到一个笼统的HTTP错误码,很难直接联想到是本地文件编码的问题。

4. 跨平台与脚本执行问题

场景:Shell脚本、Python脚本等

  • 隐蔽异常

    • Shebang (#!) 失效:在Linux或macOS上,脚本文件的第一行通常是 #!/bin/bash#!/usr/bin/env python,用来告诉系统用哪个解释器执行此脚本。如果文件被保存为带BOM的UTF-8,BOM会出现在 #! 之前。系统在读取时,无法识别这个shebang,可能会导致脚本无法执行,或者报“找不到命令”的错误。
    • 跨平台协作问题:一个在Windows上用记事本(旧版默认带BOM)编辑过的脚本,拷贝到Linux服务器上就无法运行,这在DevOps和自动化流程中是常见的“坑”。
  • 为什么隐蔽

    • 在Windows上双击可能没问题(因为它不依赖shebang),但在需要它的系统上就完全失效。
    • 对于不熟悉Linux的开发者来说,这种问题几乎无法凭直觉解决。

总结与防范

文件编码问题,尤其是UTF-8 BOM问题,其隐蔽性在于:

  1. 不可见性:问题根源是肉眼无法看到的字符。
  2. 误导性错误:产生的错误信息往往指向表层现象(如语法错误、解析失败),而非根本原因(编码错误)。
  3. 环境依赖性:同一个文件在某些软件或平台下工作正常,在另一些环境下就失败,增加了定位难度。

如何防范:

  • 统一团队开发环境:为团队配置统一的IDE(如VS Code, Rider, Visual Studio),并配置其默认文件保存格式为 UTF-8 (without BOM)。这是最一劳永逸的方法。
  • 使用版本控制的 .gitattributes:在Git项目中,可以添加一个 .gitattributes 文件,强制指定某些文件类型的编码和行尾符,例如:
    1
    2
    3
    4
    5
    6
    # 强制所有文本文件在检出时为LF行尾
    * text=auto eol=lf
    # 强制特定文件类型为UTF-8无BOM
    *.cs text eol=lf
    *.json text eol=lf
    *.xml text eol=lf
  • 养成使用专业编辑器的习惯:避免使用Windows记事本等可能产生编码问题的简单编辑器来处理项目文件。专业编辑器通常会在状态栏显示当前文件的编码格式,便于检查。
  • 遇到“灵异事件”时,优先检查编码:当你遇到看似无法解释的解析错误、编译错误或跨平台问题时,把“检查文件编码”作为你的一个标准排查步骤。