Notifications
Article
如何在Unity 2019.3中更快地进入播放模式
Updated 5 days ago
1.0 K
3
我们即将推出新的Configurable Enter Play Mode(播放模式启用可配置化)功能,该功能可以设定编辑器在进入播放模式时是否需要重新加载域和场景,减少重复性运算,加快播放模式的进入及退出速度。
作者:alexeyz,2019年11月5日
原文链接:https://blogs.unity3d.com/2019/11/05/enter-play-mode-faster-in-unity-2019-3/

播放是让Unity使用起来更有趣的核心部分。可如果项目变得复杂起来,进入播放模式就会更耗时间。而更快的播放模式进入或退出时间,意味着更快的关卡修改和测试。为此,我们将在Unity 2019.3 beta中推出一项实验性功能:Configurable Enter Play Mode(播放模式启用可配置化)
目前,在编辑器中进入播放模式时,Unity会做以下两件事:重设脚本状态(Domain Reload,域重新加载),场景重新加载。这里会花上不少时间,而项目越复杂,等待时间越长,在播放时间内测试新改动就更慢。不过,在Unity 2019.3 beta版中,我们可以选择禁用“域重新加载”和“场景重新加载”的其中一部分,或两者同时禁用。
根据我们的测试结果,此类功能可根据项目不同省下最多50-90%的等待时间。
我们可在File > Project Settings > Editor下找到Enter Play Mode Options(播放模式启用选项),其中的reload Domain(重新加载域)和reload Scene(重新加载场景)变为可用状态。请在说明文件的How to configure Play Mode(如何配置播放模式)部分查阅更多细节。
当代码没有什么变动时,此选项允许我们设置Enter Play Mode过程中是否需要重新加载域或/和场景。如果想要在进入播放模式前重置游戏状态,我们也可以使用一个API和一个回调来启用这个功能。
下方图标展示了禁用域重新加载和场景重新加载前后,启用播放模式流程的不同:
请在Unity手册相关说明文档内查阅Unity启用播放模式过程中的更多细节。
请注意该功能仍处于实验状态,并非所有Unity包都能在禁用域和场景重新加载的情况下继续使用。如果遇到任何问题,请在论坛上告诉我们吧!

在禁用域重新加载后,我该如何修改脚本?

可以看到,省去重新加载域非常简单,但也有一些问题。我们需要调整静态的字段和事件处理器,来确保在进入播放模式时脚本状态能正确地重置。
下方代码示例中含有一个计数器,当玩家按下跳跃键,则数字会增加。当启用域重新加载时,计数器会在进入播放模式时自动重置为零。然而当禁用域重新加载后,计数器不会重置;它会在进入或退出播放模式时保留自己的数值。这意味着在编辑器中第二次运行项目时,如果计数器在前一次运行中有数值改动,这次运行时它不会重置为0。
public class StaticCounterExample : MonoBehaviour { // this counter will not reset to zero when Domain Reloading is disabled(该计数器在禁用域重新加载时不会重置为0) static int counter = 0; // Update is called once per frame(每帧都会调用一次Update) void Update() { if (Input.GetButtonDown("Jump")) { counter++; Debug.Log("Counter: " + counter); } } }
我们可以使用[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] 设置,指定重置数值,确保在禁用域重新加载时计数器能正确重置。示例:
using UnityEngine; public class StaticCounterExampleFixed : MonoBehaviour { static int counter = 0; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] static void Init() { Debug.Log("Counter reset."); counter = 0; } // Update is called once per frame(在每帧上调用一次Update) void Update() { if (Input.GetButtonDown("Jump")) { counter++; Debug.Log("Counter: " + counter); } } }
当禁用了域重新加载,Unity不会在退出播放模式时注销静态事件处理器上的方法。如果你的代码中将方法注册到了静态事件处理器上时,这会让情况变得复杂起来。举例来说,在编辑器中第一次播放项目时,方法会被正常注册。然而,在第二次播放项目时,这些方法会在第一次注册方法的基础上再注册一次,于是,事件在触发时会调用两次。
下方代码会在静态事件处理器Application.quitting上注册一个方法:
using UnityEngine; public class StaticEventExample : MonoBehaviour { void Start() { Debug.Log("Registering quit function"); Application.quitting += Quit; } static void Quit() { Debug.Log("Quitting!"); } }
当域重新加载被禁用,上述示例代码中每次进入播放模式,都会给处理器加上一次退出(Quit)方法,造成每次退出播放模式,“退出”讯息会越来越多。
我们可以使用[RuntimeInitializeOnLoadMethod]属性,具体地将方法注销,防止其被注册两次:
using UnityEngine; public class StaticEventExampleFixed : MonoBehaviour { [RuntimeInitializeOnLoadMethod] static void RunOnStart() { Debug.Log("Unregistering quit function"); Application.quitting -= Quit; } void Start() { Debug.Log("Registering quit function"); Application.quitting += Quit; } static void Quit() { Debug.Log("Quitting the Player"); } }
请在我们的说明文件中查阅,禁用域重新加载时如何让代码能正确地运行。

资源商店

我们希望资源商店中高人气的资源包能在禁用域和场景重新加载的情况下正常运行。如果在项目中遇到问题,可将问题反馈给资源包的发布者,帮助我们完善此功能。

快来加入Unity 2019.3 beta测试吧!

如果你的项目进入播放模式速度较慢,我们相信该功能可以极大地提升效率。快来参加Unity 2019.3 beta测试,试试新功能吧。如果有任何想法,在论坛上向我们反馈吧!本功能仍处于试验阶段,你可以根据自己的需求帮助我们塑造它。如果遇到任何问题,请毫不犹豫地向我们提出来。
这里特别感谢论坛用户@Sini,@chrisk,@Peter77,和 @Baste,他们参与了功能的测试,提供了非常宝贵的意见,对我们有极大的帮助。

开发过程中遇到问题?在这里提问:connect.unity.com/g/discussion
Tags:
Unity China
687
Comments
bh
bin hu
4 days ago
重置写法把代码变得很不干净,但启动又快了好多,这让我很纠结你知道不
0
print
4 days ago
可以
0
max
5 days ago
主程
还需要更智能一些啊,感觉这类重置的代码可以自动生成呢,用一个Attribute实现如何?
0