Animated Models in Classes

I have a simple project Classes but for now I only have static models, but I want to add some animated models but Im struggling with getting the mixer out of the model into a class variable.

This code below is an example of my Models classes:

export class TrashBin {
    constructor(position, rotation) {
        this.mesh = this.load();
        this.mesh.position.set(position.x,position.y,position.z);
        this.mesh.rotation.set(rotation.x,rotation.y,rotation.z);
        this.mesh.scale.set(0.08,0.08,0.08);
    }

    load() {
        let loader = new GLTFLoader(loadingManager);
        let mesh = new THREE.Mesh();

        loader.load('./models/trash/trash.glb', function (gltf) {
            gltf.scene.traverse(function(child) {
                if (child.isMesh) {
                    child.castShadow = true;
                    child.receiveShadow = true;
                }
            })
            const model = gltf.scene.children[0];
            model.material.metalness = 0;
            model.position.set(0,0,0);
            model.rotation.set(0,0,0);
            model.scale.set(1,1,1);
            mesh.add(model);
        }, undefined, function (error) {
            console.error(error);
        });
        return mesh;
    }

    update(){
    }

    getMesh(){return this.mesh;}

}

So i need to get the mixer when I load the gltf ( inside loader.load ) but i cannot use the value of a variable that was initialized / receive some value. Then i cannot get the mixer to use it on my update method of the class.

Any help or advices are needed.
Thanks in advance!

You have to create an instance of AnimationMixer after the glTF asset has been loaded. There is no way around this because the 3D object is a mandatory constructor parameter.

So I suggest you create a property animationMixer in your constructor and initialize it with null. In your update method, you have to check the value of the mixer per invocation. Something like:

export class TrashBin {
    constructor(position, rotation) {
        this.mesh = this.load();
        this.mesh.position.set(position.x,position.y,position.z);
        this.mesh.rotation.set(rotation.x,rotation.y,rotation.z);
        this.mesh.scale.set(0.08,0.08,0.08);
        this.animationMixer = null;
    }

    load() {
        let loader = new GLTFLoader(loadingManager);
        let mesh = new THREE.Mesh();

        loader.load('./models/trash/trash.glb', (gltf) => {
            gltf.scene.traverse(function(child) {
                if (child.isMesh) {
                    child.castShadow = true;
                    child.receiveShadow = true;
                }
            })
            const model = gltf.scene;
            model.material.metalness = 0;
            model.position.set(0,0,0);
            model.rotation.set(0,0,0);
            model.scale.set(1,1,1);
            mesh.add(model);
            this.animationMixer = new THREE.AnimationMixer(model);
        }, undefined, function (error) {
            console.error(error);
        });
        return mesh;
    }

    update(delta){
        if(this.animationMixer !== null) this.animationMixer.update(delta);
    }

    getMesh(){return this.mesh;}

}

BTW: Avoid stuff like gltf.scene.children[0]. It’s best practice to just use gltf.scene. In this way you don’t miss transformations or potentially break animations.

My problem is when im inside the loader.load because of being a nested function I cannot access this.animationMixer property it always says its undefined. Im kinda new on Js so I dont know how to resolve it.
But thanks for your help!

Make sure to use an arrow function as the onLoad() callback like in my code snippet so the this reference still points to the “right” location.

Im sorry for being kinda annoying but now i see the model change the position to the animation but its not updating the animation so animation is not playing.

This is my class:

export class Boneco {
    constructor(position, rotation) {
        this.mesh = this.load();
        this.mesh.position.set(position.x,position.y,position.z);
        this.mesh.rotation.set(rotation.x,rotation.y,rotation.z);
        this.mesh.scale.set(10,10,10);
        this.animationMixer = null;
        this.animation = null;
        // this.animation.play();
    }

    load() {
        let loader = new GLTFLoader(loadingManager);
        let mesh = new THREE.Mesh();

        loader.load('./models/Soldier.glb', (gltf) => {
            gltf.scene.traverse(function(child) {
                if (child.isMesh) {
                    child.castShadow = false;
                    child.receiveShadow = false;
                }
            })
            // console.log(gltf)
            let model = gltf.scene;
            model.position.set(0,0,0);
            model.rotation.set(0,0,0);
            model.scale.set(1,1,1);
            mesh.add(model);

            let skeleton = new THREE.SkeletonHelper( model );
            skeleton.visible = false;
            model.add( skeleton );

            this.animationMixer = new THREE.AnimationMixer(model);
            const clips = gltf.animations;
            const clip = THREE.AnimationClip.findByName(clips, 'Walk');
            this.animation = this.animationMixer.clipAction(clip);
            this.animation.loop = LoopRepeat;
            // console.log(clips)
            this.animation.reset().play();

        }, undefined, function (error) {
            console.error(error);
        });
        return mesh;
    }

    update(delta){
        // console.log(this.animationMixer)
        if(this.animationMixer !== null) this.animationMixer.update(delta);
    }

    getMesh(){return this.mesh;}

}

And this is my Application render function:

    render() {

        let delta = clock.getDelta();

        requestAnimationFrame(() => {
            this.controls.update();
            this.stats.update();
            this.render();
        });


        this.objects.forEach((object) => {
            if(object instanceof Boneco){
                object.update(delta);
            }
            object.update();
        });

        this.renderer.render(this.scene, this.camera);
    }