1

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.

2
  • It may be hard to detect using a specific point, I'd rather try doing pos.y < 1 && pos.z < -21.821 Commented Feb 9, 2021 at 21:15
  • Oh, use a range like (pos.x > -23 && pos.x < -20)&&(pos.y > 0 && pos.y < 2)&&(pos.z > -1 && pos.z < 2)? Commented Feb 9, 2021 at 21:21

1 Answer 1

2

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/[email protected]/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/[email protected]/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)

Sign up to request clarification or add additional context in comments.

4 Comments

Yes. I was about to post this as the answer. I didn't realize that update only fired when .setAttribute() is called. It works now. That is exactly how my code looks as well
@ProtocolAlpha one more thing came to my mind - check out the edit
I was never good at three.js code. So I went with the AFrame code.
@ProtocolAlpha sooner or later it may become necessary, it just came to my mind because it's mentioned in the docs, in the best practices section

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.