Wonderland Engine for Unity Developers

本页面提供从Unity到Wonderland Engine的脚本映射,并提供构建解决方案的差异列表。

如果您更喜欢视频格式,请查看我们在YouTube频道上的切换指南:

YouTube Video

脚本编写 

Wonderland Engine在浏览器中运行,该浏览器已内置JavaScript运行时。 这使其成为Web引擎的最佳脚本语言选择,因为无需下载额外的内容。

要创建脚本,请在Wonderland Editor的资产浏览器中右键单击,并创建一个新的JavaScript/TypeScript组件。它附带一个基本模板,帮助您入门。

一个适合JS/TS的IDE是Visual Studio Code

关于Wonderland Engine的API与Unity的区别的更多信息,请参阅代码部分

TypeScript 与 JavaScript 

TypeScript为JavaScript增加了静态类型检查,使其更接近于C#并极大地改善了IDE的代码补全。 我们通常推荐熟悉Unity的开发者使用TypeScript。

Wonderland Engine会自动为您处理所有tsconfig.json的设置,只需从资产浏览器中创建一个TypeScript组件即可。

打包 

虽然Unity工作流通常使用编辑器内预览,但在Wonderland Engine中,最终打包过程非常快(不到1秒),因此浏览器中的最终应用程序可以用作预览。

每当您重新打包时,浏览器页面将重新加载,并检查视图 > 偏好设置使其在每次保存后自动运行。

要部署应用程序,只需将项目的deploy文件夹内容上传到Web服务器。或者,您可以通过可以在视图 > 插件中激活的"Wonderland Cloud Publish"插件上传。

多个场景 

Wonderland Engine允许在_多个项目文件(.wlp)_中创建的多个场景之间切换。查看切换场景教程获取说明。

您还可以在运行时流式传输场景的部分内容,请参阅在运行时流式传输.bin文件教程

预制件 

Wonderland Engine尚未具备与预制件等效的功能。相反,您可以在场景中设置一个原型,并使用object.clone()复制其层次结构及所有组件。

或者,将预制件对象移动到一个单独的场景,以便在运行时使用engine.loadPrefab(…)加载并实例化它。

导入资产 

在Wonderland Engine中,如果导入了场景文件(通过从资产浏览器拖放到场景视图或场景大纲中,或通过将图像文件拖动到材质的纹理槽中),它就会被链接并监视更改。场景文件中发现的资源将被提供给项目,并且可以在“资源”视图中查看。

在从资产浏览器导入文件之前,它在项目中不可用。与您在Unity中可能习惯的相比,“资产浏览器”可以被视为一个文件浏览器。

优化资产 

一旦资产被导入,可以进一步优化:

  • 网格可以自动简化以减少顶点数
  • 网格可以均匀缩放
  • 图像会自动压缩
  • 图像可以降级

这些设置可以在“资源”视图中找到。

目录 

  • deploy包含打包的最终结果。
  • static包含被原样复制到deploy的文件。
  • cache包含缓存的资产编译结果,例如压缩的图像。通常可以安全删除,但需要时间重新生成。

这些设置可以在“资源”视图中找到。

动画 

动画通过animation组件类型播放。如果该组件附加到目标皮肤的某个骨骼/关节上,可以使用retarget复选框重新定位蒙皮动画。

混合、编辑关键帧或关键帧事件尚不支持。

物理 

刚体通过physx组件类型创建。场景可以在编辑器中通过调试 > 模拟物理 (Alt + S)进行模拟。

网络 

点对点网络可以通过社区支持的Wonderland Engine PeerJS Networking实现。

它使用WebRTC,在一定规模上可以使用默认的PeerJS服务器基础设施。

另外,社区已集成Colyseus用于多用户。

用户界面 

用户界面可以通过cursor, cursor-target,以及collider组件手动设置。

以下基于HTML5 Canvas的2D用户界面由社区维护:Lazy Widgets project

术语 

术语UnityWonderland Engine
项目一个项目文件可能多个项目文件共享一个项目根目录
检查器视图属性视图

代码 

以下是一些常见代码模式及其Wonderland Engine等效项:

自定义行为 

在Wonderland Engine中,我们使用“Component”代替“MonoBehaviour”。要编写一个,只需扩展Component类

UnityWonderland Engine (JavaScript)Wonderland Engine (TypeScript)
 1using UnityEngine;
 2using System.Collections;
 3
 4public class MainPlayer : MonoBehaviour
 5{
 6  [field: SerializeField]
 7  public string myName;
 8
 9  string privateName;
10
11  void Start()
12  {
13    Debug.Log("My name is", this.myName, this.privateName);
14  }
15
16  void Update()
17  {
18    Debug.Log("Delta time:", Time.deltaTime);
19  }
20}
 1import {Component, Property} from '@wonderlandengine/api';
 2
 3export class MainPlayer extends Component {
 4  static TypeName = 'main-player';
 5
 6  /* Properties are exposed in the editor */
 7  static Properties = {
 8      myName: Property.string("Alice")
 9  };
10
11  privateName = "Bob";
12
13  start() {
14    console.log("My name is", myName, privateName);
15  }
16
17  update(dt) {
18    console.log("Delta time:", dt);
19  }
20}
 1import {Component} from '@wonderlandengine/api';
 2import {property} from '@wonderlandengine/api/decorators.js';
 3
 4export class MainPlayer extends Component {
 5  static TypeName = 'main-player';
 6
 7  /* Properties are exposed in the editor */
 8  @property.string("Alice")
 9  myName!: string;
10
11  privateName = "Bob";
12
13  start() {
14    console.log("My name is", myName, privateName);
15  }
16
17  update(dt: number) {
18    console.log("Delta time:", dt);
19  }
20}

与Unity中一样,某些UI元素将为参数生成。

获取游戏对象上的组件 

UnityWonderland Engine
1gameObject.GetComponent<MyComponent>();
1// 首选,因为类型可以被推断
2this.object.getComponent(MyComponent);
3
4// 或者:通过类型名
5this.object.getComponent('my-component');

将组件附加到对象 

UnityWonderland Engine
1MyComponent sc = gameObject.AddComponent<MyComponent>();
2sc.property = "set";
1this.object.addComponent(MyComponent, {property: "set"});
2
3// 或者:通过类型名
4this.object.addComponent('my-component', {property: 'set'});
5
6// 或者:推迟激活
7const sc = this.object.addComponent('my-component', {active: false});
8sc.property = 'set';
9sc.active = true;

获取子对象 

UnityWonderland Engine
1
2gameObject.transform.GetChild(0);
1this.object.children[0];

获取父对象 

UnityWonderland Engine
1gameObject.transform.parent
1this.object.parent;

设置材质属性 

设置颜色或纹理等各种材质属性。

UnityWonderland Engine
1var mesh = gameObject.GetComponent<MeshRenderer>();
2mesh.material.SetColor("_Color", Color.green);
1const mesh = this.object.getComponent(MeshComponent);
2mesh.material.diffuseColor = [0.0, 1.0, 0.0, 1.0];

数学 

JavaScript不支持操作符重载,这意味着我们对数学代码采取不同的方法。

在许多情况下,完全可以避免编写数学代码,因为Wonderland Engine的Object3D API包含许多用于操作变换的函数,这些函数在WebAssembly中高效实现:

1/* 在多个轴上平移对象。为了避免向量的垃圾产生,使用一个临时向量成员或在模块范围内使用常量。 */
2this.object.translateWorld([1, 2, 3]);
3
4/* 绕Y轴旋转对象。 */
5const AxisY = [0, 1, 0];
6this.object.rotateAxisAngleDegLocal(AxisY, 25);

垃圾回收 

JavaScript是一种垃圾回收语言,这可能导致由于自动垃圾回收而无法预测的中断,因此最好避免在堆上添加列表/向量或对象的内存,因为这些内存不是可以轻松回收的。

最佳实践是创建临时向量/四元数,无论是在构造函数中还是在自定义组件的主体中并重复使用,或者如果使用得当,在类的模块范围内使用。常量向量如[0, 1, 0]最好在模块范围内声明为const AxisY = [0, 1, 0]

数学库 

我们推荐使用glMatrix,它是一个针对JavaScript/TypeScript性能和垃圾回收优化的数学库。它已经随我们的默认模板和默认组件安装,因此您很可能不需要自己安装。

glMatrix在计算向量或四元数的函数中,不会返回新分配的向量,而是期望将第一个参数作为结果写入的目标。返回基元的函数将正常返回结果。

在此处找到glMatrix数学库的完整文档

UnityWonderland Engine
1var v = new Vector3(1, 2, 3);
2v.Set(3, 2, 1);
1const v = vec3.fromValues(1, 2, 3);
2vec3.set(v, 3, 2, 1);
1var a = new Vector3(1, 2, 3);
2var b = new Vector3(1, 2, 3);
3
4var v = a + b;
5var a = a * b;
6var a = 2.0*a;
1import {vec3} from 'gl-matrix';
2
3const a = vec3.fromValues(1, 2, 3);
4const b = vec3.fromValues(1, 2, 3);
5
6const v = vec3.add(vec3.create(), a, b);
7vec3.mul(a, a, b);
8vec3.scale(a, a, 2.0);

JavaScript 与 C# 

从C#转到JavaScript的一些显著差异包括:

  • 始终在访问成员变量时加上this.
  • var创建一个“全局变量”,不限制在当前作用域内。最佳实践是避免使用它,而用letconst代替,这些会创建有作用域的变量。