Typescript class problem (C# developers could help ;)

Hey there,

So I am having a problem with typescript. I am still a newb with TS so be gentle..

I have script "app.ts" like this :
function init ()
{    
    // Create box
    var box = new Box();
    box.AddToScene(scene);
}
init();


And then I have a another script "box.ts" like this :
class Box {
    keyboard;
    mesh: THREE.Mesh;
    constructor (){
        // Set up input
        this.keyboard = new THREEx.KeyboardState();
        
        // Create mesh
        this.mesh = new THREE.Mesh(
            new THREE.BoxGeometry(1, 1, 1),
            new THREE.MeshBasicMaterial({color: 0xff00ff})
        );
        
        // Initiate update loop
        setInterval(this.Update, 30);
    }
    
    Update () {
        if (this.keyboard.pressed("left"))
        {
            this.mesh.position.x -= 0.01;
        }
    }
    
    public AddToScene (scene : THREE.Scene){
        scene.add(this.mesh);
    }
}


I have omitted a bunch of irrelevant code to keep the post short but if you would like to see the full code just say the word.

The problem :
The box I am instantiating works great and the Update method gets called every 30 ms but I get an error when I press left that says the mesh property is undefined. However when I access the mesh property from the app.ts script it works and is defined. So I am thinking the problem must be in "box.ts" at
this.mesh.position.x -= 0.01;


I know this is a long shot but maybe there is someone here that can point me in the right direction. Typescript is very similar to C# so..

Thanks i advance for any sort of reply.
-Kobus

Comments

  • I doubt it, since this.keyboard isn't giving you an undefined at that point. Aren't you getting a js line number with that error? It's pretty easy to work backwards from that.
  • Hi

    Been a while since I have used ThreeJS. AFIK (could be wrong) Mesh object does not have any transform attributes. You need to set it as a child of an Object3D.

    Then you can adjust the position and rotations.

    In plain JS it would look a bit like this

    var obj = new THREE.Object3D();
    obj.add(mesh)

    obj.position.x +=0.001;

    etc

    Hope that helps
  • hmm actually i am wrong, i think mesh is a child of Object3D anyway.

    Maybe its a scoping issue? Hard to really diagnose without full sourcecode to play with.
    Thanked by 1mattbenic
  • @mattbenic The line number points to the line I identified.
    @shanemarks Ive attached the full source to this post. Perhaps you can figure out whats going on ?
    zip
    zip
    ThreeJS TS Test.zip
    160K
  • OK sorry I was under the impression you were guessing at one of the lines involving this.mesh based the first post.

    I don't know ThreeJS at all, but based on the snippets in the first post I'd expect mesh to be _ something_ addressable. The typescript seems correct. Hopefully @shanemarks has some more insight :)
    Thanked by 1Kobusvdwalt9
  • edited
    So... I have never used ThreeJS before, and I have no idea what I'm doing. But in case it helps, in box.js, if I set a variable (boxObject here) in the constructor, instead of using this.mesh, trying to refer to that works. (Again, noob here, but posting just in case it helps with your debugging -- or at least being able to proceed. I mean, at a guess, I'd guess that this doesn't seem to work the way you might expect it to...?)

    var boxObject;
    
        function Box() {
            // Set up input
            this.keyboard = new THREEx.KeyboardState();
            // Create mesh
            this.mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({ color: 0xff00ff }));
            boxObject = this.mesh;
            // Initiate update loop
            setInterval(this.Update, 30);
        }
    
        Box.prototype.Update = function () {
            if (this.keyboard.pressed("left")) {
                boxObject.position.x -= 0.01; //(boxObject.position.x - 0.01); // -= 0.01;
            }
        };
    Thanked by 1Kobusvdwalt9
  • @mattbenic Yeah sorry about that, that does sound like I am guessing. I should have stated that the debugger is telling me its that spesific line.

    Anyway I set up a simple project to try and locate the problem. Ive narrowed it down to some problem with setInterval();

    This works :
    // Box.ts \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
    class Box {
        position: number = 0;
        constructor(){
            this.position = 10;
            this.LogPosition();
        }
        LogPosition (){
            console.log(this.position);
        }
    }
    // App.ts \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
    /// <reference path="Box.ts" />
    var myInstance = new Box();


    but this gives a undefined :
    // Box.ts \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
    class Box {
        position: number = 0;
        constructor(){
            this.position = 10;
            setInterval(this.LogPosition, 30);
        }
        LogPosition (){
            console.log(this.position);
        }
    }
    // App.ts \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
    /// <reference path="Box.ts" />
    var myInstance = new Box();
  • Look at the JS those two compile to, It sounds to me like it might be like it might be a difference there- a scoping issue at the JS level.
  • edited
    Hi.

    I solved your issue. It is indeed a scoping issue. This is quite a common problem inside javascript (and presumably typescript).
    I edited the plain javascript to illustrate this.

    Notice how I am creating a reference to "this" called "_this" and then referring to it in your setInterval function. This is because the value of "this" is referring to the closure and not the object you have defined.

    /// <reference path="plugins/three.d.ts" />
    /// <reference path="plugins/input.js" />
    var Box = (function () {
    function Box() {
    var _this = this;
    // Set up input
    this.keyboard = new THREEx.KeyboardState();
    // Create mesh
    this.mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({ color: 0xff00ff }));
    console.log(this.mesh);

    // Initiate update loop
    setInterval(this.Update, 30);
    }
    Box.prototype.Update = function () {
    if (this.keyboard.pressed("left")) {
    console.log(_this.mesh);
    _this.mesh.position.x -= 0.01;
    }
    };
    Box.prototype.AddToScene = function (scene) {
    scene.add(this.mesh);
    };
    return Box;
    }());
    //# sourceMappingURL=box.js.map
    This article explains it better than I can:
    http://javascriptplayground.com/blog/2012/04/javascript-variable-scope-this/
    Thanked by 1Kobusvdwalt9
  • @Kobusvdwalt9, the javascript that @shanemarks posted is correct and works fine. So to get your typescript to transpile to this javascript you should change your Update method definition like so:

    private Update = () => {
    }


    Thanked by 1Kobusvdwalt9
  • Thanks guys !!!

    @shanemarks I think I understand whats happening but I will need to reread the link you posted again to make sure.
    @petrc Thanks ! Its the first time ive seen anything like that would you mind explaining what that definition does that is different from the normal one. Is it simply a way to force the typescript compiler to transpile the TS into the way @shanemarks wrote it ?
  • @Kobusvdwalt9, that is the way to use instance functions in typescript. You can find more info here
    Thanked by 1Kobusvdwalt9
  • Ah of course, I'd completely forgotten the arrow binding in TS (facepalm). I'm a bit surprised that the earlier reference to this.keyboard didn't result in an undefined first?
Sign In or Register to comment.