跳到主要内容

FAQ

更新日期:2025-04-11

修改了动态类的结构,但未生效

需要重启编辑器

目前未开放 Emit 热重载,因此当你做了以下操作后,需要重启编辑器才能生效:

  • 增删改 UClass、UStruct、UEnum、UDelegate(重命名视为先删后增)
  • 增删改 UProperty、UFunction(重命名视为先删后增)
  • 增删改 Emit 相关的反射标识符
  • 增删改 UEnum 的字段

在目前的规划中,Emit 热重载的优先级很低,可能短期内不会支持。

动态类重写了 BlueprintNativeEvent 但未生效

需要开发者做一些处理

UE 5.5 新增了一项关于 BlueprintNativeEvent 的优化: 如果一个 BlueprintNativeEvent 没有蓝图的重写版本,则直接在编译期分发到 C++ 的 Implementation。

动态类是 Native 类,即相当于一个 C++ 类。 因此,即使重写了 BlueprintNativeEvent,仍然不会有动态分发。

解决方案:

  1. 创建一个蓝图子类,重写这个函数,只连一个 AddCallToParent
  2. 创建一个 C++ 基类,将这个 BlueprintNativeEvent 转发到一个 BlueprintImplementableEvent 中。
  3. 去掉引擎代码中的这项优化(注意,改了 UHT 后需要重新编译整个引擎才能确保完全生效)。

动态类重写了 Actor、ActorComponent、UserWidget 的 Tick 但未执行

需要开发者做一些处理

对于 Actor 和 ActorComponent,首先需要确保你的类型开启了 Tick。 默认情况下,它们都是不 Tick 的,如果你继承了本身就可以 Tick 的基类,可以跳过这一步。 否则你需要在类型上添加 [PropertyDefaultOverride] 特性来开启 Tick:

// For Actor
[PropertyDefaultOverride(Property = "PrimaryActorTick.bCanEverTick", Default = true)]
// For ActorComponent
[PropertyDefaultOverride(Property = "PrimaryComponentTick.bCanEverTick", Default = true)]

其次,动态类是 Native 类,即相当于一个 C++ 类。 上述三个类型的 ReceiveTick 事件都只会在非 Native 类的实例上执行。 类似的还有 ActorComponent 的 BeginPlay 和 EndPlay。

解决方案:

  1. 创建一个蓝图子类,并使用蓝图子类的实例。
  2. 在 C++ 中添加一个脚本基类,给脚本基类添加一个 ScriptTick 事件,脚本继承这个基类并重写自定义的 Tick。
  3. 改用异步流。
  4. 去掉引擎代码中的这项优化。

是否支持生成蓝图类的胶水代码

不支持

Z# 延续了虚幻引擎原本的设计理念,C++、脚本、蓝图三者之间存在明确的层级关系,即 C++ 在最底层,脚本在中间层,蓝图在最上层。 在这种理念下,脚本是不应该依赖蓝图的,自然也就无需生成蓝图的胶水代码。 同时,不生成蓝图类的胶水代码,也就意味着动态共轭类型只能继承 Native 类,而不能继承蓝图类。

是否支持跨平台

理论支持

Mono 可以覆盖大多数主流平台,但我们目前并未在 Windows 以外的平台跑过测试流程。

是否支持热更新

理论支持

对于支持 JIT 的平台,直接替换程序集即可实现热更新; 对于不支持 JIT 的平台,目前使用 Mono 的解释模式,理论上可以通过字节流加载程序集的方式实现热更新。

是否支持其他编程语言

短期不会支持

.NET 下的每种编程语言都有各自擅长的领域。 C# 本身的定位就是用于开发大型应用软件,如果没有特殊原因,用其他语言开发游戏未必是一个明智的选择。

虽然 Z# 运行时没有对前端编程语言做任何假设,但工具链层面要实现一整套 Analyzer 的成本还是相当大的。

是否支持纯蓝图项目

不完全支持

目前打包流程依赖 C++,理论上你可以完全用脚本和蓝图开发,但必须有一个 C++ 入口。

是否支持命名中包含非常见字符(如中文字符)

不支持

我们不对特殊字符做任何处理,因此如果命名中包含非常见字符(如动态访问蓝图中的中文名变量),可能会导致一些问题。