【问题标题】:How to make A-Frame components talk to each other?如何使 A-Frame 组件相互通信?
【发布时间】:2021-09-08 08:54:07
【问题描述】:

我想要一些组件来响应用户在场景中的位置和方向。我对交互式 a-frame 场景几乎没有经验,也没有自己编写过组件。

一般来说,我希望组件能够为其他组件调用提供回调,或者如果这不可能,那么某种组件间数据切换。 “接收”组件会改变其内容(子)、外观和/或行为。

如果我们举一个非常简单的例子,假设我希望场景在用户位于 x>0 时包含一个框,或者在用户位于 x

分解一下,我很乐意了解如何...:

  1. 读取用户位置并使其可供其他人使用。我找到了how to read the position;我想我可以只取<a-scene> 元素并设置一些属性,例如user-position="1 2 3"
  2. 在某处编写一些代码,当该位置发生变化时运行一个函数(我想我会去抖动它)并对场景进行更改。我认为如果我编写自己的组件来包含整个场景,我需要...:
    • 将用户位置设置为该元素的属性;
    • 定义一个update方法;
    • update 方法中,比较当前与以前的用户位置。

...但我想知道这是否有点矫枉过正,我可以以某种方式进入一个场景,或者完全是其他的东西。

如果我采用上面提到的方法,我想缺少的部分是如何“声明”要渲染的内容?例如,使用 ReactJS 我只需要return x > 0 ? <a-box/> : <a-sphere/>;。是否有等价物,或者我需要进入 DOM 并手动添加/删除<a-box> child 等?

谢谢!

编辑:我的盒子/球体工作正常 (glitch),但感觉很奇怪,很想改进它。

【问题讨论】:

    标签: aframe


    【解决方案1】:

    如何让 A-Frame 组件相互通信?

    0。设置属性

    您可以更改任何组件中的任何属性

    element.setAttribute("component_name", "value");
    

    但我认为您想要的不仅仅是对update 呼叫做出反应。比组件schema 更灵活,每秒使用 60 次时性能更高/

    1.活动

    • 组件 1 发出事件
    • 组件 2 - x 监听事件,并做出相应反应。

    不依赖于硬编码的组件名称,您可以轻松拥有多个收件人,以及可能稳定的 API:

    <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
    <script>
      AFRAME.registerComponent("position-reader", {
        tick: function() {
          // read the position and broadcast it around
          const pos = this.el.object3D.position;
          const positionString = "x: " + pos.x.toFixed(2) +
            ", z: " + pos.z.toFixed(2)
          this.el.emit("position-update", {text: positionString})
        }
      })
      AFRAME.registerComponent("position-renderer", {
        init: function() {
          const textEl = document.querySelector("a-text");
          this.el.addEventListener("position-update", (evt) => {
            textEl.setAttribute("value", evt.detail.text);
          })
        }
      })
    </script>
    <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-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
      <a-camera position-renderer position-reader>
        <a-text position="-0.5 0 -0.75" color="black" value="test"></a-text>
      </a-camera>
    </a-scene>

    2。直接

    从字面上理解,您可以使用

    获取组件“对象”引用
    entity.components["componentName"]
    

    并调用它的函数:

    entity.components["componentName"].function();
    

    例如 - 一个组件获取当前位置,并告诉另一个组件打印它:

    <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
    <script>
      AFRAME.registerComponent("position-reader", {
        init: function() {
          // wait until the entity is loaded and grab the other component reference
          this.el.addEventListener("loaded", evt => {
            this.rendererComp = this.el.components["position-renderer"];
          })
        },
        tick: function() {
          if (!this.rendererComp) return;
          // read the position and call 'updateText' in the 'position-renderer'
          const pos = this.el.object3D.position;
          const positionString = "x: " + pos.x.toFixed(2) +
            ", z: " + pos.z.toFixed(2)
          this.rendererComp.updateText(positionString)
        }
      })
      AFRAME.registerComponent("position-renderer", {
        init: function() {
          this.textEl = document.querySelector("a-text");
        },
        updateText: function(string) {
          this.textEl.setAttribute("value", string);
        }
      })
    </script>
    <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-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
      <a-camera position-renderer position-reader>
        <a-text position="-0.5 0 -0.75" color="black" value="test"></a-text>
      </a-camera>
    </a-scene>

    在您的情况下,我会检查位置,并管理一个组件中的元素。或者用一来判断 position.x > 0 ||

    <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
    <script>
      AFRAME.registerComponent("position-check", {
        schema: {
          z: {default: 0}
        },
        tick: function() {
          const pos = this.el.object3D.position;
          // check if we're 'inside', or outside
          if (pos.z >= this.data.z) {
            // emit an event only once per occurence
            if (!this.inside) this.el.emit("got-inside");
            this.inside = true
          } else {
            // emit an event only once per occurence
            if (this.inside) this.el.emit("got-outside");
            this.inside = false
          }
        }
      })
      AFRAME.registerComponent("manager", {
        init: function() {
          const box = this.el.querySelector("a-box");
          const sphere = this.el.querySelector("a-sphere")
          //react to the changes
          this.el.sceneEl.camera.el.addEventListener("got-inside", e => {
            box.setAttribute("visible", true);
            sphere.setAttribute("visible", false);
          })
          this.el.sceneEl.camera.el.addEventListener("got-outside", e => {
            box.setAttribute("visible", false);
            sphere.setAttribute("visible", true);
          })
        }
      })
    </script>
    <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-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
    
      <a-entity manager>
        <a-box position="0 1 -3" visible="false"></a-box>
        <a-sphere position="0 1 -3" visible="false"></a-sphere>
      </a-entity>
      <a-camera position-check="z: 0"></a-camera>
    </a-scene>

    【讨论】:

    • 非常感谢彼得! ? 文档非常详尽,但有时很难消化所有细节并提出“食谱”。我真的很感激。
    • @OrenShalev 很高兴我能帮上忙 :)
    猜你喜欢
    • 2013-11-09
    • 1970-01-01
    • 2016-06-04
    • 2021-05-18
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多