How to stop local variables being overwritten?

In the below example (I have tried to trim), I have been scratching my head over how the local variable initialTarget as a Vector3 gets overwritten when a function called SetTarget is used that takes a position. It seems to always set the initialTarget Vector3 to the last position used in SetTarget which is passed as position in the function arguments. Is there something basic about Typescript I am missing here? The code below is all the places that initialTarget is used

Original Post on Discord

by user 103054507105067008

 private initialTarget: THREE.Vector3;

start() {
        if (this._controls) {
            //this.camGo = GameObject.getComponent(this.gameObject, Camera);
            if (this.camGo && !this.setFromTargetPosition()) {
                console.log("NO TARGET");
                //@ts-ignore
                const forward = new THREE.Vector3(0, 0, -1).applyMatrix4(this.camGo.cam.matrixWorld);
                this.initialTarget = this.targetPosition as THREE.Vector3;
                this.setTarget(forward);
                this.startCamPos = forward;
                //this.startCamPos = getWorldPosition(this.context.mainCamera);
                console.log(this.initialTarget);
            }
        }
    }


    public resetCamPos()
    {
        console.log("setting pos");
        console.log(this.initialTarget);
        this.setTarget(this.initialTarget);
        this.setCameraTarget(this.startCamPos, true);    
    }

    public setTarget(position: THREE.Vector3 | null = null, immediate: boolean = false) {
        //console.log(this.initialTarget);
        //console.log(position);
        this.toggleStickyMode(false);
        if (!this._controls) return;
        this.isTransitioning = true;
        console.log(position);
        if (position !== null) 
        {
            let pos = position;
            this.targetPosition.copy(pos);
        }
        //console.log(this.initialTarget);
        if (immediate)
            this._controls.target.copy(this.targetPosition);
        else 
        {
            this._lerpCameraToTarget = true;
            this._lerpToTargetPosition = true;
        }
        position = null;
    }

by user 103054507105067008

In a nutshell, initialTarget is set in Start, then it is passed in another function as the position that setTarget takes, but somehow when that setTarget function runs, initialTarget is overwritten

by user 103054507105067008

In threejs/javascript Vector3 are not structs/value types. You pass around reference types here. So when you pass your initialTarget Vector in a function and modify the vector in that function your initialTarget vector will be changed. This is a big big difference to Unity

I realise I can work around this by making that position be a gameobject position I can grab, but of course I was stifled as to why it was changing.

by user 103054507105067008

I tried using let as I saw that in some docs but it still got overwritten

by user 103054507105067008

I also tried making a new vector which would take the value of initialTarget and passing that new vector instead but the initialTarget value still changed when I used that new vector!

by user 103054507105067008

It’s like it all points back to the original value still

by user 103054507105067008

That would mean you somehow still pass in a reference to your original vector

Code like this fools you:

let pos = position;
            this.targetPosition.copy(pos);

since pos is still position

even tho you declare a new variable - it IS the same vector

this is what I mean above - there are no value types in js like in Unity for these (just the builtin types for number, boolean, undefined, null and symbol)

Seems it

    public resetCamPos()
    {
        let pos = new THREE.Vector3(0,0,0);
        pos = pos.copy(this.initialTarget);
        
        console.log("setting pos");
        console.log(this.initialTarget);
        this.setTarget(pos);
    }

This was what didn’t work

by user 103054507105067008

Vector3 is a reference type

Maybe there’s another path that accidentally uses initialTarget? (btw you could also just write this.initialTarget.clone())

I have double checked all initialTarget references

by user 103054507105067008

I’ll use that .clone() as you said, shall I make a new Vector3 and do like
const pos = this.initialTarget.clone()

by user 103054507105067008

Yup depending on how often you do that per frame its fine (i would avoid it if its called a lot per frame).

Only gets set once when a button is pressed

by user 103054507105067008

totally fine then :slightly_smiling_face: