Unity Project Tiny HTML5 3D游戏开发入门
相信大家对我们上周发布的《Unity C#版的HTML5 3D游戏解决方案正式来了》,还意犹未尽。虽然在文章中我们明确说明教程会在本周上线,但是小编在后台还是收到了无数教程和工程的请求。经过约一周的内容整理,今天终于能呈现给大家。
Unity Project Tiny是一款高度模块化的、轻量级跨平台3D解决方案,支持HTML5、Android、iOS、Windows、Mac和Linux等平台。在HTML5方面,Unity Project Tiny可以构建asmjs和WebAssembly。
在12月5号,万维网联盟W3C宣布WebAssembly核心规范为正式标准,使其成为继HTML、CSS、JavaScript之后支持代码在浏览器中运行的第四种Web语言。WebAssembly早已支持所有主流浏览器,本文所聚焦的就是构建WebAssembly相关的内容。
开发环境准备
本文主要以Windows 10操作系统进行讲解。在开发之前,我们对开发环境要进行以下准备。
1、使用Unity 2019.3.0f1或以上版本。
2、使用Visual Studio 2017或以上版本,并安装以下工作负载:
C++桌面应用开发
.NET桌面应用开发
3、安装NET框架4.7.1开发包,下载地址:
https://www.microsoft.com/en-us/download/details.aspx?id=56119
TinyRacing示例项目入门
TinyRacing示例项目是掌握Project Tiny所需组件的最简单方法。
下载TinyRacing示例项目:
https://github.com/Unity-Technologies/ProjectTinySamples
下载完成后,我们使用Unity打开TinyRacing子文件夹即可。
我们注意到,项目的根目录中还有一个Tiny3D子文件夹,此文件夹中包含一个基本的“ HelloWorld”示例项目。
Unity Project Tiny功能支持
下表为Unity Project Tiny目前的功能支持情况,我们将在后续版本中不断添加功能支持。
支持平台
支持Windows,Mac、Linux、HTML5(asmjs和WebAssembly)、Android和iOS。
3D图形
Unity.Tiny.Rendering程序集中提供了轻量级的3D渲染器。该渲染器的功能会在将来进一步扩展。
2D图形
在后续版本中,将支持2D图形。
输入
轻量级输入功能可通过Unity.Tiny.Input程序集获取。
音频
轻量级音频功能可通过Unity.Tiny.Audio程序集获取。
动画
在后续版本中,将支持动画功能。
物理
虽然Unity.Physics可以工作,但由于缺少固定时间更新,而且平台上仍然存在无法达到足够高帧率的重大问题。
在后续版本中将提供全面的支持,届时TinyRacing将切换为使用Unity.Physics。
UI
2020年将推出复杂UI解决方案。同时,我们正在寻求在短期内提供轻量级UI解决方案。
ECS
支持Unity.Entities。
Job System
支持Jobs API。
Burst Compiler
支持部分Burst Compiler功能,在后续版本中将提供全面支持,即Burst Compiler编译的作业(Burst-compiled jobs)。Burst Compiler仅适用于Release构建版本。
构建WebAssembly包
1、下载并打开TinyRacing示例项目项目后,我们双击打开Assets/Scenes/TinyRacing场景。
一开始加载场景可能会比较慢,这是因为会载入子场景DOTS Subscene,等可以看到完整游戏内容后,我们再进入下一步。
2、我们展开Assets/Build文件夹,选中Wasm。
3、在检视窗口中,我们找到Dots Runtime Build Profile,设置Configuration设置为Release。
4、点击右上角箭头,选择构建方式为“Build”,点击Apply保存构建设置文件。
5、点击“Build”开始构建。在首次构建时,需要保持网络通畅,因为会启用Tiny的构建工具Bee,并下载相关工具。
6、在构建成功后,我们可以在Assets同级目录的Builds文件夹下,找到构建完成的Wasm文件夹。
7、现在构建WebAssembly已经完成了,我们可以发现Build出来Release的Wasm文件大约有1MB多,但实际上发布到服务器端,还可以再压缩。压缩过程和发布部分会在下文中介绍。
Tiny项目剖析
DOTS运行时兼容的Unity项目与普通Unity项目非常相似,但存在以下区别:
场景必须完全由包含可转换组件的DOTS子场景组成,或者在顶层场景中的GameObjects游戏对象上使用“Convert to Entity”组件。
我们可以将未转换的GameObjects游戏对象用作创作助手,但这些文件不会保留在游戏模式或内置的应用程序中。
我们必须使用Assembly Definition(程序集定义)将运行时代码编译到程序集中。
项目代码只能使用DOTS API。由于一些源代码兼容性的原因,支持DOTS运行时的项目不支持UnityEngine API。
如果要使用Build或者Build and Run进行构建,必须使用带有DOTS运行时构建配置文件的Build Settings Asset来完成。
这些要求将在下文进行更详细的讨论。现在,我们将以TinyRacing项目为示例,介绍所有相关的要求。
场景和子场景
由于DOTS运行时是Pure DOTS(纯DOTS),因此场景必须可以转换为其DOTS实体和组件表示形式。
DOTS运行时的世界中没有GameObjects游戏对象或MonoBehaviours脚本。任何不可转换的内容无法在运行时使用。
在后续的版本中,我们将简化下面介绍的设置。此外,在Unity编辑器中,我们将提供关于可以转换和不能转换的内容的一些信息。
目前,Project Tiny的Unity场景必须至少有一个子场景。Unity场景中除了子场景外应该没有其它内容,因为此处的任何游戏对象都不会自动转换。
每个子场景中的所有内容都会在构建时自动转换。在TinyRacing中,Scenes/TinyRacing.scene中的场景包含一个子场景,即DOTS Subscene。
游戏对象和行为创作
通过游戏对象转换创作工作流程,我们可以通过GameObjects游戏对象和MonoBehaviours脚本,创建DOTS运行时数据。
标准行为和资源的一部分已定义了转换代码,例如:MeshRenderers、MeshFilters、材质和纹理资源。但是,游戏逻辑需要完全使用ECS组件定义,并使用ECS系统执行。
我们将在后续发布支持行为的详细列表。此外,我们正在努力扩展编辑器,以便在UI中提供有关支持内容的信息以及如何进行转换的指南。
根程序集
DOTS运行时及其Project Tiny仅支持纯DOTS代码。提供的所有功能在设计时都考虑了DOTS,并充分利用ECS、C#Job System和Burst Compiler的优势。
为了强制将纯DOTS代码与引用UnityEngine类型的代码分开,或者让这些代码仅在Unity编辑器中工作,游戏脚本必须编译为一个或多个使用Assembly Definition资源定义的程序集。
我们必须在Build Settings资源中指定一个程序集定义作为根程序集(Root Assembly)。根程序集必须引用包含代码使用的类和类型的任何程序集。 例如:对于核心DOTS功能,它必须引用Unity.Entities,但也可以引用Unity.Tiny.Input和Unity.Tiny.Rendering来访问Project Tiny提供的输入和渲染功能。
如果要为项目创建其它程序集,则根程序集也必须直接引用,或者通过其它引用的程序集引用它们,应用程序中不包括不属于程序集的任何脚本。
有关设置参考和其它程序集属性的信息,请访问:
https://docs.unity3d.com/Manual/class-AssemblyDefinitionImporter.html
在TinyRacing中,根程序集由“Scripts/TinyRacing”文件夹中的TinyRacing.asmdef定义。
DOTS .NET子集
为DOTS运行时编写的所有代码均基于针对代码大小和性能进行优化的.NET框架的子集构建,因此许多标准.NET不可用。
我们仍在开发这部分功能,目标是对加入的功能提供大量选择,从而提供最大程度的灵活性,让项目区分使用和不使用的项目。因此,仅仅因为代码是使用Unity C#项目进行构建的,并不能够保证它将使用DOTS运行时构建系统进行构建。
我们可以生成一个单独的DOTS C#项目,该项目针对有限的.NET子集。
DOTS .NET子集的限制包括:
没有运行时反射,即System.Reflection和相关功能。
没有重量级功能,例如:System.Xml。
没有非通用集合,例如:List <T>可用,List没有。
缺少许多较复杂的通用集合。此问题将在不久后得到解决,Unity.Collections可以提供更高效的集合,包括:NativeList、NativeSet、NativeHashMap和NativeMultiHashMap。
没有通用的ToString和Equals功能,每种类型都必须在需要时明确定义这些功能的版本。
后续版本中,我们将明确介绍关于限制的内容。
构建设置
我们使用新的构建设置机制而不是通常的Unity Build Settings窗口,来构建DOTS运行时和Project Tiny应用程序。
新的构建设置是项目中存在的资源,它们定义了构建过程:各项设置和用于执行这些步骤的步骤,也就是构建管线。它使我们轻松定义多个构建配置,并将其存储在项目中,扩展构建数据和构建步骤。构建设置可以从另一个构建设置资源继承其设置。
基于“Build Settings”资源中存在的“Build Profile”组件,我们可以使用“Build Settings”来创建DOTS运行时构建或经典的Unity构建。我们可以检查构建设置以查看其数据和触发构建。
尽管“构建设置”功能非常强大,但目前仍属于预览阶段。构建设置将来可能会发生重大变化,但核心功能将保持不变,用户界面和整体用户体验也将得到明显改善。
在TinyRacing中,Build文件夹中定义了各种Build Settings资源。
创作流程和仅编辑器可用代码
DOTS GameObject游戏对象的创作工作流程要求使用GameObjects游戏对象和MonoBehaviours脚本进行创作,使用转换系统将这些内容转换为ECS表示形式。
对于自定义组件,有以下三种方法来定义创作MonoBehaviour脚本和运行时组件:
GenerateAuthoringComponent属性。任何IComponentData都可以加入[GenerateAuthoringComponent]属性,这将自动生成一个MonoBehaviour脚本,可用于与组件中存在的字段具有相同字段的创作。
实现IConvertGameObjectToEntity的MonoBehaviour。该接口定义了将在MonoBehaviour上调用的Convert方法,并且必须使用提供的EntityManager和Entity创建所需的任何ECS组件。
GameObjectConversionSystem。这是最低级别和最强大的机制,这些系统在转换时执行,并具有原始Unity Scene数据以及目标ECS EntityManager数据的完整视图。
以上这些方法都必须在运行时使用的IComponentData中定义一个程序集,该程序集是DOTS运行时版本的一部分:根程序集或它所引用的程序集。
对于IConvertGameObjectToEntity和GameObjectConversionSystem,MonoBehaviour或转换系统代码必须位于单独的程序集中,而根程序集未引用该程序集。如果情况并非如此,则会在编译时产生编译错误。我们建议在这些程序集的名称中添加“ .Authoring”后缀。
在TinyRacing项目中,我们可以看到直接在TinyRacing程序集中使用的GenerateAuthoringComponent的混合,以及单独的TinyRacing.Authoring程序集,该程序定义了一些更复杂的转换代码。它使用自定义的GameObjectConversionSystem来处理一些手动UI和纹理,以便在运行时显示数字。
新建Project Tiny项目
通过使用Project Tiny模板,新项目的设置过程将在不久后大大简化,具体可以参考TinyRacing和Tiny3D。如果希望自己设置项目, 请按照以下步骤操作。
项目和资源包的设置
1、在Unity Hub中使用Unity 2019.3.0f1新建项目,Template模板选择Universal Render Pipeline。Project Tiny 3D渲染器被设计为URP渲染的一个子集。
2、从Package Manager资源包管理器添加以下必要的资源包:
com.unity.entities
com.unity.dots.runtime
com.unity.tiny
com.unity.tiny.rendering
com.unity.platforms
3、根据不同构建与发布的平台,从Package Manager资源包管理器安装相应的资源包:
com.unity.platforms.desktop
com.unity.platforms.windows
com.unity.platforms.linux
com.unity.platforms.macos
com.unity.platforms.android
com.unity.platforms.ios
com.unity.platforms.web
com.unity.tiny.desktop
com.unity.tiny.web
请注意:根据实际情况,开发者可以忽略不打算构建的平台。
4、在Assets同级目录的Packages资源包中设置manifest.json,指定合适的版本:
"com.unity.dots.runtime": "0.1.0-preview.5",
"com.unity.tiny": "0.20.0-preview.3",
"com.unity.tiny.desktop": "0.20.0-preview.2",
"com.unity.tiny.rendering": "0.20.0-preview.3",
"com.unity.tiny.web": "0.20.0-preview.2",
"com.unity.platforms": "0.1.7-preview.3",
"com.unity.platforms.android": "0.1.7-preview.6",
"com.unity.platforms.desktop": "0.1.7-preview.2",
"com.unity.platforms.ios": "0.1.7-preview.10",
"com.unity.platforms.linux": "0.1.7-preview.3",
"com.unity.platforms.macos": "0.1.7-preview.3",
"com.unity.platforms.web": "0.1.7-preview.6",
"com.unity.platforms.windows": "0.1.7-preview.4",
代码部分设置
1、在项目窗口的Assets文件夹中创建一个名称为GameSystems的文件夹。
2、在GameSystems文件夹内,创建一个Assembly Definition资源。
右键单击Create,选择Create > Assembly Definition。
重命名为GameSystems。
取消勾选Use GUIDs。
在检视窗口中添加以下程序集作为引用:
Unity.Entities Unity.Transforms Unity.Mathematics Unity.Tiny.Core Unity.Tiny.Rendering Unity.Tiny.EntryPoint Unity.Tiny.Main
3、在GameSystems文件夹内,创建两个C#脚本文件,并分别重命名为:RotateComponent和RotateSystem。
4、编辑RotateComponent.cs,将内容替换为以下内容。这将定义一个新的ECS组件,并使其可以在编辑器中使用。
using Unity.Entities;
[GenerateAuthoringComponent]
public struct RotateComponent : IComponentData
{
public float Speed;
}
5、编辑RotateSystem.cs脚本,将内容替换为以下内容。这会定义一个新的ECS系统,该系统使用上述组件来更改实体的旋转。
using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;
public class RotateSystem : ComponentSystem
{
protected override void OnUpdate()
{
var dt = Time.DeltaTime;
Entities.ForEach((ref Rotation rot, ref RotateComponent rc) => {
rot.Value = math.mul(rot.Value, quaternion.RotateY(dt * rc.Speed));
});
}
}
场景设置
1、我们创建一个新场景,以用作顶层Unity场景,命名为Main.unity。
2、在Main.unity中,创建一个新的空白游戏对象作为子场景的根节点。
3、右键单击该游戏对象,然后选择“New SubScene from Selection”,删除现在作为子场景的子级创建的空白游戏对象。
4、将“Main Camera”和“Directional Light”游戏对象复制到子场景中,也就是在子场景下的层次结构中。
目前,摄像机和光照有两种不同的表示形式,具体取决于它们是在DOTS运行时世界还是DOTS Hybrid混合世界中运行。目前项目暂不兼容这些表示形式。
子场景中的摄像机和光照将用于DOTS Runtime / Project Tiny构建中。在编辑器中进行预览时,编辑器将使用顶层Main场景中的图像。这些问题将在以后的版本中解决。
5、在子场景中创建一个立方体。依次选择Create >3D Object > Cube。然后在Z轴上向前移动立方体,将其放大,以便可以在摄像机中看到。
6、为立方体添加Rotate Component组件。
7、设置Speed为0.2.
构建设置
1、点击Create >Build > Build Settings,为DOTS运行时创建Build Settings资源,重命名该资源为Wasm。
2、我们将之前创建的Root Assembly程序集定义GameSystems拖到Root Assembly栏内。
3、如果场景列表不存在,添加一个Scene List场景列表到Build Settings组件中。
4、添加Main.unity场景到场景列表中。
在Scene List场景列表部分中,把Size设为1,或设为构建中将加入的场景数量。
将Main.unity场景资源拖到Size字段下方的属性栏中。
5、选择构建目标平台,即Target选项,和构建类型即Configuration选项。我们将Target设为Web (Wasm),把Configuration设为Develop。
6、点击右上角的Build and Run,目前Web平台只能Build构建,不能Run运行。
运行和调试
构建设置
Build Settings是构建和运行项目的主要位置。例如:在TinyRacing项目中,在查看Build/Windows-DotNet或Mac等平台的构建设置时,右上方会显示Build或Build and Run按钮。
单击Build将生成结果,并默认将结果放在项目的Build文件夹中。点击Build and Run将构建并运行生成的构建版本。
面向Web平台,我们将必须手动启动Web服务器以启动构建。我们可以使用“http-server”npm程序包。由于Web浏览器的安全性限制,不支持直接通过file://的URL运行项目。下文会介绍Web版本localhost搭建方法示例。
DOTS C#项目
我们已经详细介绍了C#和环境约束,现在可以创建与Unity分离的C#项目,该项目针对使用DOTS运行时构建期间使用的.NET框架和程序集。
我们可以点击Assets> Open DOTS Runtime C#Project来构建项目。项目解决方案的名称为项目名称,结尾处带有“ -Dots”。
通过编辑器至少构建了一次构建设置资源后,它将在DOTS C#项目中用作目标。如果仅进行代码更改,则可以直接从IDE进行构建和运行。目前该功能已经在Visual Studio和Rider中通过测试,但是将来会继续扩展功能的支持范围。
.NET 构建 vs il2cpp构建
我们可以使用Mono的.NET运行时或Unity的il2cpp运行时,来构建DOTS运行时的构建版本。使用.NET构建时,最终结果是纯.NET应用程序,带有本地代码共享库。一般来说,.NET版本用于开发过程,而il2cpp版本会用作最终版本。
调试
我们使用.NET构建配置创建DOTS C#项目,并在IDE中打开脚本后,我们可以设置断点,并像平时一样运行和调试。
目前暂不支持在il2cpp构建中调试C#代码。这是一个很大的限制,将在后续的版本中修复。
编辑器内运行游戏
Project Tiny项目可以在编辑器中运行,但是由于编辑器(通过DOTS Hybrid实现)和Standalone(通过DOTS运行时实现)的渲染、输入等功能还不完善,所以存在编辑器运行效果与最后发布效果不一致的情况。
虽然TinyRacing项目可以正常运行,但是也存在这样的情况,在未来的版本中我们会进一步改善。
Localhost搭建运行WebAssembly
在本地运行基于Project Tiny构建的HTML5应用时,我们推荐使用Http-server。我们可以通过Node.js的npm工具,在命令行中输入npm install http-server -g,下载安装Http-server。
现在我们启动Http-server,来查看TinyRacing的WebAssembly本地运行的效果:
1、找到TinyRacing/Builds/Wasm文件夹。
2、在命令行工具中,通过cd指令进入该文件夹。
3、输入http-server,启动本地http服务。
4、在浏览器地址栏输入http://127.0.0.1:8080,打开TinyRacing.html。
5、通过浏览器的开发者模式查看,这里使用Chrome > Developer Mode > Network。
我们通过观察可以发现TinyRacing.wasm的资源占用有1.2MB,这个资源是可以压缩的。
6、回到命令行工具,按下Ctrl + C,中断http-server。
7、输入cd ..,回退到上一级目录。
8、输入gzip -r Wasm,将Wasm文件夹的内容全部进行Gzip压缩。
9、再使用cd进入Wasm文件夹,输入http-server -g,运行gzip压缩模式,运行Http-server。
10、刷新原网页。
我们发现,现在所有的文件都变小了,TinyRacing.wasm只有357KB。
常见问题
在运行时,出现有关“Cannot find TypeIndex for type hash”的错误。
例如:“ System.ArgumentException: Cannot find TypeIndex for type hash 9701635103632511287. Ensure your runtime depends on all assemblies defining the Component types your data uses.”
转换系统生成的数据引用了已输出可执行文件中不存在的类型。我们可以通过在“Logs / SceneExportLog.txt”内部的构建输出目录中查找实际类型的名称。
通常在项目文件夹内的Builds文件夹中,位于和构建设置相同名称的文件夹中。寻找给定的TypeIndex显示为:0x86a321b9ac79d137 - 9701635103632511287 - Unity.Rendering.RenderBounds
这条信息提供了“Unity.Rendering.RenderBounds”类型名称。这里有下面的修复方法:
如果输出文件实际上应该使用此类型,则确保根程序集引用包含该类型的程序集。
如果输出文件不应该使用此类型,则可以过滤掉生成它的转换系统。转换系统没有正确设置过滤过程,这是该转换系统中的Bug。
在本示例中,此类型来自Hybrid混合渲染资源包,它只和DOTS Hybrid模式一起使用。我们可以添加“Conversion System Filter”(转化系统过滤器)构建设置组件来解决此问题:
1、添加“Conversion System Filter Settings”组件。
2、设置Size为1。
3、在第一个空属性栏选择Unity.Rendering.Hybrid。
当前,在为DOTS Runtime / Project Tiny构建时,应该运行的转换系统与面向DOTS Hybrid构建时运行的转换系统之间,尚无明确的区分。我们明确表示,当为DOTS运行时构建生成数据时,我们不希望执行混合渲染转换系统。这个问题将在后续的版本中解决。
我正在开发一个新项目,想要在编辑器中运行该项目,但没有任何内容得到渲染。
为了渲染基于实体的表示形式,我们需要在编辑器中安装“Hybrid Rendering”资源包。但是,该资源包没有针对与DOTS运行时和Project Tiny的兼容性进行优化。
我们需要进行其它设置,以确保构建工作正常进行,请查看之前有关“Cannot find TypeIndex for type hash”的问题。编辑器中的渲染效果与运行时中的显示效果不同。
Bee.exe是什么?杀毒软件报告是可疑程序。
Bee是我们新的构建工具。杀毒软件有时会错误地将其标记为可疑程序。我们已经在0.1.0-preview.5版本中给该程序提供了签名,升级到这个版本或更高版本后,它不会被标记为可疑程序。
已知问题
以下问题将在未来版本中解决:
1、asm.js构建:在所有构建模式下,Chrome的性能均较低。解决方法:使用WebAssembly。
2、桌面端Safari:由于sRGB的实现方法,可能会导致视觉色彩空间问题,渲染结果看起来比预期的要暗。
3、在较旧的iOS设备中,可能由于Metal实现方法缺少某项功能,而在启动时发生崩溃问题。
4、默认情况下,所有平台都会启用自动旋转功能。在将来的版本中,这项功能将可以进行配置。
5、Android平台:即使在该应用没有激活的时候,音频仍会持续播放。
6、渲染过程使用1080p内部分辨率完成,然后按比例放大/缩小到目标显示效果。在将来的版本中,渲染功能将变得可以配置,而且更加灵活。
7、在TinyRacing项目中,在编辑器中进入运行模式时,场景看起来与构建版本中的场景不同。目前我们正在解决该问题,从而统一渲染器的可视化结果。在将来的版本中,这个问题将逐步解决。
8、目前我们需要使用C++进行桌面端开发,即使面向非Windows平台的构建目标,也需要安装Visual Studio进行.NET桌面端开发,例如:Web平台。这个问题将很快修复。
9、编辑器平台必须设置为“PC, Mac & Linux Standalone”,如果将编辑器切换到其它平台,可能会出现错误。
小结
Unity Project Tiny HTML5 3D游戏开发入门指南为大家介绍到这里,赶紧下载示例程序,开始进入小游戏的开发世界吧。
下载Unity Connect APP,请点击此处。观看更多Unity官方精彩视频,请关注“Unity官方”B站账户。
扫码在“技术交流“群聊组中提问,Unity社区和官方团队帮你解答。
推荐阅读
Unite Shanghai 2020
点击“阅读原文”下载示例项目
↓↓↓