Unity5.3中新增加了多场景编辑功能,允许用户将一个大场景以某种逻辑分割成多个小场景并方便的编辑和管理。这在某些情况下会比较有用,是对Unity编辑器

对场景编辑能力的一个重要提升。本文将由Unity官方工程师张为,为大家介绍一些多场景编辑的基本功能以及一些实例。

什么是多场景编辑

多场景编辑就是允许用户在Unity编辑器中同时打开多个场景,并对它们进行编辑。Unity提供了一系列的UI和Scripting APIs来管理这些场景。以下就是一个在Unity编辑器中进行多场景编辑的一个实例。

什么是场景

在进一步了解多场景编辑之前,我们先了解下什么是场景(Scene)。简而言之场景就是包含了游戏对象的一个文件,比如Game objects,Components等。不过有一些对象可能一些用户并不会太在意,那就是Scene Game managers。

Unity中有两类Game Managers:

一类是Global Game Managers。它们是全局的Game

managers,包括AudioManager、InputManager、PhysicsManager等。当你在Unity5.3中发布你的游戏的

时候,你会发现在输出目录或者发布包里面会有个globalgamemanagers文件,它包含了所有全局Game managers。

另一类是Scene game managers。如果你将Editor Settings中的Asset Serialization选择为”Force Text”模式,并打开一个已经保存的*.unity场景文件,你会发现前保存在文件最前面的就是SceneSettings、RenderSettings、LightMapSettings和NavMeshSettings,它们就是每个场景都会有的Game managers。

为什么需要多场景编辑

首先将大场景分割成多个场景,可以更好的支持场景的流式加载(Scene streaming);

其次可以更好地支持协同合作,尤其是在有源代码版本管理的时候可以允许多人同时编辑而不会产生冲突;

再者支持卸载场景(Scene unloading),在5.3之前用户可以通过Application.LoadLevelAddtive()和Application.LoadLevelAdditiveAsync()动态加载场景,但没有对应的Application.UnloadScene()。而5.3中提供了场景卸载,让用户可以更灵活的管理多个场景。

多场景编辑基本功能介绍

接下来我们看看Unity在5.3中具体提供了哪些多场景编辑的功能。

Scene结构

在5.3之前,Unity中只有概念上的场景,而到5.3中我们引入了真正的Scene结构。它包含了name、path、isLoaded等变量,同时也提供了IsValid()以及GetRootGameObjects()方法。

Active Scene

在5.3中,我们引入了Active Scene(当前场景)的概念。引入它的目的在于:

如果有多个场景同时打开,我们会选择Active Scene的Scene game managers作为当前的Scene game managers。比如在bake lightmapping的时候,我们会使用Active scene的LightMapSettings来bake当前打开的所有场景。

在创建Game object的时候,会默认加入到Active scene。

SceneManager

SceneManager在UnityEngine.SceneManagement之下,它是Runtime中的Scene manager,提供了以下方法:

LoadScene() / LoadSceneAsync()

它们允许用户通过name、build index来加载场景。用户可以在Build Settings窗口查看name和build index。通过这两个方法加载的场景,要么被加到了Build Settings,要么存在于AssetBundle之中。如果是从AssetBundle中加载场景,则只能通过名字加载。

要说明的是如果有多个场景同名但位于不同的目录之下,可以使用完整的路径(不带.unity后缀名)来加载不同的场景。

用户可以通过LoadSceneMode来指定不同的加载模式。LoadSceneMode.Single在加载之前会卸载其他所有的场景,LoadSceneMode.Additive则是加载的时候不关闭之前的场景。

还有一点很重要的是LoadScene()并不是完全同步的,它只能保证在下一帧开始之前加载完毕。所以在此推荐大家使用LoadSceneAsync()这个异步的加载方法。

UnLoadScene()

目前5.3中用户只能通过name和build index来同步的卸载一个Scene。在后续的版本中我们会提供通过Scene结构来卸载一个Scene,并且提供异步卸载的方法。

GetActiveScene() / SetActiveScene()

获取和设置Active scene。

GetSceneAt() / GetSceneByName() / GetSceneByPath()

我们也提供了一组方法来查询Scene。

其它

EditorSceneManager

EditorSceneManager在UnityEditor.SceneManagement之下,它是Editor中的Scene manager,提供了以下方法:

OpenScene()

它是一个同步的方法,用户只能通过path来打开场景。不同于LoadScene() / LoadSceneAsync(),它可以直接打开一个存在于Assets目录下的场景,不管它是否被添加到Build Settings。

用户可以通过OpenSceneMode来指定不同的打开模式,相比较LoadSceneMode,它多了一个AdditiveWithoutLoading模式,允许用户增加一个场景但并不真正加载它。

CloseScene()

顾名思义,它可以关闭一个场景,同时它提供了一个bool参数来指定关闭的时候是否将场景从Scene manager中移除。

SaveScene() / SaveScenes()

通过它们可以保存一个或多个Scene。

MarkSceneDirty() / MarkAllScenesDirty()

通过它们可以将某个指定的场景或者所有场景标记为Dirty。大部分情况Unity内部通过Undo系统来实现场景的Dirty跟踪,但是有些模块并没有完全支持Undo,比如Terrain在设置某些参数的时候就不支持Undo。所以我们提供了这两个方法支持直接将场景设置为Dirty。

其它

API的使用限制

在Editor mode下,UnityEngine.SceneManagement.SceneManager的某些方法是不能使用的。

LoadScene()

LoadSceneAsync()

CreateScene()

UnloadScene()

同样在Play mode下,UnityEditor.SceneManagement.EditorSceneManager的某些方法也不能使用。

OpenScene()

NewScene()

CloseScene()

SaveScene() / SaveScenes() / …

MarkSceneDirty() / MarkAllScenesDirty()

如果用户在不同的模式下使用了错误的方法,我们会在Console输出对应的错误信息引导用户使用正确的方法。

DontDestroyOnLoad Scene

在Unity 5.3中,如果用户通过Object.DontDestroyOnLoad()方法将某个Game object标记成DontDestroyOnLoad,在进入Play mode的时候会发现Hierarchy窗口中会多出一个DontDestroyOnLoad场景,它包含了之前标记成DontDestroyOnLoad的Game object。

为什么需要DontDestroyOnLoad Scene

在Unity 5.3中,所有的Game objects必须隶属于某一个场景。这样我们必须有一个特别的场景来管理这些被标记为DontDestroyOnLoad的Game objects,否则在Unload这些Game objects所属的场景的时候,这些Game objects也会被删除掉。这显然不是我们想要的结果。

因此我们引入了DontDestroyOnLoad Scene,当进入Play mode时候,我们会把所有标记为DontDestroyOnLoad的Game objects从所属的场景移入到这个特别的场景之中。

DontDestroyOnLoad Scene的特点

DontDestroyOnLoad Scene仅仅存在于Runtime,或者是Play mode。它不能从外部访问,仅仅是Unity内部用于管理标记为DontDestroyOnLoad的Game objects。

事实上从Unity 5.3开始,我们并不推荐用户使用DontDestroyOnLoad这一功能,它使得我们内部的代码逻辑复杂度增加了不少。5.3之前因为没有多场景的支持,所以并没有很好地办法绕开它并实现相同的功能。而从5.3开始我们推荐用户创建一个Manager场景,由它负责加载/卸载其它所有的游戏场景。它从游戏开始便存在一直到游戏退出,这样所有需要被标记为DontDestroyOnLoad的Game objects都应该属于这个场景。

多场景编辑的进阶

接下来我们介绍一些关于多场景编辑的进阶以及一些小Tips。

Scene Manager Setup

Scene Manager Setup可以用来保存并恢复当前的Scene hierarchy。EditorSceneManager上提供了GetSceneManagerSetup() / RestoreSceneManagerSetup()来获取和恢复Scene hierarchy。

我们可以通过ScriptableObject来保存Scene hierarchy,如下代码所示:

publicclassSceneSetupSerialization:ScriptableObject
{[SerializeField]public SceneSetup[] SceneSetups;
}

以下的代码展示了如何保存以及读取Scene manager setup。

string sceneSetupAssetPath = "Assets/SceneSetup.asset";public static void SaveSceneSetups()
{// Create SceneSetupSerializationvar sceneSetupSerialization = ScriptableObject.CreateInstance();// Set SceneManagerSetup.var sceneSetups = EditorSceneManager.GetSceneManagerSetup();sceneSetupSerialization.SceneSetups = sceneSetups;// Create and save the asset.AssetDatabase.CreateAsset(sceneSetupSerialization, sceneSetupAssetPath);AssetDatabase.SaveAssets();
}public static void LoadSceneSetups()
{// Restore SceneManagerSetup from the asset.var sceneSetupSerialization = AssetDatabase.LoadMainAssetAtPath(sceneSetupAssetPath) as SceneSetupSerialization;EditorSceneManager.RestoreSceneManagerSetup(sceneSetupSerialization.SceneSetups);
}

Lightmap & NavMesh Baking

在Unity 5.3中,Lightmap和NavMesh的烘焙都同时支持多个场景,它们之间的不同之处在于如何管理和划分烘焙的结果。

对于Lightmap Baking,我们会根据Scenes划分Lightmaps和Realtime GI数据。每个场景都只会加载和自己相关的那部分数据。

对于NavMesh Baking,因为它烘焙的结果很小,所以我们将NavMesh的数据保存在一个asset当中,每个场景都会引用到这个asset并能够找到自己所关联的那部分数据。

另外用户也可以通过脚本进行Baking,Lightmapping.BakeMultipleScenes()和NavMeshBuilder.BuildNavMeshForMultipleScenes()都支持一次烘焙多个场景。

Scene Dirty Track

Unity内部大多通过Undo系统来实现Scene dirty追踪。Unity 5.3为了支持多场景编辑,我们通过在Undo操作中保存Scene handles来扩展Undo系统。

另外我们增加了Undo.MoveGameObjectToScene()方法来支持场景之间Game object移动的Undo。同时Scene结构上面也有一个Scene.isDirty属性用于查询某个Scene是否被修改。

“Ctrl + S”的行为

在这里有一个问题想跟大家讨论的是“Ctrl + S”的行为。在5.3以前,无论场景是否Dirty,只要用户按下”Ctrl + S”,我们一定会保存该场景。而在5.3中,因为多场景编辑的引入,我们改变了这一行为。

从5.3开始,”Ctrl + S”只会保存Dirty的场景。试想如果用户打开了上百个场景,只修改了其中某一个场景,如果“Ctrl + S”还是保存非Dirty的场景,保存速度会受到比较大的影响。

这个改动会影响到一些Editor的工具。比如某个Editor的工具创建了一个Game object,由于没有使用Undo系统(Undo.RegisterCreatedObjectUndo),使得场景未标记成Dirty。这样当在保存的时候,Unity并不会去真正保存这个场景。

在此推荐大家使用Undo系统来注册Undo操作,从而能够正确的将受影响的场景标记为Dirty。我们也乐于听到大家的反馈,来看看我们是否有办法更好的处理这个问题。

Scene加载的延迟Awaking

在多场景的使用中,一个比较有意思的地方就是Scene加载过程中的Delay awaking。在介绍它之前我们来看看Unity内部加载一个Scene所需的步骤。

Scene加载的两个步骤

Unity内部场景的加载分为两步:

Loading。是指从文件、内存(主要是Streamed scene

AssetBundle)中加载Scene的内容,创建并读取所有相关的Game objects、Assets以及Scene game

managers。所有的IO操作都在这一步完成,所以它是比较耗时的过程。当这一步完成的时候,我们内部会将加载进度标记为90%。

Awaking。主要是一些轻量级的操作,比如在Transform的Awaking的时候,我们会将Game objects加入到它所属于的Scene。

我们这里所说的Scene加载过程中的Delay awaking就是指第二步。

比如用户有一个大场景划分成了若干个子场景,在所有场景加载完毕我们才会开始Game play。这时我们就可以推迟所有子场景的Awaking。当所有的加载第一步完成了,我们才进行所有场景的Awaking。

用户可以通过将AsyncOperation.allowSceneActivation设置成false来阻止Scene的Awaking,示例如下:

string name = “TestScene”;AsyncOperation operation = SceneManager.LoadSceneAsync(name, LoadSceneMode.Additive);operation.allowSceneActivation =false;

当加载进度AsyncOperation.progress到达90%的时候,就可以将allowSceneActivation设置成true来允许Scene awaking。

using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;/// <summary>
/// 场景管理测试类
/// </summary>
public class ChinarSceneManager1 : MonoBehaviour
{/// <summary> /// 初始化函数/// </summary>void Start(){SceneManager.activeSceneChanged += SceneManager_activeSceneChanged; //订阅此事件可在活动场景发生更改时收到通知。StartCoroutine(SetActiveSceneEnumerator());                         //活动场景切换时,会收到通知,打印输出"活动场景变更了"SceneManager.sceneLoaded += SceneManager_sceneLoaded;               //委托 —— 加载场景时收到通知SceneManager.LoadSceneAsync(1);                                     //异步加载,加载方式:单一SceneManager.sceneUnloaded += SceneManager_sceneUnloaded;           //委托 —— 卸载Scene时收到通知}/// <summary>/// 设置场景为活动场景/// 必须要保证:目标场景被加载后,才可以正确设置活动状态/// </summary>IEnumerator SetActiveSceneEnumerator(){yield return SceneManager.LoadSceneAsync(1, LoadSceneMode.Additive); //等待场景加载完毕后,再向下执行SceneManager.SetActiveScene(SceneManager.GetSceneAt(1));             //设置场景为活动场景}/// <summary>/// 活动场景变动时被调用/// </summary>private void SceneManager_activeSceneChanged(Scene arg0, Scene arg1){print("活动场景变更了");}/// <summary>/// 场景被加载后,被调用/// </summary>private void SceneManager_sceneLoaded(Scene arg0, LoadSceneMode arg1){print("场景被加载了");//必须要保证:目标场景被加载后,才可以正确设置活动状态SceneManager.SetActiveScene(SceneManager.GetSceneByName(a.name));this.initUI();}/// <summary>/// 场景被卸载时,被调用/// </summary>private void SceneManager_sceneUnloaded(Scene arg0){print("场景被卸载了");}
}

Unity SceneManager场景管理Chinar详解API_Chinarcsdn的博客-CSDN博客

Unity多场景管理相关推荐

  1. Unity AssetBundle内存管理相关问题

    AssetBundle机制相关资料收集 最近网友通过网站搜索Unity3D在手机及其他平台下占用内存太大. 这里写下关于Unity3D对于内存的管理与优化. Unity3D 里有两种动态加载机制:一个 ...

  2. Unity中场景生命周期的监听: EditorSceneManager

    本文分享Unity中场景生命周期的监听: EditorSceneManager 在Unity开发中, 有时我们需要在场景的某些生命周期时做一些特定的操作, 特别是在Editor模式下的一些工具代码. ...

  3. 游戏场景管理(二)视锥体剔除

    在学习场景管理之前,我们要先学习一下视锥体剔除(VFC),因为无论你使用什么空间划分算法,划分的空间都要进行视锥体剔除,被剔除的空间内部的所有物件都会被抛弃以此来加速渲染或碰撞.这也是场景管理的核心目 ...

  4. unity 前端场景搭建UI框架的设计

    在 Unity 前端场景中搭建 UI 框架时,可以采用以下设计方案: 基础组件库:设计一套基础组件库,包括常用的 UI 控件,如文本.按钮.图像等,组件库的设计应该尽量简单易用,方便开发者快速搭建 U ...

  5. [Unity] 包括场景互动与射击要素的俯视角闯关游戏Demo

    [Unity] 包括场景互动与射击要素的俯视角闯关游戏Demo ​ 一个简单的单机闯关小游戏,主角到达终点即为胜利,关卡中有两种怪物能够对主角造成伤害,此外还有灯.陷阱.宝箱等场景互动要素,主角从宝箱 ...

  6. BSP场景管理方法简介

    BSP(Binary Space Partition,二叉空间分割)方法,在大型3d游戏场景管理方面,可以认为是已经证明了的,最成熟的,最经得起考验的场景管理方法.诸如虚幻系列引擎(Unreal 1, ...

  7. gaia引擎分析(二)场景管理

    只是粗略的分析原理,大虾轻喷~~ Gaia引擎中没有场景管理器(scenemanager)这种东西,但是并不是没有场景管理,而是在cGameHost类中有一课场景树进行场景组织.一棵四叉树用来进行剪裁 ...

  8. 【转】Unity Scene场景自定义坐标轴

    [转]Unity Scene场景自定义坐标轴 来自:https://blog.csdn.net/cheng624/article/details/70859054 多看看别人的代码是没有坏处的,即使学 ...

  9. 转:OGRE场景管理器介绍

    一个场景代表在虚拟世界中显示的物品.场景可以包括静态几何体(比如地形或者室内),模型(比如树.椅子等),光和摄像机.场景有下面种类.室内场景:可能由走廊.有家具的屋子和挂着装饰品的墙组成.室外场景:可 ...

最新文章

  1. SpringMVC+SwfUpload进行多文件同时上传
  2. Linux下的文件系统修复
  3. 4步win7下简单FTP服务器搭建(试验成功)
  4. 扩大mysql的cpu_MySQL CPU占用超过100%
  5. 最高月薪25K!一周收到7个15K以上的offer,他是如何做到的?
  6. 前端性能毫秒必争综合方案
  7. U811.1接口EAI系列之三--采购订单生成--VB语言
  8. 《Java核心技术》读后感(JAVA 小虚竹)
  9. ActivityGroup的使用
  10. 多媒体视频开发_(30)使用ffmpeg在视频中进行抽帧
  11. 【游戏】GBA经典游戏《逆转裁判》1、2、3合集发布
  12. 虚拟主机二级域名(m.dedehtml.com)绑定到织梦子目录(m)做手机站
  13. 线上线下一体化趋势下,零售品牌如何利用线上营销为营收赋能?
  14. 博科SAN交换机基本配置(华为SNS系列交换机为例OEM博科)
  15. iOS开发之《英语词汇学习》
  16. Chrome开发者工具-阅读列表
  17. 通过sql给表添加字段
  18. 信息学奥赛一本通:1064:奥运奖牌计数
  19. 学编程需要的电脑配置
  20. (Ubuntu)下载及安装Genymosion模拟器并配置Android Studio

热门文章

  1. 【Overload游戏引擎】源码分析之十三:OvRendering函数库(十一)
  2. 麦克利兰的成就动机理论(1966)--zz
  3. 阿里版ChatGPT突然上线邀测!大模型热战正剧开始,这是第一手体验实录
  4. mysql中dtp是_DTP是什么运输条款
  5. 人渐渐成熟的15个迹象
  6. 和人工智能一起选剧本 | 拍什么电影,AI说了算?
  7. OpenHarmony 3.2 Beta Audio——音频渲染
  8. 5、USB协议学习:USB的枚举过程
  9. vue dayjs 构造日历组件
  10. 英语学习时间:《新概念英语第二册》Lesson 1 笔记