Search code examples
javascripthtmlthree.jsaframe

Using an Object's postion for an Event in AFrame


I'm trying to make a component that checks the current position of a sphere in an AFrame scene and when it hits a specific coordinate and when it does it fires an event (In example below it resets it to its default position):

AFRAME.registerComponent("trackball", {
  update: function() {
    let pos = this.el.getAttribute("position");
    if (pos == {x:-21.821,y: 1,z: 0})
      {
        this.el.setAttribute("position", "-21.821 5 0");
      }
  }
});

I'm not sure what format is returned when .getAttribute("position") is called so that may be why it's not working. I am running AFrame 1.1.0.


Solution

  • First of all update is called when attributes are changed via setAttribute(). If you want a function that is called on each render frame, then use tick().

    Secondly, try using a range, instead of a fixed point, it's very likely that the object will move past the point between two ticks.

    Something like this:

    <script src="https://aframe.io/releases/1.1.0/aframe.min.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/n5ro/aframe-physics-system@v4.0.1/dist/aframe-physics-system.min.js"></script>
    <script>
    AFRAME.registerComponent("trackball", {
      tick: function() {
        let pos = this.el.getAttribute("position");
        if (pos.y < 0.5) {
            // reset position
            this.el.setAttribute("position", "0 3 -4")
            // sync
            this.el.components["dynamic-body"].syncToPhysics();
          }
      }
    });
    </script>
    <a-scene physics cursor="rayOrigin: mouse">
      <a-sphere position="0 1.25 -5" radius="0.25" color="#EF2D5E" dynamic-body trackball></a-sphere>
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" static-body></a-plane>
      <a-sky color="#ECECEC"></a-sky>
    </a-scene>

    Also try using the object3D properties instead setAttribute() and getAttribute() when dealing with frequently called functions (which certainly applies to tick()):

    <script src="https://aframe.io/releases/1.1.0/aframe.min.js"></script>
    <script src="https://cdn.jsdelivr.net/gh/n5ro/aframe-physics-system@v4.0.1/dist/aframe-physics-system.min.js"></script>
    <script>
      AFRAME.registerComponent("trackball", {
        // iife to initialize the "origin point" once
        tick: (function() {
          const origin = new THREE.Vector3(0, 3, -4);
          const y_range = 0.5;
          return function() {
            // check if the ball is out of range
            const pos = this.el.object3D.position
            if (pos.y < y_range) {
              // reset position
              pos.copy(origin);
              // sync
              this.el.components["dynamic-body"].syncToPhysics();
            }
          }
        })()
      });
    </script>
    <a-scene physics cursor="rayOrigin: mouse">
      <a-sphere position="0 1.25 -4" radius="0.25" color="#EF2D5E" dynamic-body trackball></a-sphere>
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" static-body></a-plane>
      <a-sky color="#ECECEC"></a-sky>
    </a-scene>

    Keep in mind, updating the position in such manner is more performant, but will cause getAttribute("position") to return the last position set via setAttribute("position", new_position)