Why does the error says "cannot read property (0) undefined" when it is defined?

Hello

I have a method which moves a sphere on a spline of type Curve3.
So I have a snippet of code, which work well in JS in the playground I’ve implemented before moving to TS, and is taken from the “follow path” tutorial.
Since I’ve transformed it to TS it gives me “undefined” errors of many kinds.
The location of the error is at the line: this._sphere.position = this.pathPoints[i];

What is wrong with this code?

private async _prepareTrailEffect(spline: Curve3, splineMesh: Mesh, startPosition: Vector3) {
    this._sphere.setParent(splineMesh);
    this._sphere.position = startPosition;

    var pathPoints = spline.getPoints();
    Logger.Warn("path point count" + pathPoints.length);
    var numberOfPoints = pathPoints.length;
    var path3d = new Path3D(pathPoints);
    var normals = path3d.getNormals();

    var theta = Math.acos(Vector3.Dot(Axis.Z, normals[0]));

    var i = 0;
    this.scene.registerAfterRender(function () {
        this._sphere.position = this.pathPoints[i];

        theta = Math.acos(Vector3.Dot(normals[i], normals[i + 1]));
        var direction = Vector3.Cross(normals[i], normals[i + 1]).y;
        var direction = direction / Math.abs(direction);

        this._sphere.rotate(Axis.Y, direction * theta, Space.WORLD);

        i = (i + 1) % (numberOfPoints - 1);
    });
}

So I tried to use For Loop

        for (var i = 0; i < numberOfPoints; i++) {
        this.scene.registerAfterRender(function () {
            this._sphere.position = this.pathPoints[i];

            theta = Math.acos(Vector3.Dot(normals[i], normals[i + 1]));
            var direction = Vector3.Cross(normals[i], normals[i + 1]).y;
            var direction = direction / Math.abs(direction);

            this._sphere.rotate(Axis.Y, direction * theta, Space.WORLD);
        });
    }

The goal is to wait until the end of frame and then increase the index by 1.

What would be the preferred way to do so in TS?

Thanks

Just a guess. I think this is a JS problem, not BJS specific.

this refers to the class instance. The context ‘this’ is not in the function you declared and passed into this.scene.registerAfterRender. Thus it is undefined.

You can either use JS bind to pass the context of ‘this’ to your function:

this.scene.registerAfterRender(function () {
    this._sphere.position = this.pathPoints[i];

    theta = Math.acos(Vector3.Dot(normals[i], normals[i + 1]));
    var direction = Vector3.Cross(normals[i], normals[i + 1]).y;
    var direction = direction / Math.abs(direction);

    this._sphere.rotate(Axis.Y, direction * theta, Space.WORLD);

    i = (i + 1) % (numberOfPoints - 1);
}.bind(this));

Or use ES6 arrowed function, which passes the context in the parent scope into the function by default.

this.scene.registerAfterRender(() => {
    this._sphere.position = this.pathPoints[i];

    theta = Math.acos(Vector3.Dot(normals[i], normals[i + 1]));
    var direction = Vector3.Cross(normals[i], normals[i + 1]).y;
    var direction = direction / Math.abs(direction);

    this._sphere.rotate(Axis.Y, direction * theta, Space.WORLD);

    i = (i + 1) % (numberOfPoints - 1);
});
2 Likes

Thanks! using lambda expression worked for me. :slight_smile: