Search code examples
javascript3daframewebvr

How do I set some of an object's coordinates without resetting the other ones?


I am trying to adjust only the Y coordinate of an object, while keeping the X and Z coordinates the same. The only method that I have working is fetching the object's position and composing a new partially modified position. It's not pretty, and seems like it could be inefficient. It looks like this may be due to the fact that position is a single-property component, so maybe this isn't possible.

Here's my current solution:

https://glitch.com/edit/#!/aframe-position-example

index.html:

<html>
  <head>
    <script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
  </head>
  <body>
    <a-scene>
      <a-camera id="camera"></a-camera>
    </a-scene>
    <script src="index.js"></script>
  </body>
</html>

index.js:

const camera = document.querySelector( '#camera' )

console.log( camera.getAttribute( 'position' ) )
// {x: 0, y: 1.6, z: 0}

// overwrites original position, as expected
camera.setAttribute( 'position', { x: 0, y: 0, z: 5 } )
console.log( camera.getAttribute( 'position' ) )
// {x: 0, y: 0, z: 5}

// overwrites original position (including z, defaults to 0), maybe not expected
camera.setAttribute( 'position', { x: 5, y: 5 } )
console.log( camera.getAttribute( 'position' ) )
// {x: 5, y: 5, z: 0}

// overwrites original position (x and z become 0), maybe not expected
camera.setAttribute( 'position', 'y', 10 )
console.log( camera.getAttribute( 'position' ) )
// {x: 0, y: 10, z: 0}

// how to change some position variables and keep the other ones the same
let oldPos = camera.getAttribute('position')
let newPos = { x: 4, y: oldPos.y, z: oldPos.z }
camera.setAttribute( 'position', newPos )
console.log( camera.getAttribute( 'position' ) )
// {x: 4, y: 10, z: 0}

Solution

  • You could either:

    • Set a temporary position variable, and change only the desired part:
      let pos = this.el.getAttribute('position'); pos.x += velocity; this.el.setAttribute('position',pos);
    • use Rainer Witmann's idea of cutting the temporaries by using Object.Assign(): this.el.setAttribute('position', Object.assign({}, this.el.getAttribute('position'), {x: newX}));
      Seems shorter, but I like having the whole position as a temporary variable: live here: https://jsfiddle.net/gftruj/dqyszzz5/4/

    • Mess with the position component directly, by changing data, and calling the update() function:
      this.el.components.position.data.z-=2; this.el.components.position.update();
      This is fun, but I think this is a terrible idea when creating a commercial/proffesional project, as every framework ingeration would be.

    • use the threejs object3D properties:
      this.el.object3D.position.x += velocity;
      check it out in my fiddle: https://jsfiddle.net/gftruj/dqyszzz5/1/
      Please note, that later on You won't be able to call getAttribute(), as the position component does not change.

    In Your glitch You use the first option, but You don't need use the position object attributes separately: setAttribute('position',{x:pos.x,y:pos.y,z:pos.Z});, You can simply use the whole object: setAttribute('position',pos);