Odd behavior using .getPosition in a console.log statement

I ran into something odd today and am not sure if it is a bug or if I just don’t understand the function and use properly. The short description is that the statement:

console.log(‘After location’, this.CopterSphere.getPosition());
updates the reposit variable the same as:
reposit = this.CopterSphere.getPosition();

The longer version is that the entity CopterSphere is parented to an an entity Copter. I reposition Copter after having previously set the Vec3 variable, reposit to CopterSphere’s position. At this point in time, reposit still holds the old values for CopterSphere’s location. But if I call a console.log statement that gets the CopterSphere location using .getPosition, the variable reposit gets updated?!?!?

I’ve had no problem working around this, now that I understand what is going on. But I was surprised to see that my working script broke when I remarked out all of my console.log statements. It turns out I had failed to update the reposit variable and the console.log statement was covering up my mistake.

So is this normal functioning? I’m just beginning to learn PlayCanvas and found this behavior very surprising and not intuitive at all.

Thanks!


master = this.Copter.getPosition();
target = this.PivotMarker.getPosition();
reposit = this.CopterSphere.getPosition();

        console.log('original CopterNull Pos', master);
        shiftAmt = master.sub(target);
        console.log('target Null Pos', target);
        console.log('Before location.', reposit);
        console.log('Shift Amount', shiftAmt);

        this.Copter.setPosition(target);
        //console.log('After location', this.CopterSphere.getPosition());
        reposit = this.CopterSphere.getPosition();
        this.CopterSphere.setPosition(reposit.add(shiftAmt));
        console.log('After location2', this.CopterSphere.getPosition());
        this.Copter.script.rotate.orbitSensitivity = 0.25;

This will take a little explanation :stuck_out_tongue:

Some languages like C++ and C# will allow you to copy by value as well as by reference.

Javascript only allows by reference on object types (like pc.Vec3)

.getPosition does a calculation of the world position of the entity based on the scene graph and returns a reference to a pc.Vec3 with that world position.

To avoid generating new objects every time it is called (which would lead to frame stutters when the GC is called), PlayCanvas has a pc.Vec3 for each entity to use to store the world position in the getPosition function (see https://github.com/playcanvas/engine/blob/093b760f1c2fdf9cac558c615b0d5ce430784e49/src/scene/graph-node.js#L713).

Which means when you do this:

master = this.Copter.getPosition();
reposit = this.CopterSphere.getPosition();

Both master and reposit are actual referencing the same object so changing either master, reposit or calling getPosition again means that both master and reposit are affected.

The common pattern in PlayCanvas for things like this is to have a temp pc.Vec3 yourself and copying the data. Eg

SomeScript.prototype.initialize = function() {
    this._tempPos = new pc.Vec3();
};

SomeScript.prototype.update = function() {
    this._tempPos.copy(this.entity.getPosition());
    // Do something with this._tempPos
};

Or

SomeScript.__tempPos = new pc.Vec3();
SomeScript.prototype.update = function() {
    var tempPos = SomeScript.__tempPos;
    tempPos.copy(this.entity.getPosition());
    // Do something with tempPos
};

So yes, this isn’t intuitive and I don’t think the documentation mentions this as I got thrown the first time I came across this, especially being new to Javascript at the same time.