A-Frame是一个基于Web的框架,允许您在虚拟现实(VR)中创建各种应用程序,游戏,场景。 以上所有内容均可直接从您的VR头盔的浏览器中获得。 该工具对于想要在浏览器中开发VR游戏的人很有用,例如,它可以用作创建Web VR应用程序,网站,登录页面的平台。 Web BP的使用仅受您的想象力限制。 副手我可以介绍一些对BP有用的人类活动领域:教育,医学,体育,销售,休闲。
里面有什么?
A-Frame不是在纯WebGL上从0写入的,它基于
Three.js库。 因此,我建议您在开始使用A-Frame之前先了解Three.js的基本概念,尽管这不是必需的,因为A-Frame的设计目的是使您最少考虑渲染几何图形,而将重点更多地放在应用程序的逻辑上。 实际上,这就是他和框架的原因。
为此,A-Frame提出了三个要点,我们将在后面讨论。
A框架可与HTML一起使用
许多基本的A-Frame元素(例如场景,摄像机,盒子,球体等)通过具有相同前缀
a-的标签添加到场景中。 每个相似的项目都注册为自定义。 A帧(0.8.0)当前使用v0规范。
<a-scene> <a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box> <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere> </a-scene>
这个小代码片段将绘制一个WebGL场景,在该场景中将添加两个对象:具有给定参数的立方体和球体。 除了上述两个元素之外,还可以通过相同的方式将许多其他原语添加到场景中:
<a-circle>,<a-cone>,<a-cylinder>,<a-十二面体>,<a-二十面体> ,<a-八面体>,<a-平面>,<a-ring>,<a-四面体>,<a-torus-结>,<a-torus>,<a-triangle> 。 同样在A-Frame中,还有许多其他元素可以执行某些功能:
- <a-camera> -创建一个相机。 当前仅支持透视相机(PerspectiveCamera)。
- <a-obj-model>,<a-collada-model>,<a-gltf-model> -它们都加载并显示相应格式的模型。
- <a-cursor> -允许您执行各种操作的元素:单击,引导等。光标绑定到相机的中心,因此它将始终位于用户所看到的中心。
- <a-image> -在平面(<a-plane>)上显示选定的图像。
- <a-link>与标签相同,仅适用于3D场景。
- <a-sky> -舞台周围的巨大圆柱体,可以显示360张照片。 或者,您可以简单地用一些颜色填充它。
- <a-sound> -在给定位置创建声源。
- <a-text> -绘制纯文本。
- <a-video> -在飞机上播放视频。
我还要指出,我们使用DOM元素,因此可以使用标准的DOM API,包括querySelector,getElementById,appendChild等。
A框架使用ECS
ECS(实体组件系统) -应用程序和游戏设计模式。 它仅在第二部分中很普遍。 顾名思义,模式的三个基本概念是实体,组件,系统。 在经典形式中,它们按如下方式互连:我们有一些容器对象(实体),可以向其中添加组件。 通常,组件负责逻辑的单独部分。 例如,我们有一个Player对象,它有一个Health组件。 该组件将包含与玩家(对象)的补充或失去生命相关的所有逻辑。 反过来,需要系统来管理由某些组件组合的一组实体。 通常,组件可以在系统内注册具有相同名称的实体。
在A-Frame中,借助属性可以非常简单,优雅地实现此模式。 任何A框架元素-
<a-scene>,<a-box>,<a-sphere>等都用作实体,但是
<a-entity>元素当然是分开的。 他的名字不言而喻。 所有其他元素本质上都是组件的包装,并且为方便起见而制作,因为任何元素也可以使用
<a-entity>创建。 例如
<a-box> :
<a-entity geometry="primitive: box; width: 1; height: 1; depth: 1"></a-entity>
geometry-在这种情况下,是添加到
<a-entity>实体的组件 。
<a-entity>本身没有任何逻辑(在全局意义上),并且
几何图形组件实质上将其转换为多维数据集或其他形式。 同样重要的是
几何 。 它向几何图形添加材料。 该材料负责我们的立方体是否像金属一样发光,是否具有任何纹理等。 在纯
Three.js中,我们必须创建单独的几何图形,单独的材质,然后将所有这些都需要组合在缓存中。 通常,此方法可以节省时间。
A-Frame中的任何组件都必须通过特殊设计在全球范围内注册:
AFRAME.registerComponent('hello-world', { init: function () { console.log('Hello, World!'); } });
然后可以将此组件添加到场景或任何其他元素。
<a-entity hello-world></a-entity>
由于我们为组件添加了
初始化回调,因此一旦将元素添加到DOM,该回调将起作用,并且我们将在控制台中看到消息。 A-Frame组件中还有其他生命周期回调。 让我们更详细地介绍它们:
- update-在初始化期间作为init以及更新此组件的任何属性时都被调用。
- remove-在删除包含它的组件或实体之后调用。 也就是说,如果您从DOM中删除<a-entity>,则其所有组件都将调用remove回调。
- tick-每次在渲染场景之前调用。 在渲染循环内使用requestAnimaitonFrame
- tock-渲染场景后每次调用。
- 播放 -恢复场景渲染时会调用每个调用。 基本上在scene.play()之后;
- 暂停 -每当场景停止渲染时调用。 基本上在scene.pause()之后;
- updateSchema-在更新架构后每次调用。
A框架中的另一个重要组件概念是电路。 该图描述了组件的属性。 定义如下:
AFRAME.registerComponent('my-component', { schema: { arrayProperty: {type: 'array', default: []}, integerProperty: {type: 'int', default: 5} } }
在这种情况下,我们的
my-component将包含两个属性
arrayProperty和
integerProperty 。 要将它们传递给组件,您需要设置相应属性的值。
<a-entity my-component="arrayProperty: 1,2,3; integerProperty: 7"></a-entity>
您可以通过
data属性在组件内部获取这些属性。
AFRAME.registerComponent('my-component', { schema: { arrayProperty: {type: 'array', default: []}, integerProperty: {type: 'int', default: 5} }, init: function () { console.log(this.data); } }
要从要添加组件的实体获取组件的属性,可以使用经过稍微修改的
getAttribute函数。 访问A-Frame实体时,它不仅返回属性的字符串值,而且还返回上述
数据对象。
console.log(this.el.getAttribute('my-component'));
可以以大致相同的方式更改组件的属性:
this.el.setAttribute('my-component',{arrayProperty: [], integerProperty: 5})
现在让我们谈谈系统。 A-Frame中的系统以与组件相同的方式注册:
AFRAME.registerSystem('my-system', { schema: {}, init: function () { console.log('Hello, System!'); }, });
除了组件之外,系统还具有电路和回调。 只有系统只有5个:
init,play,pause,tick,tock 。 无需将系统作为组件添加到实体。 它将自动添加到场景中。
this.el.sceneEl.systems['my-system'];
如果组件与系统具有相同的名称,则该系统将位于
this.system上 。
AFRAME.registerSystem('enemy', { schema: {}, init: function () {}, }); AFRAME.registerComponent('enemy', { schema: {}, init: function () { const enemySystem = this.system; }, });
通常,需要系统来组装和管理具有相关组件的实体。 从理论上讲,这里应该有与实体集合有关的逻辑。 例如,控制游戏中敌人的出现。
通过浏览器事件在A-Frame中进行通信
的确,如果目前有一个很好的内置DOM元素的发布者-订阅者实现方案,那么为什么要重新发明轮子呢? DOM事件允许您侦听两个浏览器事件,例如按键,鼠标单击和其他用户事件。 A-Frame通过用户事件为我们提供了一种在实体,组件和系统之间进行通信的便捷方法。 为此,每个A-Frame元素都由
发出函数修补,它具有三个参数:第
一个是事件的名称,
第二个是要传输的数据,
第三个是是否应弹出事件。
this.el.emit('start-game', {level: 1}, false);
您可以使用
addEventListener以通常的方式为我们所有人订阅此事件
: const someEntity = document.getElementById('someEntity'); someEntity.addEventListener('start-game', () => {...});
事件冒泡是非常重要的一点,因为有时两个必须彼此通信的实体处于同一级别,在这种情况下,您可以将事件侦听器添加到场景元素。 如您先前所见,它可以通过
sceneEl链接在每个元素内使用。
this.el.sceneEl.addEventListener('start-game', () => {...});
总结
也许这就是我在本文中想要谈论的全部。 A-Frame可以涵盖很多不同的主题,但是本文是一篇评论,我希望读者仅关注重点。
在下一篇文章中,我们将尝试创建一个基本场景,以便测试在实践中获得的所有知识。 谢谢大家!