[SOLVED] Looking for the Best Approach to Make A Modified Object From The Original

I create a custom list-like object that contains multiple pc.Vec2 objects.
The purpose of this object is to confines the newly created vector objects to a limited number.

The problem was that I tried to derive the list object for pc.Vec3 from the 2-dimensional vector array object, but couldn’t figure out the wise and keen approach.

    /* Custom Constant Functions */
    // Create a 2 Dimensional Vector Array
    pc.Vec2Array = function ( _length ) {
        let _vectors = [];

        for (var i = 0; i < _length; i++) {
            _vectors.push(new pc.Vec2(0, 0));
        }
        
        this.vectors = _vectors;
        this.x = [];
        this.y = [];
        this.lengths = [];

        this.update = function () {
            let _Xarray = [];
            let _Yarray = [];
            let _vectorLengths = [];
            
            _vectors.forEach(function(moment) {
                _Xarray.push(moment.x);
                _Yarray.push(moment.y);
                _vectorLengths.push(moment.length());
            });
            
            this.x = _Xarray;
            this.y = _Yarray;
            this.lengths = _vectorLengths;
        };
        
        this.push = function ( x, y ) {
            for (let i = _length-1; i > 0; i--) {
                this.vectors[i].copy( this.vectors[i-1] );
            }
            this.vectors[0].set( x, y );

            this.update();
        };
        
        this.update();
    };
    
    // Create a 3 Dimensional Vector Array
    pc.Vec3Array = function ( _length ) {
        let _vectors = [];

        for (var i = 0; i < _length; i++) {
            _vectors.push(new pc.Vec3(0, 0));
        }
        
        this.vectors = _vectors;
        this.x = [];
        this.y = [];
        this.z = [];
        this.lengths = [];

        this.update = function () {
            let _Xarray = [];
            let _Yarray = [];
            let _Zarray = [];
            let _vectorLengths = [];
            
            _vectors.forEach(function(moment) {
                _Xarray.push(moment.x);
                _Yarray.push(moment.y);
                _Zarray.push(moment.z);
                _vectorLengths.push(moment.length());
            });
            
            this.x = _Xarray;
            this.y = _Yarray;
            this.z = _Yarray;
            this.lengths = _vectorLengths;
        };
        
        this.push = function ( x, y, z ) {
            for (let i = _length-1; i > 0; i--) {
                this.vectors[i].copy( this.vectors[i-1] );
            }
            this.vectors[0].set( x, y, z );

            this.update();
        };
        
        this.update();
    };

As you can see, there are obvious parts in the code for pc.Vec3Array that are identical to the parts in the Vector 2 Array object.

I attempt to use a funtion.prototype.call, but if anyone knows the better solution for this code, please guide me. Or, if anyone has a point to criticize the fundamental of this code that disrupts the recommended standard practice, feel free to comment on this post.

https://playcanvas.com/project/732663/overview/Mound%20Simulator

Before recommending, we need to know how this is used. For example, can you describe the reasoning behind the update method? How often is it used and what for?

I need to store several vectors in one array, then derive other arrays, such as the one that only contains x value of those vectors, from the vector array.

I temporarily define “update” function in the object in order to renew the x, y, and length arrays from the vector array in every frame, by placing the function into other scripts’ update.

The original object only handles the 2-dimensional vectors, hence generates the arrays associated with x, y, and lengths. But now I want to extend the object to cope with 3-dimensional vectors. Therefore, the new object should have z array while the vector array should contain pc.Vec3 instead of pc.Vec2.

If you need an additional detail related to the modules, let me know about your curiosity.

If I understand correctly the reason you have update function is so that you can access x, y and z components of your vectors.

Firstly:

this.update = function () {
    let _Xarray = [];
    ...

This will allocate new Array every frame. Instead it is better to create it only once, when you create your Vec2Array, outside of update method. Then inside the update function you would reuse it.

Then the way you assign new _Xarray to this.x:

...
this.x = [];
...
this.x = _Xarray;

Here, you create a new Array, but then destroy it by overwriting the value of this.x with a new reference _Xarray. One option is to set this.x = null;, so no allocation is made or create an array before update and reuse.

Then about the length:

_vectorLengths.push(moment.length());

I am not sure what your goal here is. But this is measuring a length of pc.Vec2() vector. If that is the goal, then you can get the length from the vector directly. More on this below.

So, I would recommend 3 things:

  1. Remove update method and access the vectors directly. This will remove a need in updating the arrays each frame and storing local copies of vector components.
  2. Change push method by removing copy process of elements - this will get more expensive the larger the array is. You can simply remove the last element and insert a new in the beginning, no need to copy all.
  3. You can use a normal Array[] to store all your vectors in:
const myArray = [];

// add new vector
myArray.push(new pc.Vec3);

// access some vector
const myVector = myArray[0];
myVector.x;        // 0
myVector.y;        // 0
myVector.length(); // 0

// add new vector
myArray.unshift(vector);
myArray.pop();
  1. If you want to add some other convenience methods, not supported by standard Array, then you can make it into a class (I would recommend using a standard Array, though). In this case you should also generalize it, so it doesn’t matter if you use Vec2 or Vec3.

Here is an example:

class VecArray {
    constructor(vector, length) {
        const vectors = [];
        for (let i = 0; i < length; i++) {
            vectors.push(vector.clone());
        }
        this._vectors = vectors;
    }
    
    get length() {
        return this._vectors.length;
    }

    get(index) {
        return this._vectors[index];
    }
    
    push(vector) {
        this._vectors.unshift(vector);
        this._vectors.pop();
    }
    
    clear() {
        this._vectors.length = 0;
    }
}

// Examples how to use:

const v2 = new pc.Vec2();
const v3 = new pc.Vec3();

const v2Array = new VecArray(v2, 2);    // [ Vec2, Vec2 ]
const v3Array = new VecArray(v3, 2)     // [ Vec3, Vec3 ]

const newVector = new pc.Vec3(1, 2, 3);
v3Array.push(newVector);                // [ Vec3, Vec3, Vec3 ]

v2Array.length;     // 2
v3Array.length;     // 3

// access vectors directly by index
const myVector2 = v2Array.get(2);       // pc.Vec2(0, 0)
const myVector3 = v3Array.get(2);       // pc.Vec3(0, 0, 0)

myVector2.x;        // 0
myVector2.y;        // 0
myVector2.length(); // 0

v2Array.clear();
v2Array.length;     // 0

1 Like

I appreciate your advices.

  1. Definitely I have to avoid initiating a new array repeatedly.
  2. I may modified the code by using shift and push instead of copying an entire array.
  3. Sometimes I forgot the purpose of this code as, at some specific moment, I replace all of the code from utilizing vector only array to generating separated arrays. I have to rethink about the codes anyhow.
1 Like