我如何创建回收站! 虚拟现实



上一篇文章中,我们尝试在A-Frame中创建一个基本场景,以便在实践中尝试该框架的基本概念。 在本文中,我想分享一下我在A-Frame-Recycle上创建游戏的经验。 虚拟现实 以下链接提供了项目资源库。

回收!


当我发现有关Web VR的知识时,几乎立即就创建了游戏。 尽管总的来说,我认为网络游戏无论如何对于移动设备来说都不如好的项目,更不用说个人计算机和游戏机了。 但是,在我看来,游戏是最困难的测试。 我开始思考我该怎么做。 我观看了其他项目,立即有机会使用控制器进行操作,这让我感到震惊。 而且由于我已经与从事单独垃圾收集的组织建立联系已有相当长的时间了,所以答案是自己产生的。 回收。 我们把垃圾扔进垃圾桶。 什么可能更容易。 但是事实并非如此简单,事实上,这将进一步讨论。

框架选择


在开始游戏开发时,我只知道大约2种或多或少的严肃框架:React 360,A-Frame。 显然,A-Frame最适合创建游戏。 是的,现在我知道仍然有一个PlayCanvas游戏引擎也支持VR,但是为时已晚。 而且,事实证明,A-Frame对于创建游戏也不错。

从哪里开始?


我首先研究了A-Frame开发人员提供的官方游戏示例。 这些的好处还不够。 A-Blast,A-Painter,博物馆,Super Craft以及现在的Ganters of Oasis。 在所有提出的项目中,我最喜欢A-Blast-射击游戏,您必须在其中与宇宙中最可爱的生物战斗。 因此,我想将此游戏作为我的模板。 但是没有成功。 原因是游戏的结构。 在我看来,她太混乱了,没想过。 也许并不需要更多,但是我想做些更方便,更容易理解的事情。

结构形式


A-Blast结构仅表示一个入口点-index.html文件,该文件包含一个场景,其中包含所有资产,基本游戏实体,控件以及所有常规内容。



从屏幕快照中可以看到,除了必要的组件和系统(A-Frame使用实体组件系统模式)外,还有子弹和敌人-本质上是相同的系统,但是由于某些原因有自己的包装器。 一般说这个代码不容易理解。 因此,我决定考虑如何构建此代码。 第一个想法是将场景分解为其组成部分。 为什么路由器和模板会有用,它将渲染场景的这一部分。 在搜索了第一和第二个(不,不是五分钟)之后,我什么也没找到。 尽管我是规则的支持者,但不要写自行车,但是这次我必须写我的决定。 尽管在2-3周内我遇到了Kevin Ngo的模板。 但是为时已晚。

路由器和模式




因此, 框架路由器模板进入场景。 他能做什么? 如上所述,其主要任务是渲染游戏的必要部分,例如标题屏幕,比赛场地,游戏结束屏幕等。 怎么做? 原则上,您可以在github上的模块文档中找到所需的所有内容,但总之,我们具有以下内容:

<a-scene router> ... <!-- Routes --> <a-route id="start-screen" template="start-screen"></a-route> <a-route id="game-field" template="game-field"></a-route> <a-route id="game-over" template="game-over"></a-route> <a-route id="how-to-play" template="how-to-play"></a-route> <!-- End Routes --> ... <!-- Templates --> <a-template name="controls"></a-template> <!-- End Templates --> ... </a-scene> 

  1. 我们正在将路由器组件添加到场景中。
  2. 为应用程序的每个部分添加一个路由(场景的框架)。 主屏幕的一条路线,运动场的另一条路线,等等。
  3. 通过a-templates直接渲染模板
  4. 如有必要,我们会更改路线

     this.el.systems.router.changeRoute('game-field'); 

    注意 :此示例涉及场景代码,因此我们可以直接调用路由器系统。
  5. 我们设置并连接模板,如下所示:

     AFRAME.registerTemplate('game-field', ` <a-sub-assets> <a-asset-item id="glass" src="/assets/models/glass_bottle.gltf"></a-asset-item> ... <audio id="fail" src="/assets/sounds/fail.wav" preload></audio> </a-sub-assets> <a-template name="button" options="text: EXIT; position: 0 1 4; rotation: 0 180 0; event: stop-game"></a-template> <a-entity id="indicator" indicator visible="false" position="0 1 -2" text="align: center; width: 4; color: #00A105; value: -1" ></a-entity> <a-entity game-field-manager></a-entity> `); 

    注意: a-sub-assets允许您加载资产和a-assets,但不同之处在于默认情况下会进行检查,并且如果资产已经添加,则在更改路线时不会再次添加资产。

    注意2:通常,您只能将模板与ES6模板字符串一起使用。 否则,它会变成“字符串” + var +“字符串”,不酷。 例如,凯文(Kevin)支持模板引擎。 但是为什么使它复杂化呢?

因此,您可以创建一个方便的应用程序结构,其中将包含以下内容: 组件,系统,模板,状态,库 。 仅此而已,一切都在架子上。

操作对象




首先要解决的任务是对象的操纵。 我需要一个功能,例如抢-投。 最初,我开始考虑如何从头开始创建这样的组件。 纯粹在非宗教的层面上,这样的反射是允许的:我们有一个控制器(在桌面的情况下是光标),它有一个位置。 我们也有某些对象,例如立方体,它们也有位置。 通过更改控制器的位置,我们必须更改对象的位置。 简单吗? 所以,实际上,是的,但是那行不通。 我会从很长的列表中提到几点,以使您相信这一点:

  • A帧中的光标是相机的后代,具有相对坐标;
  • 控制器的位置不够,您仍然需要考虑方向,到物体的距离,摄像机(播放器)的位置;
  • 对于具有物理物体的对象,这将根本不起作用,因为几何坐标与物体的坐标有关。

好人威尔·墨菲(Will Murphy)先生和他的朋友们做了一副超人手 。 本质上,此库包含所有必需的组件:

  • 徘徊 。 指导。 将控制器或光标指向对象(通常是整个对象)的碰撞区域
  • 可抓取 :捕获。 使用适当的按钮抓取对象并将其拖动
  • 伸缩性 :双手抓住并拉伸\挤压
  • 可拖动\可放置 :基本上需要确定事件“项目被扔到特定位置”

您可以在上述存储库中找到有关建立和连接超级手的所有信息。 我只想提请注意一些细微差别:

  • 为左右手创建单独的混合。 根据支持的设备类型将组件分开。 例如,除了oculus-touch,vive控件,windows-motion控件之外,右手还可能有oculus-go控件和gear-vr控件。 BP移动头盔的左手需要隐藏。 每个控制器必须同时包含混合动手和超级动手组件。 一个例子 ;
  • 如果您指定了对象:reycaster的.clsname,请不要忘记将其添加到可以使用控制器获取的每个元素中,否则,没有一个超级手事件会失败。 当然,如果colliderEvent:raycaster-intersection ;
  • 用鼠标拖动将2d坐标投影到3d世界中,因此最好将光标用于桌面。

添加物理


将物理学添加到框架中实际上非常简单。 为此有一个特殊的系统 。 它已添加到场景中,瞧,物理已经在您的口袋里了。

 <a-scene physics="debug: false"> <a-box dynamic-body position="0 1 -2"></a-box> <a-box id="floor" static-body></a-box> </a-scene> 

标记debug:true使您能够查看绑定到几何体的物理物体。 当您需要“概述”对象时,这很方便。

实际上,这是cannon.js的包装程序,它为您完成了比较几何体和物理体的所有繁琐工作。 同样,关于该系统的工作方式,您可以在存储库的描述中找到它。 我只想谈一谈对我的游戏很重要的一点。

我需要确保通过将按钮按到垃圾箱上来设置一定的力(按住按钮的次数越多,力就越大)。 事实证明,这项任务并不像乍看起来那样简单。 好吧,有什么复杂的? -您说,我们确实应用了Implusevoila 。 并不是真的。它设置对象沿应用到身体中心的向量的旋转。 使用这种方法,我们只能模拟一个尤尔。 但是,如果将向量设置为与平面正确的角度,则可能会获得类似于推动的效果。 但这不是我所需要的。

事实证明,设置此参数时我需要速度,对象开始沿给定方向移动。 该方向由矢量指定。 从这里开始乐趣。 如何找到这个向量? 我发现了两个选择:

  1. 获取控制器(或台式机的摄像头)的四元数,该四元数描述了其在空间中的方向。 创建向量V1 = <1,1,1>,将其乘以抛掷力,然后将方向应用于所有向量。

     const velocityVector = new THREE.Vector3(1,1,1); velocityVector.multiplyScalar(this.force); velocityVector.applyQuaternion(controllerQuaternion); this.grabbed.body.velocity.set(velocityVector.x, velocityVector.y, velocityVector.z); 
  2. 找到控制器(光标)的位置和要抛出的对象的位置。 计算两个点的方向向量。 归一化向量。 并乘以力量。

     const directionX = (trashPosition.x - zeroPosition.x); const directionZ = (trashPosition.z - zeroPosition.z); const vectorsLength = Math.sqrt(Math.pow(directionX, 2) + Math.pow(directionZ, 2)); const x = (directionX / vectorsLength) * this.force; const y = this.force; const z = (directionZ / vectorsLength) * this.force; this.grabbed.body.velocity.set(x , y, z ); 

我选择第二个选项是因为在其中我只能计算x和z。 自己动手,因为我需要沿着弧线投掷,以便尽管用户握住控制器,但丢弃的垃圾仍会落入篮子。

关于模型的几句话




从一开始,我就决定制作一款低聚风格的游戏。 尽管WebGL如今可以渲染相对复杂的场景,但其性能仍不如DirectX,Vulkan,Mantle等高级库。它还取决于用户设备的性能。 由于我想专注于更实惠的BP移动头盔(Oculus Go,Gear VR),因此我认为低聚是创建VR应用程序或游戏的少数解决方案之一。 当然,这全都取决于音量。

好的,低聚是如此低聚,但是这一切怎么做? 一切都很简单,有一个很好的开源工具-Blender 。 相信我,他有很多能力,但是对于简单的任务,他并不适合。 在Blender中有很多与建模有关的培训材料,找到它们并不难。 我只是想将您的注意力集中在与Web开发相关的许多方面:

  1. 三js导出器已过期。 需要寻找并提供GLTF出口商 。 GLTF是一种为Web设计的特殊格式。 是的,这是JSON。
  2. GLTF不支持Cycles Renderer,因此您必须使用Blender Renderer。 这意味着将不会有任何酷炫的结,颜色转换,金属亮点(可以以其他方式完成)。
  3. 您只需要导出所选项目。 您不需要额外的相机和灯吗? 文件>导出> gltf 2.0。 在左侧菜单中,仅选择导出GLTF 2.0>导出。
  4. 我们从Blender中的位置<0,0,0>开始导出。 最好在同一位置进行缩放,以便以后不再在a帧中使用缩放组件。
  5. 如果您像在回收中那样画出开放空间! VR,您只需要在播放器理论上可以看到的地方添加对象即可。 在后面,在房子后面,在回收站! 有几棵树,只有在用户可以看到它们的地方。 不必使场景超负荷。
  6. 如果需要更改模型材质,则需要等到其加载,获取模型本身,从中拉出所有节点(GLTF不仅包含有关网格的信息)

     e.detail.model.traverse((node) => { if (node.isMesh) { node.material.color = new THREE.Color(someColor); } }); 

总结


谢谢大家的关注! 我再次提醒您, 以下链接提供了项目存储库。 任何想要为游戏带来新事物的人-欢迎。

Source: https://habr.com/ru/post/zh-CN443062/


All Articles